[java] Spring Boot에서 암시 적으로 사용되는 Jackson JSON 매퍼를 사용자 정의하는 방법은 무엇입니까?

RESTful 웹 서비스 구축 튜토리얼 에서와 비슷한 방식으로 Spring Boot (1.2.1)를 사용하고 있습니다.

@RestController
public class EventController {

    @RequestMapping("/events/all")
    EventList events() {
        return proxyService.getAllEvents();
    }

}

따라서 위의 Spring MVC는 EventListJSON으로 객체 를 직렬화하기 위해 암시 적으로 Jackson을 사용합니다 .

하지만 다음과 같이 JSON 형식에 대한 몇 가지 간단한 사용자 지정을 수행하고 싶습니다.

setSerializationInclusion(JsonInclude.Include.NON_NULL)

질문은 암시 적 JSON 매퍼를 사용자 정의하는 가장 간단한 방법은 무엇입니까?

이 블로그 게시물 에서 CustomObjectMapper 등을 만드는 방법을 시도했지만 3 단계 “Spring 컨텍스트에서 클래스 등록”은 실패합니다.

org.springframework.beans.factory.BeanCreationException:
  Error creating bean with name 'jacksonFix': Injection of autowired dependencies failed;
  nested exception is org.springframework.beans.factory.BeanCreationException:
  Could not autowire method: public void com.acme.project.JacksonFix.setAnnotationMethodHandlerAdapter(org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter);
  nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
  No qualifying bean of type [org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter]
  found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}

이 지침은 이전 버전의 Spring MVC에 대한 것 같지만 최신 Spring Boot에서이 작업을 수행하는 간단한 방법을 찾고 있습니다.



답변

Spring Boot 1.3을 사용하는 경우 다음을 통해 직렬화 포함을 구성 할 수 있습니다 application.properties.

spring.jackson.serialization-inclusion=non_null

Jackson 2.7의 변경 사항에 따라 Spring Boot 1.4는 spring.jackson.default-property-inclusion대신 이름이 지정된 속성을 사용합니다 .

spring.jackson.default-property-inclusion=non_null

Spring Boot 문서의 ” Customize the Jackson ObjectMapper “섹션을 참조하십시오 .

이전 버전의 Spring Boot를 사용하는 경우 Spring Boot에 직렬화 포함을 구성하는 가장 쉬운 방법은 적절하게 구성된 고유 한 Jackson2ObjectMapperBuilderBean 을 선언하는 것 입니다. 예를 들면 :

@Bean
public Jackson2ObjectMapperBuilder objectMapperBuilder() {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    builder.serializationInclusion(JsonInclude.Include.NON_NULL);
    return builder;
}


답변

나는이 질문에 조금 늦게 대답하고 있지만, 미래에 누군가가 유용하다고 생각할 것입니다. 아래의 접근 방식은 다른 많은 접근 방식 외에도 가장 잘 작동하며 개인적으로 웹 애플리케이션에 더 적합 할 것이라고 생각합니다.

@Configuration
@EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter {

 ... other configurations

@Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        builder.serializationInclusion(JsonInclude.Include.NON_NULL);
        builder.propertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
        builder.serializationInclusion(Include.NON_EMPTY);
        builder.indentOutput(true).dateFormat(new SimpleDateFormat("yyyy-MM-dd"));
        converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
        converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
    }
}


답변

응용 프로그램 속성에서 많은 것을 구성 할 수 있습니다. 불행히도이 기능은 버전 1.3에서만 가능하지만 Config-Class에 추가 할 수 있습니다.

@Autowired(required = true)
public void configureJackson(ObjectMapper jackson2ObjectMapper) {
    jackson2ObjectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}

[업데이트 : build()구성이 실행되기 전에 -method가 호출 되므로 ObjectMapper에서 작업해야합니다 .]


답변

문서 에는이를 수행하는 여러 방법이 나와 있습니다.

기본값을 ObjectMapper완전히 바꾸려면 @Bean해당 유형 의을 정의 하고로 표시하십시오 @Primary.

결정적인 @Bean유형은 Jackson2ObjectMapperBuilder기본적 모두 사용자 정의 할 수 있습니다 ObjectMapperXmlMapper(에 사용 MappingJackson2HttpMessageConverter하고 MappingJackson2XmlHttpMessageConverter각각을).


답변

주석이 달린 부트 스트랩 클래스 내부에 다음 메서드를 추가 할 수 있습니다. @SpringBootApplication

    @Bean
    @Primary
    public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
    ObjectMapper objectMapper = builder.createXmlMapper(false).build();
    objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    objectMapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false);

    objectMapper.registerModule(new JodaModule());

    return objectMapper;
}


답변

spring.jackson.serialization-inclusion=non_null 우리를 위해 일했던

하지만 스프링 부트 버전을 1.4.2.RELEASE 이상으로 업그레이드했을 때 작동이 멈췄습니다.

자, 또 다른 속성 spring.jackson.default-property-inclusion=non_null 이 마술을하고 있습니다.

실제로 serialization-inclusion는 더 이상 사용되지 않습니다. 이것이 내 intellij가 나에게 던지는 것입니다.

더 이상 사용되지 않음 : ObjectMapper.setSerializationInclusion은 Jackson 2.7에서 더 이상 사용되지 않습니다.

따라서 spring.jackson.default-property-inclusion=non_null대신 사용 을 시작하십시오.


답변

나는 아주 좋은 또 다른 해결책을 우연히 발견했습니다.

기본적으로 언급 된 블로그에서 2 단계 만 수행 하고 사용자 정의 ObjectMapper를 Spring으로 정의합니다 @Component. ( 3 단계에서 모든 AnnotationMethodHandlerAdapter 항목을 방금 제거 했을 때 상황이 작동하기 시작했습니다. )

@Component
@Primary
public class CustomObjectMapper extends ObjectMapper {
    public CustomObjectMapper() {
        setSerializationInclusion(JsonInclude.Include.NON_NULL);
        configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }
}

구성 요소가 Spring에서 스캔 한 패키지에있는 한 작동합니다. (사용@Primary 제 경우에는 이 필수는 아니지만 명시 적으로 만드는 것은 어떻습니까?)

저에게는 다른 접근 방식에 비해 두 가지 이점이 있습니다.

  • 이것은 더 간단합니다. Jackson에서 클래스를 확장 할 수 있으며 .NET과 같은 Spring 관련 항목에 대해 알 필요가 없습니다 Jackson2ObjectMapperBuilder.
  • 나는 내 응용 프로그램의 다른 부분에서 JSON을 deserialising 동일한 잭슨 CONFIGS를 사용하려면,이 방법은 매우 간단합니다 : new CustomObjectMapper()대신 new ObjectMapper().