Spring Boot를 이용해 개발을 하면서 ObjectMapper를 직간접적으로 사용하고 있었다. 기본 ObjectMapper를 사용했을 때 자주 잊어버리는 항목인 것 같아 이번 기회에 정리해보았다.
class TestObject {
private Long id;
private String name;
}
Object에 해당하는 클래스에 @NoArgsConstructor가 필요하고 @Getter 또는 @Setter가 필요하다.
spring boot에서 request json 문자열을 DTO 객체로 변환하는 과정이다.
ObjectMapper mapper = new ObjectMapper();
final String value = "{\"name\":\"test\",\"id\":1}";
TestObject resObject = mapper.readValue(value, TestObject.class);
Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "name" (class com.test.teamlog.global.security.TestObject), not marked as ignorable (0 known properties: ])
at [Source: (String)"{"name":"test","id":1}"; line: 1, column: 10] (through reference chain: com.test.teamlog.global.security.TestObject["name"])
필드가 없다면서 UnrecognizedPropertyException이 발생한다.
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.test.teamlog.global.security.TestObject` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
no Creators, like default constructor 라면서 기본 생성자를 만들어달라고 에러를 뱉는다.
인턴 시절 실무에서 뭣모르고 했다가 종종 버그가 발생했던 사례가 떠올라 적어보기로 했다. 당시 특정 필드의 값을 request로부터 받는 시점에 변환하고 싶었던 모양이었는지 request dto에 해당하는 클래스의 필드에 대한 setter를 재정의했다. (왜 그랬지...) 아래와 같이 말이다.
@Getter
class TestObject {
private Long id;
private String name;
public void setName(String name) {
this.name = "Hello, my name is " + name;
}
}
spring boot에서 DTO 객체 -> response로 변환하는 과정이다.
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.test.teamlog.global.security.TestObject and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
기본적으로 public인 필드에 접근하게 된다. 즉, 필드를 public으로 열어주거나 getter 메소드를 열어주어 접근 가능하도록 해야한다.