프로젝트를 진행하던 중, DTO 객체에서 다음과 같은 문제가 발생했다.
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.example.interfaces.dto.SampleDto and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
무슨 문제고 왜 발생했을까? 🤔
문제는 구글링을 통해서 쉽게 찾아낼 수 있었다. 스프링 부트에서는 기본적으로 Jackson 라이브러리가 탑재(?)되어있는데 - Serialize 하는 과정에서 접근 제한자가 public이거나 Getter/Setter를 이용하기 때문에 필드가 private로 선언되어있으면 JSON 변환 과정에서 문제가 발생하는 것이였다.
💡 여기서 말하는 Serialize는 무슨 의미일까?
여기서 Serialize 한다는 의미는 변환한다는 의미로 보면 된다.
- Object to JSON (Serialize)
- JSON to Object (Deserialize)
- Custom (요구 사항에 따라 조절)
💡 (번외) DTO 클래스 - Serializable를 구현하라?
DTO, VO 객체 클래스를 보면 Serializabe 인터페이스를 구현한 코드를 많이 확인할 수 있는데, 객체를 담을 클래스는 기본적으로 Serializable을 구현하는 것을 권장한다고 한다. 직렬화 자체가 오버헤드의 원인이 되기도 하지만, Serializable은 해당 클래스의 인스턴스를 직렬화가 가능하다는 것을 선언하는 것 뿐이니, 설계를 고려해서 잠재적으로 직렬화 가능성이 있는 유형은 Serializable을 구현하는 편이 좋다고 한다. 참고로 Serializable 인터페이스는 serialVersionUID가 선언되어있어야 한다.
가장 좋은 해결책은 Getter를 사용하는 것이라고 생각한다. 하지만 Getter를 사용했음에도 해결되지 않아 추가적으로 알아본 내용들을 정리해보자.
ObjectMapper의 인스턴스에서 private 필드로 접근이 가능하도록 구성하거나 @JsonProperty
혹은 @JsonAutoDetect
어노테이션을 이용하여 해결할 수 있다. 이 중에서도 가장 생소한 @JsonAutoDetect
에 대해서 알아보자.
@JsonAutoDetect
는 private 필드에 접근하도록 설정할 수 있다. 옵션으로는 DEFAULT, NON_PRIVATE, NONE, PROTECTED,_AND_PUBLIC, PUBLIC_ONLY, ANY
가 있는데, 그 중 ANY
를 활용한 코드를 살펴보자.
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
public class Employee {
private long id;
private String name;
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + "]";
}
}
추가로, 앞에서 이야기하지 않았지만 FAIL_ON_EMPTY_BEANS 예외를 무시하는 방법도 있는데, 무시하는 행위 자체가 그렇게 좋다고 볼 수 없기 때문에 눈으로만 스윽 👀 보고 넘어가자.
spring.jackson.serialization.FAIL_ON_EMPTY_BEANS=false
덕분에 좋은 정보 잘 보고 갑니다.
감사합니다.