İlkbaharda ObjectMapper'ı Yapılandırma


91

Amacım, objectMapperyalnızca ek açıklamalı öğeyi serileştirecek şekilde yapılandırmaktır @JsonProperty.

Bunu yapmak için , nesne eşleştiricisinin nasıl yapılandırılacağını anlatan bu açıklamayı takip ettim.

Özel nesne eşleştiriciyi burada açıklandığı gibi ekledim .

Ancak sınıf NumbersOfNewEventsserileştirildiğinde json'daki tüm öznitelikleri içerir.

Bir ipucu olan var mı? Şimdiden teşekkürler

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

Yanıtlar:


136

Spring Boot (1.2.4) ve Jackson (2.4.6) kullanarak aşağıdaki açıklama tabanlı yapılandırma benim için çalıştı.

@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'ın bazı özelliklerini application.properties'de özelleştirmeyi destekler: docs.spring.io/spring-boot/docs/current/reference/html/…
NangSaigon

10
Hey Millet. Java yapılandırmasında objectMapper isimli bean'i ilan ettiğinizde, aynı örnekte gösterildiği gibi, bu bean Spring Boot tarafından göz ardı edilir, çünkü bu isimle bean sistemde zaten kayıtlı, \ @ yerleştirseniz bile Üzerine birincil açıklama. Bu sorunu çözmek için, bean'ı farklı bir adla kaydetmeniz gerekir, örneğin jsonObjectMapper ve onu \ @Primary annotation
Demwis

Bakınız benim cevap size eğer değil İlkbahar Önyükleme kullanarak.
Dormouse

Bir soru: sınıfa isim vermelisiniz JacksonConfiguration? Spring Boot'a bu sınıfı Jackson için yapılandırma sınıfı olarak kullanması talimatını vermenin otomatik bir yolu bu mu?
Marco Sulla

Ayrıca kullanırken gerçekten çalışıyor @EnableWebMvcmu? ... gördüğünüz çünkü şüphe benim cevap : Neden @EnableWebMvc kullanımı bir sorundur?
adrhc

25

Bunun nedeni, Spring 3.1 kullanmam olabilir (sorunuzun belirttiği Bahar 3.0.5 yerine), ancak Steve Eastwood'un cevabı benim için işe yaramadı. Bu çözüm Bahar 3.1 için geçerlidir:

İlkbahar xml bağlamınızda:

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

Bu, Jackson 2.x'i Spring 3.1 ile kullanmaya yardımcı oldu: stackoverflow.com/questions/10420040/…
Aram Kocharyan

İşe yarar! Spring 3.0'dan 3.2'ye yükseltme sırasında özel ObjectMapper'ımı kaydetmek için bu yaklaşımı benimsemeliydim. Daha önce bir MappingJacksonJsonView bean tanımlanırken bir objectMapper özelliği ayarlanıyordu, ancak bu artık çalışmıyordu. Bu Jackson 1.7 ile
David Easley

20

Orada org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBeanuzun süre. Spring Boot'un 1.2 sürümünden itibaren org.springframework.http.converter.json.Jackson2ObjectMapperBuilderJava Config için var.

String Boot'da konfigürasyon şu kadar basit olabilir:

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

içinde classpath:application.propertiesveya bazı Java kodu @Configurationsınıfında:

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

Görmek:


2
Bu, çoğu kullanım durumu için işe yarar, ancak @EnableWebMvc ek açıklamasını kullanıyorsanız (Spring Boot 2.0.3'te test edilmiştir) Spring Boot jackson yapılandırması yok sayılır.
John

1
Test etmemiş olsam da, bunun @EnableWebMvc ile çalışmayacağından eminim (yay önyüklemesini kullanıp kullanmamasına rağmen). Neden? (DelegatingWebMvcConfiguration WebMvcConfigurationSupport genişletir) WebMvcConfigurationSupport bkz: Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json().
adrhc

16

Bunu Jackson 2.x ve Spring 3.1.2+ ile kullandım

servlet-context.xml:

Kök öğenin olduğunu unutmayın <beans:beans>, bu nedenle kurulumunuza bağlı olarak bu öğelerden bazılarını kaldırmanız beansve eklemeniz gerekebilir 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

Çözümü şimdi https://github.com/FasterXML/jackson-module-hibernate'e göre buldum

Nesne eşleyicisini genişlettim ve miras alınan kurucuya nitelikleri ekledim.

Daha sonra yeni nesne eşleştiricisi bir fasulye olarak kaydedilir.

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

Çözüm için çok teşekkür ederim! <annotation-driven> etrafında kazarak dört saatten fazla zaman geçirdim , sadece dönüştürücüleri almadı. Cevabınızı denedim, sonunda işe yaradı!
snowindy

1
Ek açıklamaları kullanmak için ObjectMapper, @Componentve olarak genişleyen özel Eşleştiricinize not ekleyebilirsiniz @Primary. Bu, Bahar Referans Kılavuzunda önerilen yaklaşımdır ve benim için iyi çalıştı.
OlgaMaciaszek

9

Özel serileştiricileri kaydetmek için özel ObjectMapper eklemek istiyorsanız, cevabımı deneyin.

Benim durumumda (Spring 3.2.4 ve Jackson 2.3.1), özel serileştirici için XML yapılandırması:

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

açıklanamayan bir şekilde bir şey tarafından varsayılana geri yazılmıştır.

Bu benim için çalıştı:

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

Çözümümde XML yapılandırmasına ( <mvc:message-converters>(...)</mvc:message-converters>) gerek yok .


6

Spring 4.1.6 ve Jackson FasterXML 2.1.4 kullanıyorum.

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

bu benim applicationContext.xml yapılandırmamda çalışıyor


6

ÇÖZÜM 1

Özellikle @EnableWebMvc kullanırken yararlı olan ilk çalışma çözümü (test edilmiştir):

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

ÇÖZÜM 2

Elbette aşağıdaki ortak yaklaşım da işe yarıyor (ayrıca @EnableWebMvc ile çalışmak):

@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 kullanımı neden bir sorundur?

@EnableWebMvc, bunu DelegatingWebMvcConfigurationyapan genişletmeleri kullanıyor WebMvcConfigurationSupport:

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

Bu, @EnableWebMvc kullanırken ObjectMappervarsayılanı oluşturmak için MappingJackson2HttpMessageConverterkullanmak üzere hazırlamak amacıyla kendi başınıza enjekte etmenin bir yolu olmadığı anlamına gelir .


Harika! Aslında, Spring-data-rest-webmvc'nin bir parçası olan RepositoryRestMvcConfiguration: 3.2.3, Spring tarafından oluşturulan ObjectMapper'ı kullanmaz ve yalnızca modülleri olan özel objectMapper kullanıma hazır değildir. İlk yaklaşım gerçektir ve spring-data-rest-webmvc ile özelleştirilmiş ObjectMapper'ın yerini alır. Teşekkürler!
Valtoni Boaventura

EnableWebMvc'den berbat olan ObjectMapper'ımı özelleştiremediğim bir sorunla karşılaştım. Buna rastladığıma çok sevindim.
Evan Beyaz

3

Spring Boot'ta 2.2.xbunu şu şekilde yapılandırmanız gerekir:

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

Kotlin:

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

2

İlkbahar 4'ün üzerinde, MappingJacksonHttpMessageConverteryalnızca yapılandırmayı planlıyorsanız, yapılandırmaya gerek yoktur ObjectMapper.

(yapılandırma MappingJacksonHttpMessageConverter, diğer MessageConverter'ı kaybetmenize neden olur)

Yapmanız gereken tek şey:

public class MyObjectMapper extends ObjectMapper {

    private static final long serialVersionUID = 4219938065516862637L;

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

Ve Bahar konfigürasyonunuzda şu fasulyeyi yaratın:

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

Çalışmıyor - - customObjectMapper: sınıf yolu kaynağındaki 'customObjectMapper' yöntemi tarafından tanımlandı [com / Config.class] -_halObjectMapper: defined in null
Angshuman Agarwal

1
Ve bu sadece Spring Boot ile çalışacaktır. Düz Spring Web değil.
Dormouse

2

Java 8 JSR-310 JavaTimeModule etkinleştirmek için bu durumda, düz yay ağı içerisinde bir mesaj dönüştürücü yapılandırmak için öncelikle ihtiyaç uygulamak WebMvcConfigureriçinde senin@Configuration geçersiz sonra sınıf ve configureMessageConvertersyöntemi:

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

Bunun gibi ObjectMapper, Java tabanlı bir Spring konfigürasyonunda tanımlanmış herhangi bir özel olarak kaydedebilirsiniz .


ObjectMapper'ın Spring Boot ile enjekte edilmesini ve yapılandırılmasını tercih ederim.
Constantino Cronemberger

1
Elbette, Spring Boot kullanıyorsanız. Bu bir Spring Boot sorusu değildi.
Dormouse

Evet, Spring Web'i Spring Boot ile kullanırken, Spring Boot tarafından sağlanan ObjectMapper'ı kullanmadığını fark etmek ilginç ve bu yüzden bana yardımcı olan bu soruya son verdim.
Constantino Cronemberger

Bu, tüm varsayılan mesaj dönüştürücülerini temizler! Eminim kimse bunu istemez. Çözüm için cevabımı görün .
adrhc

Mesaj dönüştürücülerini genişletmek istiyorsanız extendMessageConverters, Spring belgelerine göre doğru çözüm geçersiz kılmak olacaktır . Ama buna hiç ihtiyacım olmadı, çünkü sadece özelleştirilmiş bir şeye ihtiyacım var MappingJackson2HttpMessageConverter.
Dormouse

1

Spring 3.2.4 ve Jackson FasterXML 2.1.1 kullanıyorum.

Eşlenen Nesnelerin her bir özniteliği için açık ek açıklamalarla çalışan özel bir JacksonObjectMapper oluşturdum :

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

Daha sonra bu, bağlam yapılandırmasında ( servlet-context.xml ) somutlaştırılır :

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

Bu iyi çalışıyor!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.