JSON 데이터 <-> Java 객체 변환

Hyun·2023년 6월 20일
0

Spring

목록 보기
9/38
post-thumbnail

ObjectMapper

ObjectMapper는 Jackson 라이브러리에서 제공하는 클래스로, Java 객체와 JSON 데이터 간의 변환을 수행하는 데 사용됩니다. 주요 기능은 다음과 같습니다:

  1. Java 객체를 JSON 문자열로 변환
    ObjectMapper를 사용하여 Java 객체를 JSON 형식의 문자열로 변환할 수 있습니다. writeValueAsString() 메서드를 사용하면 Java 객체를 JSON 문자열로 직렬화할 수 있습니다.

  2. JSON 문자열을 Java 객체로 변환
    ObjectMapper를 사용하여 JSON 형식의 문자열을 Java 객체로 역직렬화할 수 있습니다. readValue() 메서드를 사용하면 JSON 문자열을 Java 객체로 역직렬화할 수 있습니다.

  3. 다양한 설정 옵션 제공
    ObjectMapper는 다양한 설정 옵션을 제공하여 JSON 변환 동작을 제어할 수 있습니다. 예를 들어, SerializationFeatureDeserializationFeature를 사용하여 직렬화 및 역직렬화 동작을 설정할 수 있습니다. 또한, DateFormat을 설정하여 날짜 형식을 지정할 수도 있습니다.

@GetMapping("/music")
public String getData(Model model) {
    String path = "https://api.manana.kr/karaoke.json";

    String responseData = webClient.get()
            .uri(path)
            .retrieve()
            .bodyToMono(String.class)
            .block();
    
    ObjectMapper objectMapper = new ObjectMapper();
    List<MusicData> songs = objectMapper.readValue(responseData, new TypeReference<List<MusicData>>() {});

    model.addAttribute("songs", songs);
    return "test";
}

위의 코드에서 ObjectMapper는 JSON 문자열을 Java 객체로 역직렬화하는 기능을 사용하고 있습니다. responseDate는 웹 요청을 통해 얻은 JSON 데이터이며, ObjectMapper를 사용하여 이 JSON 데이터를 List<MusicData> 형태로 역직렬화하고 있습니다. 이를 통해 JSON 데이터를 Java 객체로 변환하여 songs 리스트에 저장한 후, model.addAttribute()를 통해 모델에 해당 리스트를 추가하고 있습니다.

따라서, ObjectMapper는 JSON 데이터와 Java 객체 간의 변환을 담당하는 핵심적인 역할을 수행하는 클래스입니다.

TypeReference

TypeReference는 Jackson 라이브러리에서 제공하는 클래스로, Java의 제네릭 타입을 처리하는 데 사용됩니다. JSON 데이터를 Java 객체로 역직렬화할 때, TypeReference를 사용하여 명시적으로 제네릭 타입을 지정할 수 있습니다.

Java에서는 제네릭 타입의 정보를 컴파일 시간에만 유지하고, 런타임에는 제거됩니다. 이로 인해 컴파일 시간에는 제네릭 타입을 알 수 있지만, 런타임에서는 타입 정보가 손실됩니다. 따라서, JSON 데이터를 역직렬화할 때 해당 데이터가 어떤 제네릭 타입인지 알 수 없게 되는데, 이를 해결하기 위해 TypeReference를 사용합니다.

TypeReference는 추상 클래스이며, 서브클래스에서 구체적인 타입을 지정할 수 있습니다. 이를 통해 JSON 데이터의 역직렬화 시 제네릭 타입을 보존할 수 있습니다. ObjectMapper의 readValue() 메서드에 TypeReference 객체를 전달하여 JSON 데이터를 역직렬화할 때, 해당 제네릭 타입을 유지할 수 있습니다.

@GetMapping("/music")
public String getData(Model model) {
    String path = "https://api.manana.kr/karaoke.json";

    String responseData = webClient.get()
            .uri(path)
            .retrieve()
            .bodyToMono(String.class)
            .block();
    
    ObjectMapper objectMapper = new ObjectMapper();
    List<MusicData> songs = objectMapper.readValue(responseData, new TypeReference<List<MusicData>>() {});

    model.addAttribute("songs", songs);
    return "test";
} 

위의 코드에서 new TypeReference<List>() {}를 사용하여 List 타입을 명시적으로 지정하고 있습니다. 이를 통해 ObjectMapper는 JSON 데이터를 List 형태로 역직렬화할 수 있습니다.

따라서, TypeReference는 제네릭 타입을 처리하는 데 사용되며, JSON 데이터를 역직렬화할 때 해당 제네릭 타입을 보존하기 위해 활용됩니다.

Question)

컴파일 시간에는 제네릭 타입을 알 수 있지만, 런타임에서는 타입 정보가 손실된다는게 무슨 의미야?

ChatGPT)

Java에서는 제네릭 타입 정보는 컴파일 시간에 사용되며, 컴파일러는 이 정보를 통해 타입 검사 및 타입 안정성을 보장합니다. 제네릭을 사용하면 코드의 재사용성과 타입 안정성이 향상되는 장점이 있습니다.

그러나 제네릭 타입은 컴파일 시간에만 유효하며, 런타임 시에는 타입 정보가 손실됩니다. 이는 제네릭 타입 매개변수가 실제로는 Object 타입으로 변환되기 때문입니다. 즉, 제네릭으로 정의한 컬렉션 또는 객체는 컴파일되면서 제네릭 타입이 Object로 변환되어 실행 파일에 포함되며, 런타임에는 해당 객체의 타입 매개변수에 대한 정보가 없어집니다.

이러한 제네릭 타입의 정보 손실은 타입 안전성을 감소시킬 수 있습니다. 예를 들어, 컴파일 시간에 타입 검사가 이루어지지만, 런타임에는 타입 정보가 없으므로 잘못된 타입의 객체가 전달될 수 있습니다. 이는 컴파일러가 경고를 표시하지 않고 런타임 오류가 발생할 가능성을 야기할 수 있습니다.

Jackson 라이브러리에서 TypeReference를 사용하여 제네릭 타입을 유지하는 이유도 여기에 있습니다. JSON 데이터를 역직렬화할 때, 제네릭 타입 정보가 손실되지 않도록 TypeReference를 사용하여 명시적으로 제네릭 타입을 지정함으로써, 런타임에도 올바른 타입으로 데이터를 역직렬화할 수 있습니다.

Question)

만약 위 코드에서 TypeReference가 없으면 어떻게 되는데?

ChatGPT)

만약 위 코드에서 TypeReference를 사용하지 않고 다음과 같이 작성한다면 어떤 일이 벌어질까요?

List<MusicData> songs = objectMapper.readValue(responseData, List.class);  

위와 같이 작성하면 objectMapper.readValue() 메서드는 반환 타입으로 List를 사용하게 됩니다. 하지만 이는 실제로는 List로 반환되는 것과 같습니다. 즉, 제네릭 타입 정보가 손실되어 모든 객체가 Object로 처리되게 됩니다.

이 경우, "songs 변수는 List 타입으로 선언되어 다른 코드에서 사용할 때 문제가 발생할 수 있습니다." 예를 들어, songs 리스트의 요소를 가져올 때 강제 형변환을 해야하고, 의도하지 않은 타입 불일치로 인한 런타임 오류가 발생할 수 있습니다.

따라서 TypeReference를 사용하여 제네릭 타입 정보를 유지함으로써, 정확한 타입으로 데이터를 역직렬화할 수 있게 됩니다. TypeReference는 제네릭 타입의 정보를 보존하기 위해 Jackson 라이브러리에서 제공되는 유틸리티 클래스입니다. 이를 사용하여 역직렬화할 때 원하는 제네릭 타입을 지정할 수 있습니다.

profile
better than yesterday

0개의 댓글