Controller 에서 response 값에 null 값은 어떻게 처리 할까? Gson의 toJson & toJsonTree
생일날 적어보는 포스팅 뭐 생일이라고 별거 있나,,
이전 포스팅에서 restcontroller에서 body에서 담긴 null값을 어떻게 처리 하는지 알아봤었다.
#####Controller 에서 response의 null 값은 어떻게 처리 할까?
이글에서 해결방법은 gson.serializeNulls() 과 application properties에 spring.gson.serialize-nulls= true 를 통해 2중으로 serialize를 하는 방법이였다.
나도 이 방법을 국내 블로그가 아닌 이곳(gson with spring config) 에서 확인 하였다. 이 글이 한번쯤 확인해 볼만한 글이여서 이번에는
위 저널을 적어보려 한다.
Gson with Spring BootPermalink
이 아티클에선 Google의 gson을 spring boot 에서 어떻게 사용하는지에 대해 정리한다. Gson 은 Java 객체를 Json 으로 serialize deserialize 해주는 오픈소스 라이브러리이다.
0.IntroPermalink
Spring Boot 는 Java 객체를 직렬/역직렬화 하는 라이브러리로 Jackson을 기본 라이브러리로 사용한다.
만약 당신의 어플리케이션에 “spring boot starter”를 추가한다면, 우리 classpath에 위의 Jackson 라이브러리가 추가가 된다.
이것은 굉장히 편리하지만, 가끔 우리는 SPRING BOOT가 자동으로 설정한 설정 말고 다른 API 를 사용하고 싶을수 있다.
그렇기에 이 아티클에선 Spring Boot 와 Gson을 사용하는 방법을 단계별로 알려준다.
Spring Boot는 특정 기본값이 있는 지능형 시스템이며, Gson에 대한 auto configuration 또한 존재한다.
Spring boot 는 Gson이 class path에 있음을 발견하면 자동으로 Gson bean을 등록한다.
또한 Spring Boot는 application.properties에 여러 Gson 특정 속성을 제공합니다.
Maven DependencyPermalink
첫째로 할것은 우리의 환경에 Gson dependency 를 pom.xml 에 추가하는 것이다.
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version> <!-- check latest version for GSON -->
</dependency>
위의 설정을 통해, Spring Boot는 Gson bean을 합리적 기본값으로 만든다? (이건 무슨말인지?)
이를 통해 Spring 은 Google Gson 라이브러리르 사용하여 Json을 읽고 쓸수 있는 GsonHttpMessageConverter를 제공할수 있게 된다.
1.1 Using Gson as default MapperPermalink
우리는 Gson을 class path에 등록 하였지만, Gson을 application.properties 에 추가 하여 사용하여 한다.
spring.http.converters.preferred-json-mapper=gson #Preferred JSON mapper to use for HTTP message conversion.
기본 json mapper 설정을 하지 않는다면
org.springframework.http.converter.HttpMessageNotWritableException
와 같은 에러를 만날수도 있다.
1.2 Gson ConfigurationPermalink
내가 저번 문제를 해결한 설정
Spring Boot는 Gson configuration 에 대해 여러가지 설정을 제공한다하였다. 아래가 그 리스트이다.
# Format to use when serializing Date objects.
# Date 객체를 직렬화할 때 사용할 포맷
spring.gson.date-format=
# Whether to disable the escaping of HTML characters such as '<', '>', etc.
# '<', '>', 같은 HTML 문자의 이스케이프를 비활성화할지에 대한 여부
spring.gson.disable-html-escaping=
# Whether to exclude inner classes during serialization.
# 직렬화 중에 내부 클래스를 제외할지에 대한 여부
spring.gson.disable-inner-class-serialization=
# Whether to enable serialization of complex map keys (i.e. non-primitives).
# 복잡한 맵 키 (즉, 기본이 아닌 키) 의 직렬화를 활성화 할지에 대한 여부 ??? 뭐지
spring.gson.enable-complex-map-key-serialization= # Whether to enable serialization of complex map keys (i.e. non-primitives).
# Whether to exclude all fields from consideration for serialization or deserialization that do not have the "Expose" annotation.
# Expose 주석이 없는 직렬화 또는 역직렬화에 대한 고려에서 모든 필드를 제외할지 여부
spring.gson.exclude-fields-without-expose-annotation=
# Naming policy that should apply to an object's field during serialization and deserialization.
# 직렬화및 역직렬화 중에 개체의 필드에 적용해야 하는 명명 정책
spring.gson.field-naming-policy=
# Whether to generate non executable JSON by prefixing the output with some special text.
# 출력에 특별한 텍스트를 접두사로 붙여 실행 불가능한 Json을 생성할지 여부
spring.gson.generate-non-executable-json=
# Whether to be lenient about parsing JSON that doesn't conform to RFC 4627.
# RFC 4672? 를 준수하지 않는 json 구분 분석에 대해 허용할지?
spring.gson.lenient=
# Serialization policy for Long and long types.
# Long 및 Long 유형에 대한 직렬화 정책
spring.gson.long-serialization-policy=
# Whether to output serialized JSON that fits in a page for pretty printing.
# 페이지에 맞는 pretty 형태의 Json
spring.gson.pretty-printing=
# *******************************
# Whether to serialize null fields.
# null 필드를 직렬화 할지 여부
spring.gson.serialize-nulls=
2. Exclude Jackson DependencyPermalink
만약 Gson을 우리 스프링 부트의 기본 라이브러리로 설정하였다면, Jackson을 classpath에서 제외시켜 주어야 한다.
이 Jackson을 제외시키는 방법은 2가지가 있다.
2.1 Using MavenPermalink
가장 쉬운 방법은 pom.xml에서 exclude tag를 통해 제외를 시키는 방법이다. Spring Boot 는 web-starter 를 통해 Jackson을 추가하게 된다. 우리가 필요한건 web-starter 내에서 Jackson을 제외 시켜주는 것이다.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- Exclude the default Jackson dependency -->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
</dependencies>
2.2 Using Exclude propertyPermalink
두번째 대안은 property와 @EnableAutoConfiguration 또는 @SpringBootApplication 어노테이션에 추가를 해주는것이다.,
@SpringBootApplication(exclude = {JacksonAutoConfiguration.class})
public class GsonSpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(GsonSpringBootApplication.class, args);
}
}
위 옵션을 사용하면, Spring Boot에 의해 구성된 매퍼가 하나만 있기 때문에 spring.http.converters.preferred-json-mapper 를 무시하고 넘어갈 수 있다.
3. Customize Using HttpMessageConvertersPermalink
Spring Boot Application 에서 Gson Mapper 동작을 커스마이징 하기 위해 WebMvcConfigurerAdapter 를 확장하여 Spring 에서 Http Message Converter를 사용할 수 있다.
아래는 Json converter 의 날짜 형식을 사용자가 원하는데로 지정하는 예를 보여준다.
@Configuration
public class ApplicationConfig extends WebMvcConfigurerAdapter {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(customGsonHttpMessageConverter());
super.configureMessageConverters(converters);
}
private GsonHttpMessageConverter customGsonHttpMessageConverter() {
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.setDateFormat("yyyy'-'MM'-'dd'T'HH':'mm':'ss'")
.create();
GsonHttpMessageConverter gsonMessageConverter = new GsonHttpMessageConverter();
gsonMessageConverter.setGson(gson);
return gsonMessageConverter;
}
}
WebMvcConfigurerAdapter 는 스프링 2.0 에서 제외(Deprecated) 되었음