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


101

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에서이 작업을 수행하는 간단한 방법을 찾고 있습니다.


이 주석을 삽입 했습니까? : @SuppressWarnings ({ "SpringJavaAutowiringInspection"})
sven.kwiotek

Spring Web을 사용하는 경우에도이 ObjectMapper를 사용하도록 수동으로 알려야합니다. 그렇지 않으면 구성되지 않는 자체 인스턴스가 생성됩니다. 보다 stackoverflow.com/questions/7854030/…
Constantino Cronemberger

답변:


116

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;
}

1
알겠습니다. 작동하는 것 같습니다. 그런 방법을 어디에 두겠습니까? 아마도 기본 Application 클래스 ( @ComponentScan, @EnableAutoConfiguration등)에 있습니까?
Jonik

2
예. 이 메서드는 @Configuration앱의 모든 클래스에 사용할 수 있습니다. 메인 Application클래스는 좋은 장소입니다.
Andy Wilkinson

2
중요 사항 : Jackson2ObjectMapperBuilder 클래스는 spring-web 구성 요소의 일부이며 버전 4.1.1에 추가되었습니다.
gaoagong 2015 년

2
@Deprecated setSerializationInclusion
Dimitri Kopriwa

6
더 이상 사용되지 않음 : ObjectMapper.setSerializationInclusion은 Jackson 2.7에서 더 이상 사용되지 않습니다. 대신 stackoverflow.com/a/44137972/6785908 spring.jackson.default-property-inclusion = non_null 사용
so-random-dude

24

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

@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
최신 버전에서는 구현해야합니다WebMvcConfigurer
João Pedro Schmitt

예, 사람들,이 솔루션을 사용해보십시오. ObjectMapper에 Bean을 제공 한 다음 작동하지 않는 Jackson2ObjectMapperBuilder 구매에 Bean을 제공하려고 시도했지만 여전히 이유를 모릅니다. 추가 커버 터가 작동했습니다!
Somal Somalski

23

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

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

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


그것이 내 하루를 구한 해결책이었습니다. 이 메서드를 구성 클래스가 아닌 REST 컨트롤러 자체에 추가 한 것을 제외하고는.
Nestor Milyaev

20

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

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

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


2
기본값을 바꾸지 않고 동일한 작업을 수행하는 방법은 ObjectMapper무엇입니까? 나는 기본뿐만 아니라 관습을 유지하는 것을 의미합니다.
soufrk

12

주석이 달린 부트 스트랩 클래스 내부에 다음 메서드를 추가 할 수 있습니다. @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;
}

이것은 Boot 2.1.3을 사용하여 나를 위해 일했습니다. spring.jackson 속성은 효과가 없었습니다.
Richtopia

9

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대신 사용 을 시작하십시오.


4

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

기본적으로 언급 된 블로그에서 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().

이 접근 방식의 단점은 사용자 지정 구성이 ObjectMapperSpring Boot에 의해 생성되거나 구성되는 인스턴스에 적용되지 않는다는 것 입니다.
Andy Wilkinson

흠, 사용자 지정 구성 @RestController 현재 저에게 충분한 클래스 의 암시 적 직렬화에 사용됩니다 . (그러면 해당 인스턴스가 Spring Boot가 아닌 Spring MVC에 의해 생성된다는 의미입니까?)하지만 ObjectMappers를 인스턴스화해야하는 다른 경우에 부딪히면 Jackson2ObjectMapperBuilder 접근 방식을 염두에 두겠습니다!
Jonik

3

스프링 부트 2.0.6에서 ObjectMapper를 기본으로 만들려고 할 때 오류가 발생하여 스프링 부트가 나를 위해 만든 것을 수정했습니다.

또한 참조 https://stackoverflow.com/a/48519868/255139

@Lazy
@Autowired
ObjectMapper mapper;

@PostConstruct
public ObjectMapper configureMapper() {
    mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);

    mapper.configure(MapperFeature.ALLOW_COERCION_OF_SCALARS, true);
    mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);

    SimpleModule module = new SimpleModule();
    module.addDeserializer(LocalDate.class, new LocalDateDeserializer());
    module.addSerializer(LocalDate.class, new LocalDateSerializer());
    mapper.registerModule(module);

    return mapper;
}

1

위에서 설명한 솔루션을 찾았습니다.

spring.jackson.serialization-inclusion = non_null

1.4.0.RELEASE 버전의 스프링 부트에서만 작동합니다. 다른 모든 경우에는 구성이 무시됩니다.

스프링 부트 샘플 "spring-boot-sample-jersey"를 수정하여 실험하여이를 확인했습니다.


0

나는 스프링 부트를 요구하는 질문을 알고 있지만 거의 하루 종일 검색하는 것처럼 스프링이 아닌 부트에서 이것을 수행하는 방법을 찾는 많은 사람들이 믿습니다.

Spring 4 이상에서는 구성 MappingJacksonHttpMessageConverter하려는 경우 구성 할 필요가 없습니다.ObjectMapper .

다음을 수행하면됩니다.

public class MyObjectMapper extends ObjectMapper {

    private static final long serialVersionUID = 4219938065516862637L;

    public MyObjectMapper() {
        super();
        enable(SerializationFeature.INDENT_OUTPUT);
    }       
}

그리고 Spring 구성에서 다음 빈을 만듭니다.

@Bean 
public MyObjectMapper myObjectMapper() {        
    return new MyObjectMapper();
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.