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를 이용하여 매핑되지 않은 속성을 무시할 수 있습니다.
참고 사이트
- Jackson 공식 문서: https://github.com/FasterXML/jackson
- Spring Boot 공식 문서: https://spring.io/projects/spring-boot
'JAVA' 카테고리의 다른 글
[JAVA] Jackson과 Spring Boot 통합 (0) | 2024.11.15 |
---|---|
[JAVA] Jackson을 활용한 XML 데이터 처리 (0) | 2024.11.14 |
[JAVA] Jackson의 성능 최적화 전략 (0) | 2024.11.13 |
[JAVA] Jackson 커스텀 모듈 사용하기 (0) | 2024.11.12 |
[JAVA] Jackson과 Java 8 이상 기능 연동 (2) | 2024.11.12 |
[JAVA] Jackson의 Data Binding API와 Tree Model API 차이점 (0) | 2024.11.12 |
[JAVA] Jackson Tree Model API 활용하기 (1) | 2024.11.12 |
[JAVA] Jackson 컬렉션 및 배열 데이터 처리 (1) | 2024.11.12 |