👩🏻‍💻 Programming/SpringBoot

@JsonUnwrapped의 개념과 사용법

한국의 메타몽 2022. 3. 7. 19:26

JsonUnwrapped란?

 

객체 내부의 프로퍼티(Property), 다시말해 객체 내부의 변수가 unwrapped 상태로 직렬화가 이루어져야할때 사용되는 어노테이션이다.

이해하기 쉽게 아래 예시를 봐보자.

 

Department.java

package com.logicbig.example;

public class Department {
  private String deptName;
  private String location;
    .............
}

 

Employee.java

package com.logicbig.example;

import com.fasterxml.jackson.annotation.JsonUnwrapped;

public class Employee {
  private String name;
  @JsonUnwrapped
  private Department dept;
    .............
}

 

Main.java

public class ExampleMain {
  public static void main(String[] args) throws IOException {
      Department dept = new Department();
      dept.setDeptName("Admin");
      dept.setLocation("NY");
      Employee employee = new Employee();
      employee.setName("Amy");
      employee.setDept(dept);

      System.out.println("-- before serialization --");
      System.out.println(employee);

      System.out.println("-- after serialization --");
      ObjectMapper om = new ObjectMapper();
      String jsonString = om.writeValueAsString(employee);
      System.out.println(jsonString);

      System.out.println("-- after deserialization --");
      Employee employee2 = om.readValue(jsonString, Employee.class);
      System.out.println(employee2);
  }
}

 

+ @JsonUnwrapped가 사용된 상태의 직렬화 / 역직렬화

-- before serialization --
Employee{name='Amy', dept=Department{deptName='Admin', location='NY'}}
-- after serialization --
{"name":"Amy","deptName":"Admin","location":"NY"}
-- after deserialization --
Employee{name='Amy', dept=Department{deptName='Admin', location='NY'}}

중간부분을 확인해보면 Department가 unwrapped 상태로 직렬화 됐다.

 

+ @JsonUnwrapped가 사용되지 않은 상태로 직렬화 / 역직렬화

-- before serialization --
Employee{name='Amy', dept=Department{deptName='Admin', location='NY'}}
-- after serialization --
{"name":"Amy","dept":{"deptName":"Admin","location":"NY"}}
-- after deserialization --
Employee{name='Amy', dept=Department{deptName='Admin', location='NY'}}

보다시피 어떤 방법으로든 Department가 unwrapped되지 않았다.

 

 

 

실제 사용 예시

 

JUnit을 통해 API의 Response를 테스트 하던 중, 아래와 같은 에러가 발생했다.

19:16:21.306 [Test worker] ERROR c.h.i.a.p.내가테스트중인.대상 - server error(Type definition error: [simple type, class 내가테스트중인DTO$ResponseBody]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class 내가테스트중인DTO$ResponseBody and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: 내가테스트중인DTO$Response["body"]))

* 개인정보는 임의로 이름을 변경

 

No serializer found for class, no properties discovered to create BeanSerializer 에러가 발생했는데,

이유인 즉슨 말 그대로 No serializer, 다시말해 직렬화 된 데이터가 없어서 데이터를 읽어들이는데 실패해서 발생한 에러였다.

 

    @Builder
    @AllArgsConstructor
    public static class ResponseBody {
        private long totalUseCount;
        @JsonUnwrapped
        private List<MultipleUseDto> results;
        
        ...

위와 같이 직렬화가 필요한 대상에게 @JsonUnwrapped를 추가해줬더니 에러가 사라지고 테스트 코드가 정상적으로 작동했다

 

 

 

참고 자료

 

Jackson JSON - Using @JsonUnwrapped to serialize/deserialize properties as flattening data structure

Jackson JSON - Using @JsonUnwrapped to serialize/deserialize properties as flattening data structure [Last Updated: Aug 11, 2020]

www.logicbig.com