Cấu hình ObjectMapper trong Spring


91

mục tiêu của tôi là định cấu hình objectMappertheo cách mà nó chỉ tuần tự hóa phần tử được chú thích @JsonProperty.

Để làm như vậy, tôi đã làm theo lời giải thích này cho biết cách cấu hình objectmapper.

Tôi đã bao gồm objectmapper tùy chỉnh như được mô tả ở đây .

Tuy nhiên khi lớp NumbersOfNewEventsđược tuần tự hóa nó vẫn chứa tất cả các thuộc tính trong json.

Có ai có một gợi ý? Cảm ơn trước

Jackson 1.8.0 mùa xuân 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();
    }
}

Câu trả lời:


135

Sử dụng Spring Boot (1.2.4) và Jackson (2.4.6), cấu hình dựa trên chú thích sau đây phù hợp với tôi.

@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 hỗ trợ tùy chỉnh một số thuộc tính của Jackson trong application.properties: docs.spring.io/spring-boot/docs/current/reference/html/…
NangSaigon 18/02/17

10
Này các cậu. Tôi gặp phải một vấn đề là khi bạn khai báo bean với tên objectMapper trong java config, giống như nó được hiển thị trong ví dụ, bean này bị Spring Boot bỏ qua, vì bean có tên như vậy đã được đăng ký trong hệ thống, ngay cả khi bạn đặt \ @ Chú thích chính về nó. Để khắc phục sự cố này, bạn cần đăng ký bean với tên khác, ví dụ: jsonObjectMapper và đánh dấu nó bằng \ @Primary annotation
Demwis

Vui lòng tham khảo câu trả lời của tôi nếu bạn không sử dụng Spring Boot.
Dormouse

Một câu hỏi: bạn phải đặt tên cho lớp JacksonConfiguration? Đó là một cách tự động để hướng dẫn Spring Boot sử dụng lớp này làm lớp cấu hình cho Jackson?
Marco Sulla,

Nó có thực sự hoạt động khi sử dụng @EnableWebMvckhông? Tôi nghi ngờ vì ... hãy xem trong câu trả lời của tôi : Tại sao việc sử dụng @EnableWebMvc là một vấn đề?
adrhc

25

Có thể là do tôi đang sử dụng Spring 3.1 (thay vì Spring 3.0.5 như câu hỏi của bạn đã chỉ định), nhưng câu trả lời của Steve Eastwood không phù hợp với tôi. Giải pháp này hoạt động cho Spring 3.1:

Trong bối cảnh xml mùa xuân của bạn:

<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" />

Điều này đã giúp cho việc sử dụng Jackson 2.x với Spring 3.1: stackoverflow.com/questions/10420040/...
Aram Kocharyan

Hữu ích! Phải áp dụng cách tiếp cận này để đăng ký ObjectMapper tùy chỉnh của tôi khi nâng cấp từ Spring 3.0 lên 3.2. Trước đây đã đặt thuộc tính objectMapper khi xác định bean MappingJacksonJsonView, nhưng điều đó không còn hoạt động nữa. Đây là với Jackson 1,7
David Easley

20

org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBeantrong một thời gian dài. Bắt đầu từ phiên bản 1.2 của Spring Boot, có org.springframework.http.converter.json.Jackson2ObjectMapperBuildercho Java Config.

Cấu hình trong String Boot có thể đơn giản như sau:

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

trong classpath:application.propertieshoặc một số mã Java trong @Configurationlớp:

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

Xem:


2
Điều này hoạt động cho hầu hết các trường hợp sử dụng, tuy nhiên cấu hình jackson Spring Boot bị bỏ qua nếu bạn đang sử dụng chú thích @EnableWebMvc (được thử nghiệm trong Spring Boot 2.0.3).
John

1
Mặc dù tôi đã không kiểm tra, tôi chắc chắn rằng điều đó sẽ không hoạt động với @EnableWebMvc (mặc dù sử dụng hoặc không khởi động mùa xuân). Tại sao? thấy WebMvcConfigurationSupport (DelegatingWebMvcConfiguration kéo dài WebMvcConfigurationSupport): Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json().
adrhc

16

Tôi đã sử dụng cái này với Jackson 2.x và Spring 3.1.2+

servlet-context.xml:

Lưu ý rằng phần tử gốc là <beans:beans>, vì vậy bạn có thể cần phải xóa beansvà thêm mvcvào một số phần tử này tùy thuộc vào thiết lập của bạn.

    <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

Tôi đã tìm thấy giải pháp hiện dựa trên https://github.com/FasterXML/jackson-module-hibernate

Tôi đã mở rộng trình ánh xạ đối tượng và thêm các thuộc tính trong hàm tạo kế thừa.

Sau đó, trình ánh xạ đối tượng mới được đăng ký dưới dạng bean.

<!-- 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>   

Cảm ơn bạn rất nhiều về giải pháp! Tôi đã dành hơn bốn giờ để tìm hiểu về <annotation-driven> , nó chỉ đơn giản là không nhận được các bộ chuyển đổi. Đã thử câu trả lời của bạn, cuối cùng nó hoạt động!
snowindy

1
Để sử dụng chú thích, bạn có thể chỉ cần chú thích Người vẽ bản đồ tùy chỉnh của mình mở rộng ObjectMappernhư @Component@Primary. Đây là cách tiếp cận được đề xuất trong Hướng dẫn tham khảo mùa xuân và nó đã hoạt động tốt đối với tôi.
OlgaMaciaszek

9

Nếu bạn muốn thêm ObjectMapper tùy chỉnh để đăng ký bộ tuần tự hóa tùy chỉnh, hãy thử câu trả lời của tôi.

Trong trường hợp của tôi (Spring 3.2.4 và Jackson 2.3.1), cấu hình XML cho bộ tuần tự hóa tùy chỉnh:

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

theo cách không giải thích được bị ghi đè trở lại mặc định bởi một thứ gì đó.

Điều này đã làm việc cho tôi:

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

Không cần cấu hình XML ( <mvc:message-converters>(...)</mvc:message-converters>) trong giải pháp của tôi.


6

Tôi đang sử dụng Spring 4.1.6 và 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>

điều này hoạt động ở cấu hình applicationContext.xml của tôi


6

GIẢI PHÁP 1

Giải pháp làm việc đầu tiên (đã được thử nghiệm) hữu ích đặc biệt khi sử dụng @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);
        });
    }

GIẢI PHÁP 2

Tất nhiên, phương pháp phổ biến bên dưới cũng hoạt động (cũng hoạt động với @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));
    }

Tại sao việc sử dụng @EnableWebMvc là một vấn đề?

@EnableWebMvc đang sử dụng DelegatingWebMvcConfigurationmở rộng WebMvcConfigurationSupportthực hiện điều này:

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

điều đó có nghĩa là không có cách nào để chèn ObjectMappertệp của riêng bạn với mục đích chuẩn bị nó được sử dụng để tạo mặc định MappingJackson2HttpMessageConverterkhi sử dụng @EnableWebMvc.


Tuyệt quá! Trên thực tế RepositoryRestMvcConfiguration, một phần của spring-data-rest-webmvc: 3.2.3 không sử dụng ObjectMapper do Spring tạo ra và chỉ objectMapper tùy chỉnh với các mô-đun không hoạt động ngoài hộp. Cách tiếp cận đầu tiên là thực tế và thay thế ObjectMapper được tùy chỉnh bởi spring-data-rest-webmvc. Cảm ơn!
Valtoni Boaventura

Tôi đã gặp sự cố trong đó tôi không thể tùy chỉnh ObjectMapper của mình. Điều này đã làm hỏng b / c của EnableWebMvc. Rất vui vì tôi đã tình cờ biết được điều này.
Evan White

3

Trong Spring Boot, 2.2.xbạn cần cấu hình nó như sau:

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

Kotlin:

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

2

Trên Spring 4, không cần cấu hình MappingJacksonHttpMessageConverternếu bạn chỉ định cấu hình ObjectMapper.

(cấu hình MappingJacksonHttpMessageConvertersẽ khiến bạn mất MessageConverter khác)

Bạn chỉ cần làm:

public class MyObjectMapper extends ObjectMapper {

    private static final long serialVersionUID = 4219938065516862637L;

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

Và trong cấu hình Spring của bạn, hãy tạo bean này:

@Bean 
public MyObjectMapper myObjectMapper() {        
    return new MyObjectMapper();
}

Không làm việc - - customObjectMapper: xác định bằng phương pháp 'customObjectMapper' trong tài nguyên đường dẫn lớp [com / Config.class] -_halObjectMapper: defined in null
Angshuman Agarwal

1
Và điều này sẽ chỉ hoạt động với Spring Boot. Không phải Spring Web đơn giản.
ngủ tập thể

2

Để định cấu hình trình chuyển đổi tin nhắn trong spring-web thuần túy, trong trường hợp này để kích hoạt JavaTimeModule Java 8 JSR-310, trước tiên bạn cần triển khai WebMvcConfigurertrong @Configurationlớp của mình và sau đó ghi đè configureMessageConvertersphương thức:

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

Như vậy, bạn có thể đăng ký bất kỳ tùy chỉnh nào được xác định ObjectMappertrong cấu hình Spring dựa trên Java.


Tôi muốn có ObjectMapper được tiêm và cấu hình thông qua Spring Boot.
Constantino Cronemberger

1
Chắc chắn, nếu bạn sử dụng Spring Boot. Đây không phải là một câu hỏi Spring Boot.
Dormouse

Có, thú vị khi nhận thấy rằng khi sử dụng Spring Web với Spring Boot, nó không sử dụng ObjectMapper được cung cấp bởi Spring Boot và đó là lý do tại sao tôi đã kết thúc câu hỏi này.
Constantino Cronemberger

Điều này sẽ xóa tất cả các trình chuyển đổi thông báo mặc định! Tôi khá chắc rằng không ai muốn điều này. Xem câu trả lời của tôi để biết giải pháp.
adrhc

Nếu bạn muốn mở rộng trình chuyển đổi thông báo, giải pháp chính xác sẽ là ghi đè extendMessageConverters, theo tài liệu Spring . Nhưng tôi không có nhu cầu về nó, bởi vì tôi chỉ cần một tùy chỉnh MappingJackson2HttpMessageConverter.
túc xá

1

Tôi đang sử dụng Spring 3.2.4 và Jackson FasterXML 2.1.1.

Tôi đã tạo một JacksonObjectMapper tùy chỉnh hoạt động với các chú thích rõ ràng cho từng thuộc tính của Đối tượng được ánh xạ:

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

Sau đó, điều này được khởi tạo trong cấu hình ngữ cảnh ( 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>

Điều này hoạt động tốt!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.