Spring에서 ObjectMapper 구성


91

내 목표는 objectMapper주석이 달린 요소 만 직렬화 하도록 구성 하는 것입니다 @JsonProperty.

이를 위해 objectmapper를 구성하는 방법을 설명 하는 이 설명 을 따랐습니다.

여기에 설명 된대로 사용자 정의 objectmapper를 포함했습니다 .

그러나 클래스 NumbersOfNewEvents가 직렬화 되면 여전히 json의 모든 속성이 포함됩니다.

아무도 힌트가 있습니까? 미리 감사드립니다

Jackson 1.8.0 봄 3.0.5

CustomObjectMapper

public class CompanyObjectMapper extends ObjectMapper {
    public CompanyObjectMapper() {
        super();
        setVisibilityChecker(getSerializationConfig()
                .getDefaultVisibilityChecker()
                .withCreatorVisibility(JsonAutoDetect.Visibility.NONE)
                .withFieldVisibility(JsonAutoDetect.Visibility.NONE)
                .withGetterVisibility(JsonAutoDetect.Visibility.NONE)
                .withIsGetterVisibility(JsonAutoDetect.Visibility.NONE)
                .withSetterVisibility(JsonAutoDetect.Visibility.DEFAULT));
    }
}

servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <context:component-scan base-package="de.Company.backend.web" />

    <mvc:annotation-driven />

    <bean
        class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
                    <property name="objectMapper" ref="jacksonObjectMapper" />
                </bean>
            </list>
        </property>
    </bean>

    <bean id="jacksonObjectMapper" class="de.Company.backend.web.CompanyObjectMapper" />
</beans>

NumbersOfNewEvents

public class NumbersOfNewEvents implements StatusAttribute {

    public Integer newAccepts;
    public Integer openRequests;

    public NumbersOfNewEvents() {
        super();
    }
}

답변:


136

Spring Boot (1.2.4)와 Jackson (2.4.6)을 사용하면 다음 주석 기반 구성이 저에게 효과적이었습니다.

@Configuration
public class JacksonConfiguration {

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, true);

        return mapper;
    }
}

3
Spring은 application.properties에서 Jackson의 일부 속성을 사용자 정의 할 수 있도록 지원합니다. docs.spring.io/spring-boot/docs/current/reference/html/…
NangSaigon

10
얘들 아. Java config에서 objectMapper라는 이름으로 bean을 선언하면 예제에서 보듯이이 bean은 Spring Boot에서 무시되어 \ @를 배치해도 해당 이름의 bean이 시스템에 이미 등록되어있는 문제에 직면했습니다. 그것에 대한 기본 주석. 이 문제를 해결하려면 다른 이름 (예 : jsonObjectMapper)으로 bean을 등록하고 \ @Primary 주석으로 표시해야합니다.
Demwis

Spring Boot를 사용 하지 않는 경우 내 대답을 참조하십시오 .
Dormouse

질문 : 클래스 이름을 지정해야 JacksonConfiguration합니까? 이 클래스를 Jackson의 구성 클래스로 사용하도록 Spring Boot에 지시하는 자동 방법입니다.
Marco Sulla

또한 사용할 때 정말 작동 @EnableWebMvc합니까? 내 대답 에서 볼 수 있기 때문에 의심 스럽습니다 . 왜 @EnableWebMvc 사용이 문제입니까?
adrhc

25

내가 Spring 3.1을 사용하고 있기 때문일 수 있지만 (Spring 3.0.5 대신) Steve Eastwood의 대답이 나를 위해 작동하지 않았습니다. 이 솔루션은 Spring 3.1에서 작동합니다.

스프링 XML 컨텍스트에서 :

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
        <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
        <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
            <property name="objectMapper" ref="jacksonObjectMapper" />
        </bean>        
    </mvc:message-converters>
</mvc:annotation-driven>

<bean id="jacksonObjectMapper" class="de.Company.backend.web.CompanyObjectMapper" />

이 봄 3.1 잭슨 2.X를 사용하기위한 도움이 stackoverflow.com/questions/10420040/...
아람 Kocharyan

유능한! Spring 3.0에서 3.2로 업그레이드 할 때 내 사용자 정의 ObjectMapper를 등록하는 데이 접근 방식을 채택해야했습니다. 이전에 MappingJacksonJsonView 빈을 정의 할 때 objectMapper 속성을 설정했지만 더 이상 작동하지 않았습니다. 이것은 Jackson 1.7
David Easley

20

org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean오랜 시간 동안. Spring Boot 1.2 릴리스부터 org.springframework.http.converter.json.Jackson2ObjectMapperBuilderJava Config 용이 있습니다.

String Boot 구성은 다음과 같이 간단 할 수 있습니다.

spring.jackson.deserialization.<feature_name>=true|false
spring.jackson.generator.<feature_name>=true|false
spring.jackson.mapper.<feature_name>=true|false
spring.jackson.parser.<feature_name>=true|false
spring.jackson.serialization.<feature_name>=true|false
spring.jackson.default-property-inclusion=always|non_null|non_absent|non_default|non_empty

에서 classpath:application.properties또는 일부 자바 코드 @Configuration클래스 :

@Bean
public Jackson2ObjectMapperBuilder jacksonBuilder() {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    builder.indentOutput(true).dateFormat(new SimpleDateFormat("yyyy-MM-dd"));
    return builder;
}

보다:


2
이것은 대부분의 사용 사례에서 작동하지만 @EnableWebMvc 주석을 사용하는 경우 Spring Boot jackson 구성이 무시됩니다 (Spring Boot 2.0.3에서 테스트 됨).
John

1
테스트하지는 않았지만 @EnableWebMvc에서 작동하지 않을 것이라고 확신합니다 (스프링 부팅을 사용하거나 사용하지 않더라도). 왜? (DelegatingWebMvcConfiguration가 WebMvcConfigurationSupport를 확장) WebMvcConfigurationSupport를 참조하십시오 Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json().
adrhc

16

나는 이것을 Jackson 2.x 및 Spring 3.1.2+에서 사용했습니다.

servlet-context.xml :

루트 요소는 <beans:beans>이므로 설정에 따라 이러한 요소 중 일부 를 제거 beans하고 추가 해야 할 수 있습니다 mvc.

    <annotation-driven>
        <message-converters>
            <beans:bean
                class="org.springframework.http.converter.StringHttpMessageConverter" />
            <beans:bean
                class="org.springframework.http.converter.ResourceHttpMessageConverter" />
            <beans:bean
                class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <beans:property name="objectMapper" ref="jacksonObjectMapper" />
            </beans:bean>
        </message-converters>
    </annotation-driven>

    <beans:bean id="jacksonObjectMapper"
        class="au.edu.unimelb.atcom.transfer.json.mappers.JSONMapper" />

au.edu.unimelb.atcom.transfer.json.mappers.JSONMapper.java :

public class JSONMapper extends ObjectMapper {

    public JSONMapper() {
        SimpleModule module = new SimpleModule("JSONModule", new Version(2, 0, 0, null, null, null));
        module.addSerializer(Date.class, new DateSerializer());
        module.addDeserializer(Date.class, new DateDeserializer());
        // Add more here ...
        registerModule(module);
    }

}

DateSerializer.java :

public class DateSerializer extends StdSerializer<Date> {

    public DateSerializer() {
        super(Date.class);
    }

    @Override
    public void serialize(Date date, JsonGenerator json,
            SerializerProvider provider) throws IOException,
            JsonGenerationException {
        // The client side will handle presentation, we just want it accurate
        DateFormat df = StdDateFormat.getBlueprintISO8601Format();
        String out = df.format(date);
        json.writeString(out);
    }

}

DateDeserializer.java :

public class DateDeserializer extends StdDeserializer<Date> {

    public DateDeserializer() {
        super(Date.class);
    }

    @Override
    public Date deserialize(JsonParser json, DeserializationContext context)
            throws IOException, JsonProcessingException {
        try {
            DateFormat df = StdDateFormat.getBlueprintISO8601Format();
            return df.parse(json.getText());
        } catch (ParseException e) {
            return null;
        }
    }

}

10

이제 https://github.com/FasterXML/jackson-module-hibernate를 기반으로 솔루션을 찾았습니다.

객체 매퍼를 확장하고 상속 된 생성자에 속성을 추가했습니다.

그런 다음 새 개체 매퍼가 빈으로 등록됩니다.

<!-- https://github.com/FasterXML/jackson-module-hibernate -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
        <array>
            <bean id="jsonConverter"
            class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
                <property name="objectMapper">
                    <bean class="de.company.backend.spring.PtxObjectMapper"/>
                </property>
            </bean>
        </array>
    </property>
</bean>   

솔루션에 대단히 감사합니다! 나는 <annotation-driven>에 대해 4 시간 이상을 보냈지 만 단순히 변환기를 선택하지 않았습니다. 답변을 시도했지만 마침내 작동합니다!
snowindy 2013

1
주석을 사용하려면 및로 확장 ObjectMapper되는 사용자 정의 매퍼에 주석을 달 수 있습니다 . 이것은 Spring Reference Guide에서 권장하는 접근 방식이며 저에게 잘 작동했습니다. @Component@Primary
OlgaMaciaszek 2015

9

사용자 지정 serializer를 등록하기 위해 사용자 지정 ObjectMapper를 추가하려면 내 대답을 시도하십시오.

필자의 경우 (Spring 3.2.4 및 Jackson 2.3.1) 사용자 지정 serializer에 대한 XML 구성 :

<mvc:annotation-driven>
    <mvc:message-converters register-defaults="false">
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper">
                <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                    <property name="serializers">
                        <array>
                            <bean class="com.example.business.serializer.json.CustomObjectSerializer"/>
                        </array>
                    </property>
                </bean>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

설명 할 수없는 방식으로 무언가에 의해 기본값으로 다시 덮어 쓰기되었습니다.

이것은 나를 위해 일했습니다.

CustomObject.java

@JsonSerialize(using = CustomObjectSerializer.class)
public class CustomObject {

    private Long value;

    public Long getValue() {
        return value;
    }

    public void setValue(Long value) {
        this.value = value;
    }
}

CustomObjectSerializer.java

public class CustomObjectSerializer extends JsonSerializer<CustomObject> {

    @Override
    public void serialize(CustomObject value, JsonGenerator jgen,
        SerializerProvider provider) throws IOException,JsonProcessingException {
        jgen.writeStartObject();
        jgen.writeNumberField("y", value.getValue());
        jgen.writeEndObject();
    }

    @Override
    public Class<CustomObject> handledType() {
        return CustomObject.class;
    }
}

<mvc:message-converters>(...)</mvc:message-converters>내 솔루션에는 XML 구성 ( )이 필요하지 않습니다.


6

Spring 4.1.6과 Jackson FasterXML 2.1.4를 사용하고 있습니다.

    <mvc:annotation-driven>
        <mvc:message-converters>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper">
                    <bean class="com.fasterxml.jackson.databind.ObjectMapper">
                        <!-- 设置不输出null字段-->
                        <property name="serializationInclusion" value="NON_NULL"/>
                    </bean>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

이것은 내 applicationContext.xml 구성에서 작동합니다.


6

해결 방법 1

특히 @EnableWebMvc를 사용할 때 유용한 첫 번째 작업 솔루션 (테스트 됨) :

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private ObjectMapper objectMapper;// created elsewhere
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        // this won't add a 2nd MappingJackson2HttpMessageConverter 
        // as the SOLUTION 2 is doing but also might seem complicated
        converters.stream().filter(c -> c instanceof MappingJackson2HttpMessageConverter).forEach(c -> {
            // check default included objectMapper._registeredModuleTypes,
            // e.g. Jdk8Module, JavaTimeModule when creating the ObjectMapper
            // without Jackson2ObjectMapperBuilder
            ((MappingJackson2HttpMessageConverter) c).setObjectMapper(this.objectMapper);
        });
    }

해결 방법 2

물론 아래의 일반적인 접근 방식도 작동합니다 (@EnableWebMvc에서도 작동).

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private ObjectMapper objectMapper;// created elsewhere
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        // this will add a 2nd MappingJackson2HttpMessageConverter 
        // (additional to the default one) but will work and you 
        // won't lose the default converters as you'll do when overwriting
        // configureMessageConverters(List<HttpMessageConverter<?>> converters)
        // 
        // you still have to check default included
        // objectMapper._registeredModuleTypes, e.g.
        // Jdk8Module, JavaTimeModule when creating the ObjectMapper
        // without Jackson2ObjectMapperBuilder
        converters.add(new MappingJackson2HttpMessageConverter(this.objectMapper));
    }

@EnableWebMvc 사용이 문제인 이유는 무엇입니까?

@EnableWebMvc는 다음을 수행 DelegatingWebMvcConfiguration하는 확장 WebMvcConfigurationSupport을 사용 합니다.

if (jackson2Present) {
    Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
    if (this.applicationContext != null) {
        builder.applicationContext(this.applicationContext);
    }
    messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}

이는 @EnableWebMvc를 사용할 때 ObjectMapper기본값을 만드는 데 사용할 준비를 할 목적으로 자신을 주입 할 방법이 없음을 의미합니다 MappingJackson2HttpMessageConverter.


큰! 실제로 spring-data-rest-webmvc : 3.2.3의 일부인 RepositoryRestMvcConfiguration은 Spring에서 만든 ObjectMapper를 사용하지 않으며 모듈이있는 사용자 정의 objectMapper 만 기본적으로 작동하지 않습니다. 첫 번째 접근 방식은 실제이며 spring-data-rest-webmvc에 의해 사용자 정의 된 ObjectMapper를 대체합니다. 감사!
Valtoni Boaventura

EnableWebMvc의 비참한 b / c였던 ObjectMapper를 사용자 정의 할 수없는 문제가있었습니다. 나는 이것을 우연히 발견하게되어 기쁩니다.
Evan White

3

Spring Boot에서는 2.2.x다음과 같이 구성해야합니다.

@Bean
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
    return builder.build()
}

Kotlin :

@Bean
fun objectMapper(builder: Jackson2ObjectMapperBuilder) = builder.build()

2

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

(구성 MappingJacksonHttpMessageConverter하면 다른 MessageConverter를 잃게됩니다)

다음을 수행하면됩니다.

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

작동하지 않음 - - customObjectMapper : 클래스 패스 리소스에 'customObjectMapper'방법에 의해 정의 된 [COM /의 config.class] -_halObjectMapper: defined in null
Angshuman 아가 왈

1
그리고 이것은 Spring Boot에서만 작동합니다. 평범한 Spring Web이 아닙니다.
Dormouse

2

일반 spring-web에서 메시지 변환기를 구성하려면이 경우 Java 8 JSR-310 JavaTimeModule을 활성화하려면 먼저 클래스 WebMvcConfigurer에서 구현 @Configuration한 다음 configureMessageConverters메서드 를 재정의해야 합니다.

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().modules(new JavaTimeModule(), new Jdk8Module()).build()
            .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    converters.add(new MappingJackson2HttpMessageConverter(objectMapper));
}

이와 같이 ObjectMapperJava 기반 Spring 구성에 정의 된 모든 사용자 정의 를 등록 할 수 있습니다.


Spring Boot를 통해 ObjectMapper를 주입하고 구성하는 것을 선호합니다.
Constantino Cronemberger

1
물론, Spring Boot를 사용한다면. 이것은 Spring Boot 질문이 아닙니다.
Dormouse

예, Spring Web을 Spring Boot와 함께 사용할 때 Spring Boot에서 제공하는 ObjectMapper를 사용하지 않는다는 점에 주목하는 것이 흥미 롭습니다. 이것이 제가이 질문에 도움이 된 이유입니다.
Constantino Cronemberger

이렇게하면 모든 기본 메시지 변환기가 지워집니다! 아무도 이것을 원하지 않는다고 확신합니다. 솔루션에 대한 내 대답 을 참조하십시오 .
adrhc

메시지 변환기를 확장하고 싶다면 올바른 해결책은 Spring 문서에extendMessageConverters 따라 재정의하는 것 입니다. 하지만 사용자 정의 된 . MappingJackson2HttpMessageConverter
Dormouse

1

Spring 3.2.4와 Jackson FasterXML 2.1.1을 사용하고 있습니다.

매핑 된 개체의 각 속성에 대한 명시 적 주석과 함께 작동 하는 사용자 지정 JacksonObjectMapper 를 만들었습니다 .

package com.test;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

public class MyJaxbJacksonObjectMapper extends ObjectMapper {

public MyJaxbJacksonObjectMapper() {

    this.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
            .setVisibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.ANY)
            .setVisibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE)
            .setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE)
            .setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE);

    this.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
    }
}

그런 다음 컨텍스트 구성 ( servlet-context.xml ) 에서 인스턴스화됩니다 .

<mvc:annotation-driven>
    <mvc:message-converters>

        <beans:bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <beans:property name="objectMapper">
                <beans:bean class="com.test.MyJaxbJacksonObjectMapper" />
            </beans:property>
        </beans:bean>

    </mvc:message-converters>
</mvc:annotation-driven>

이것은 잘 작동합니다!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.