การกำหนดค่า ObjectMapper ใน Spring


95

เป้าหมายของฉันคือการกำหนดค่าobjectMapperในทางที่มัน serialises @JsonPropertyองค์ประกอบซึ่งมีคำอธิบายประกอบกับ

ในการดำเนินการดังกล่าวฉันทำตามคำอธิบายนี้ซึ่งระบุวิธีกำหนดค่า objectmapper

ผมรวม objectmapper ที่กำหนดเองตามที่อธิบายไว้ที่นี่

อย่างไรก็ตามเมื่อคลาสNumbersOfNewEventsถูกทำให้เป็นอนุกรมมันยังคงมีแอตทริบิวต์ทั้งหมดใน json

ใครมีคำใบ้? ขอบคุณล่วงหน้า

แจ็คสัน 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();
    }
}

คำตอบ:


140

การใช้ 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 รองรับการปรับแต่งคุณสมบัติบางอย่างของ Jackson ใน application.properties: docs.spring.io/spring-boot/docs/current/reference/html/…
NangSaigon

10
ไงพวก. ฉันประสบปัญหาเมื่อคุณประกาศ bean ด้วยชื่อ objectMapper ใน java config เช่นเดียวกับที่แสดงในตัวอย่าง Spring Boot ไม่สนใจ bean นี้ทำให้ bean ที่มีชื่อดังกล่าวถูกลงทะเบียนในระบบแล้วแม้ว่าคุณจะวาง \ @ คำอธิบายประกอบหลักอยู่ ในการแก้ไขปัญหานี้คุณต้องลงทะเบียน bean ด้วยชื่ออื่นเช่น jsonObjectMapper และทำเครื่องหมายด้วย \ @Primary annotation
Demwis

โปรดอ้างอิงคำตอบของฉันหากคุณไม่ได้ใช้ Spring Boot
Dormouse

คำถาม: คุณต้องตั้งชื่อชั้นเรียนJacksonConfiguration? เป็นวิธีอัตโนมัติในการสั่งให้ Spring Boot ใช้คลาสนี้เป็นคลาสกำหนดค่าสำหรับ Jackson?
Marco Sulla

มันใช้งานได้จริง@EnableWebMvcหรือไม่เมื่อใช้ด้วย? ฉันสงสัยเพราะ ... ดูในคำตอบของฉัน : ทำไมการใช้งาน @EnableWebMvc จึงมีปัญหา
adrhc

26

อาจเป็นเพราะฉันใช้ 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" />

สิ่งนี้ช่วยในการใช้ Jackson 2.x กับ Spring 3.1: stackoverflow.com/questions/10420040/…
Aram Kocharyan

มีประโยชน์! ต้องใช้แนวทางนี้ในการลงทะเบียน ObjectMapper ที่กำหนดเองของฉันในการอัปเกรดจาก Spring 3.0 เป็น 3.2 ก่อนหน้านี้เคยตั้งค่าคุณสมบัติ objectMapper เมื่อกำหนด MappingJacksonJsonView bean แต่ใช้งานไม่ได้อีกต่อไป นี่คือของ Jackson 1.7
David Easley

20

มีorg.springframework.http.converter.json.Jackson2ObjectMapperFactoryBeanมาช้านาน. Spring Boot ตั้งแต่ 1.2 รีลีสมีorg.springframework.http.converter.json.Jackson2ObjectMapperBuilderสำหรับ Java 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หรือโค้ด Java ใน@Configurationคลาส:

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

ดู:


2
วิธีนี้ใช้ได้กับกรณีการใช้งานส่วนใหญ่อย่างไรก็ตามการกำหนดค่า Spring Boot jackson จะถูกละเว้นหากคุณใช้คำอธิบายประกอบ @EnableWebMvc (ทดสอบใน Spring Boot 2.0.3)
จอห์น

1
แม้ว่าฉันจะไม่ได้ทดสอบ แต่ฉันแน่ใจว่าจะใช้ไม่ได้กับ @EnableWebMvc (แม้ว่าจะใช้หรือไม่ใช้สปริงบูตก็ตาม) ทำไม? ดู WebMvcConfigurationSupport (DelegatingWebMvcConfiguration ขยาย Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json()WebMvcConfigurationSupport):
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>มันก็ไม่ได้รับตัวแปลง ลองคำตอบของคุณในที่สุดก็ได้ผล!
snowindy

1
ที่จะใช้คำอธิบายประกอบคุณก็สามารถใส่คำอธิบายประกอบ Mapper กำหนดเองของคุณที่ขยายObjectMapperเป็นและ@Component @Primaryนี่เป็นแนวทางที่แนะนำในคู่มืออ้างอิงฤดูใบไม้ผลิและใช้ได้ผลดีสำหรับฉัน
OlgaMaciaszek

9

หากคุณต้องการเพิ่ม ObjectMapper ที่กำหนดเองสำหรับการลงทะเบียนซีเรียลไลเซอร์แบบกำหนดเองลองคำตอบของฉัน

ในกรณีของฉัน (Spring 3.2.4 และ Jackson 2.3.1) การกำหนดค่า XML สำหรับ serializer แบบกำหนดเอง:

<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 ( ) ในโซลูชันของฉัน


7

แนวทางแก้ไข 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()));
}

ซึ่งหมายความว่าไม่มีวิธีการฉีดของคุณเองObjectMapperโดยมีจุดประสงค์เพื่อเตรียมใช้สำหรับสร้างค่าเริ่มต้นMappingJackson2HttpMessageConverterเมื่อใช้ @EnableWebMvc


เยี่ยมมาก! จริงๆแล้ว RepositoryRestMvcConfiguration ส่วนหนึ่งของ spring-data-rest-webmvc: 3.2.3 ไม่ใช้ ObjectMapper ที่สร้างโดย Spring และมีเพียง objectMapper ที่กำหนดเองที่มีโมดูลเท่านั้นที่ไม่สามารถใช้งานได้ทันที แนวทางแรกเป็นจริงและแทนที่ ObjectMapper ที่กำหนดเองโดย spring-data-rest-webmvc ขอบคุณ!
Valtoni Boaventura

ฉันมีปัญหาที่ฉันไม่สามารถปรับแต่ง ObjectMapper ของฉันซึ่งเป็น b / c ที่น่าสังเวชของ EnableWebMvc ดีใจมากที่ฉันเจอสิ่งนี้
Evan White

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 ของฉัน


4

ในการกำหนดค่าตัวแปลงข้อความในสปริงเว็บธรรมดาในกรณีนี้เพื่อเปิดใช้งาน 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));
}

ด้วยวิธีนี้คุณสามารถลงทะเบียนที่กำหนดเองใด ๆ ที่กำหนดไว้ObjectMapperในการกำหนดค่า Spring ที่ใช้ Java


ฉันต้องการให้ ObjectMapper ฉีดและกำหนดค่าผ่าน Spring Boot
Constantino Cronemberger

1
แน่นอนว่าถ้าคุณใช้ Spring Boot นี่ไม่ใช่คำถาม Spring Boot
Dormouse

ใช่น่าสนใจที่จะสังเกตว่าเมื่อใช้ Spring Web กับ Spring Boot มันไม่ได้ใช้ ObjectMapper ที่ Spring Boot ให้มาและนั่นคือเหตุผลที่ฉันจบลงด้วยคำถามนี้ซึ่งช่วยฉันได้
Constantino Cronemberger

สิ่งนี้จะล้างตัวแปลงข้อความเริ่มต้นทั้งหมด! ฉันค่อนข้างมั่นใจว่าไม่มีใครต้องการสิ่งนี้ ดูคำตอบของฉันสำหรับวิธีแก้ปัญหา
adrhc

ดีถ้าคุณต้องการที่จะขยายการแปลงข้อความวิธีที่ถูกต้องก็จะไปแทนที่extendMessageConvertersตามเอกสารฤดูใบไม้ผลิ แต่ฉันไม่ได้มีความจำเป็นสำหรับการใด ๆ MappingJackson2HttpMessageConverterเพราะผมก็ต้องมีการปรับแต่ง
Dormouse

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 นี้:

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

ไม่ทำงาน - - customObjectMapper: กำหนดโดยเมธอด 'customObjectMapper' ในทรัพยากรพา ธ คลาส [com / Config.class] -_halObjectMapper: defined in null
Angshuman Agarwal

1
และจะใช้ได้กับ Spring Boot เท่านั้น ไม่ใช่ Spring Web ธรรมดา
Dormouse

1

ฉันใช้ Spring 3.2.4 และ Jackson FasterXML 2.1.1

ฉันได้สร้างJacksonObjectMapper แบบกำหนดเองที่ทำงานร่วมกับคำอธิบายประกอบที่ชัดเจนสำหรับแต่ละแอตทริบิวต์ของ Objects ที่แมป:

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.