Spring MVC에서 ObjectMapper로 json 포맷의 request body를 DTO 객체로 역직렬화 하는 방법은 크게 두 가지이다.

디폴트 생성자가 있을 경우,

이 경우는 다음과 같은 순서를 따라 역직렬화를 수행한다. 역직렬화의 시작점은 BeanDeserializer이다.

  1. BeanDeserializer.deserializeFromObject()에서 디폴트 생성자를 이용한 리플렉션 기법(Constructor.newInstance(Object[] args)으로 DTO 객체를 생성한다.
  2. FieldProperty.deserializeAndSet(...)에서 리플렉션으로 얻어온 Field에 JSON 포맷에서 얻은 값을 set한다. 여기서의 Field는 DTO 객체의 멤버 필드의 메타 정보를 포함한 객체이다.

디폴트 생성자가 있을 경우의 결론은 디폴트 생성자를 이용해서 Java의 리플렉션을 이용해 Field에 값을 세팅한다.

 

디폴트 생성자가 없을 경우,

문제는 디폴트 생성자가 없을 경우이다.

이 경우는 IntelliJ에서 Gradle 빌드 옵션(IntelliJ > Settings > Build, Execution, Deployment > Build Tools > Gradle)을 Gradle(default)로 설정하느냐 IntelliJ로 설정하느냐에 따라 다르다.

여기서의 핵심은 PropertyBasedCreator 객체가 null이냐 그렇지 않느냐이다.

 

Gradle 빌드 옵션을 Gradle(default)로 설정할 경우,

디폴트 생성자가 없어도 argument가 있는 Constructor 정보를 이용한 리플렉션 기법을 통해 JSON에서 DTO 객체로 역직렬화가 된다. 

PropertyBasedCreator 객체가 null이 아니다.

 

PropertyBasedCreator가 null이 아니므로, BeanDeserializer.deserializeFromObjectUsingNonDefault() 에서 시작해 내부적으로 더 들어 가면,

PropertyBasedCreator가 StdValueInstantiator를 이용해 역시 리플렉션 기법으로 argument가 있는 Constructor로 객체를 생성한다.

argument가 있다라는 것은 DTO 클래스의 필드에 생성자 주입을 통해 바로 값이 세팅된다라는 의미와 같다.

 

Gradle 빌드 옵션을 IntelliJ로 설정할 경우,

디폴트 생성자가 없으면 JSON에서 DTO 객체로 역직렬화가 되지 않는다.

PropertyBasedCreator 객체가 null이다.

PropertyBasedCreator가 null 이므로, 디폴트 생성자나 argument가 있는 생성자를 이용해 리플렉션으로 DTO 클래스의 객체를 생성할 수 없다.

 

PropertyBasedCreator에 대해서는 아래와 같이 설명하고 있다.

Object that is used to collect arguments for non-default creator (non-default-constructor, or argument-taking factory method) before creator can be called. Since ordering of JSON properties is not guaranteed, this may require buffering of values other than ones being passed to creator.

즉, 디폴트 생성자가 아닌 생성자의 argument를 수집하는데 사용한다고 설명이 나와 있음.

 

결론

  • Gradle 빌드 옵션이 Gradle(default)일 경우, 디폴트 생성자가 없어도 리플렉션을 통해 argument가 있는 Constructor 정보로 DTO 객체를 생성할 수 있다. 즉, 어떤 경우도 역직렬화가 가능하다.
  • Gradle 빌드 옵션을, IntelliJ로 설정하면 PropertyBasedCreator 객체가 생성되지 않으므로, 디폴트 생성자가 반드시 있어야지만 역직렬화가 가능하다.
  • Gradle 빌드 옵션을 바꾸지 말자.

+ Recent posts

출처: http://large.tistory.com/23 [Large]