JAVA

[JAVA] Jackson 자주 발생하는 오류와 해결 방법

인생아 2024. 11. 15. 18:32
반응형

Jackson은 Java에서 JSON 데이터 직렬화와 역직렬화를 매우 편리하게 수행할 수 있는 라이브러리지만, 사용 중 발생할 수 있는 다양한 오류들이 있습니다. 특히, JSON과 Java 객체 간의 매핑 문제나 설정 오류로 인해 UnknownPropertyException이나 No serializer found 등의 예외가 자주 발생합니다. 이번 포스트에서는 Jackson 사용 시 발생할 수 있는 예외와 해결 방법을 다뤄보고, 각 오류의 발생 원인과 해결 방법을 구체적인 예제 코드와 함께 설명하겠습니다.

Jackson 사용 시 발생할 수 있는 주요 예외와 해결 방법

1. UnknownPropertyException과 기본 해결법

UnknownPropertyException은 JSON 문자열에서 Java 클래스에 정의되지 않은 속성을 포함하고 있을 때 발생합니다. 예를 들어, 서버에서 내려온 JSON 데이터에 Java 클래스에는 정의되어 있지 않은 속성이 포함된 경우 발생할 수 있습니다.

{
  "name": "김철수",
  "city": "서울",
  "age": 30,
  "gender": "남"
}

위 JSON 데이터를 매핑할 Java 클래스에 gender 속성이 없다면, Jackson은 기본적으로 UnknownPropertyException을 발생시킵니다.

해결 방법 1: @JsonIgnoreProperties 어노테이션 사용

가장 간단한 해결 방법은 @JsonIgnoreProperties(ignoreUnknown = true) 어노테이션을 사용해 매핑되지 않은 속성을 무시하도록 설정하는 것입니다.

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public class User {
    private String name;
    private String city;
    private int age;

    // Getters and Setters
}

위와 같이 설정하면, Jackson은 JSON 데이터에 gender 속성이 있어도 해당 필드를 무시하고 User 객체를 생성합니다. 이 방법은 서버와 클라이언트 간 데이터 일관성이 중요하지 않거나 일부 속성만 사용할 때 유용합니다.

해결 방법 2: ObjectMapper 설정 변경

ObjectMapper 설정을 통해 UnknownPropertyException이 발생하지 않도록 할 수도 있습니다. 이를 위해 DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES 옵션을 false로 설정할 수 있습니다.

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonConfig {
    public static void main(String[] args) throws Exception {
        String jsonData = "{\"name\": \"김철수\", \"city\": \"서울\", \"age\": 30, \"gender\": \"남\"}";

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        User user = objectMapper.readValue(jsonData, User.class);
        System.out.println(user.getName()); // 김철수 출력
    }
}

위 설정은 FAIL_ON_UNKNOWN_PROPERTIES를 false로 지정하여, UnknownPropertyException이 발생하지 않고 설정된 필드만 매핑합니다.

2. No serializer found 예외와 해결 방법

No serializer found 예외는 Jackson이 특정 클래스를 JSON으로 직렬화할 때 필요한 Serializer를 찾지 못했을 때 발생합니다. 대표적으로 ObjectMapper가 Java 객체를 JSON으로 변환하는 과정에서, Jackson이 해당 객체에 대한 직렬화 방법을 모를 때 발생합니다.

예를 들어, 아래와 같은 Order 클래스에 LocalDate와 같은 직렬화되지 않는 속성이 있을 경우 발생할 수 있습니다.

import java.time.LocalDate;

public class Order {
    private String orderId;
    private LocalDate orderDate;
    private String customerName;

    public Order(String orderId, LocalDate orderDate, String customerName) {
        this.orderId = orderId;
        this.orderDate = orderDate;
        this.customerName = customerName;
    }

    // Getters and Setters
}

해결 방법 1: JavaTimeModule 모듈 추가

LocalDate와 같은 Java 8 날짜 형식을 사용하려면 Jackson의 JavaTimeModule 모듈을 등록해야 합니다.

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

public class JacksonConfig {
    public static void main(String[] args) throws Exception {
        Order order = new Order("12345", LocalDate.now(), "김영희");

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());

        String json = objectMapper.writeValueAsString(order);
        System.out.println(json); // JSON 문자열 출력
    }
}

JavaTimeModule을 추가하면 LocalDate와 같은 Java 8 날짜 유형을 정상적으로 직렬화할 수 있습니다. 이 설정을 통해 No serializer found 예외를 방지할 수 있습니다.

해결 방법 2: 커스텀 Serializer 작성

커스텀한 직렬화 로직이 필요한 경우, 직접 Serializer를 구현해 사용할 수도 있습니다. 예를 들어, LocalDate의 형식을 "yyyy-MM-dd"로 지정하고 싶다면 아래와 같이 Custom Serializer를 작성할 수 있습니다.

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class LocalDateSerializer extends StdSerializer<LocalDate> {
    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    public LocalDateSerializer() {
        super(LocalDate.class);
    }

    @Override
    public void serialize(LocalDate date, JsonGenerator generator, SerializerProvider provider) throws IOException {
        generator.writeString(date.format(formatter));
    }
}

위의 LocalDateSerializer는 LocalDate 객체를 "yyyy-MM-dd" 형식으로 직렬화합니다. 이제 이 Serializer를 Order 클래스에 적용합니다.

import com.fasterxml.jackson.databind.annotation.JsonSerialize;

public class Order {
    private String orderId;

    @JsonSerialize(using = LocalDateSerializer.class)
    private LocalDate orderDate;

    private String customerName;

    public Order(String orderId, LocalDate orderDate, String customerName) {
        this.orderId = orderId;
        this.orderDate = orderDate;
        this.customerName = customerName;
    }

    // Getters and Setters
}

이렇게 하면, LocalDate 필드는 커스텀한 LocalDateSerializer를 통해 지정한 형식대로 JSON 문자열로 변환됩니다.

추가 오류와 해결 방법: JsonMappingException

JsonMappingException은 매핑 과정에서 다양한 이유로 발생할 수 있는 예외입니다. 예를 들어, JsonParseException은 JSON 형식이 올바르지 않거나, UnrecognizedPropertyException은 JSON에 정의되지 않은 속성이 포함된 경우 발생할 수 있습니다.

JsonMappingException 해결 방법

  • JSON 구조가 맞는지 확인하거나, Jackson 설정을 통해 필요하지 않은 속성을 무시하도록 설정합니다.
  • @JsonIgnoreProperties를 이용하여 매핑되지 않은 속성을 무시할 수 있습니다.

참고 사이트

반응형