Configuring ObjectMapper in Spring

前端 未结 12 1705
迷失自我
迷失自我 2020-11-22 10:46

my goal is to configure the objectMapper in the way that it only serialises element which are annotated with @JsonProperty.

In order to do

相关标签:
12条回答
  • 2020-11-22 11:12

    I've used this with Jackson 2.x and Spring 3.1.2+

    servlet-context.xml:

    Note that the root element is <beans:beans>, so you may need to remove beans and add mvc to some of these elements depending on your setup.

        <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;
            }
        }
    
    }
    
    0 讨论(0)
  • 2020-11-22 11:18

    I am using Spring 3.2.4 and Jackson FasterXML 2.1.1.

    I have created a custom JacksonObjectMapper that works with explicit annotations for each attribute of the Objects mapped:

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

    Then this is instantiated in the context-configuration (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>
    

    This works fine!

    0 讨论(0)
  • 2020-11-22 11:19

    Above Spring 4, there is no need to configure MappingJacksonHttpMessageConverter if you only intend to configure ObjectMapper.

    (configure MappingJacksonHttpMessageConverter will cause you to lose other MessageConverter)

    You just need to do:

    public class MyObjectMapper extends ObjectMapper {
    
        private static final long serialVersionUID = 4219938065516862637L;
    
        public MyObjectMapper() {
            super();
            enable(SerializationFeature.INDENT_OUTPUT);
        }       
    }
    

    And in your Spring configuration, create this bean:

    @Bean 
    public MyObjectMapper myObjectMapper() {        
        return new MyObjectMapper();
    }
    
    0 讨论(0)
  • 2020-11-22 11:20

    I am using Spring 4.1.6 and 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>
    

    this works at my applicationContext.xml configration

    0 讨论(0)
  • 2020-11-22 11:21

    SOLUTION 1

    First working solution (tested) useful especially when using @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);
            });
        }
    

    SOLUTION 2

    Of course the common approach below works too (also working with @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));
        }
    

    Why @EnableWebMvc usage is a problem?

    @EnableWebMvc is using DelegatingWebMvcConfiguration which extends WebMvcConfigurationSupport which does this:

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

    which means that there's no way of injecting your own ObjectMapper with the purpose of preparing it to be used for creating the default MappingJackson2HttpMessageConverter when using @EnableWebMvc.

    0 讨论(0)
  • 2020-11-22 11:25

    Using Spring Boot (1.2.4) and Jackson (2.4.6) the following annotation based configuration worked for me.

    @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;
        }
    }
    
    0 讨论(0)
提交回复
热议问题