Spring Boot tarafından örtük olarak kullanılan Jackson JSON eşleştiricisi nasıl özelleştirilir?


102

Spring Boot'u (1.2.1), RESTful Web Hizmeti Oluşturma öğreticisiyle benzer şekilde kullanıyorum :

@RestController
public class EventController {

    @RequestMapping("/events/all")
    EventList events() {
        return proxyService.getAllEvents();
    }

}

Yukarıda, Spring MVC, nesnemi JSON'a serileştirmek için dolaylı olarak Jackson'ı kullanıyor EventList.

Ancak JSON biçiminde bazı basit özelleştirmeler yapmak istiyorum, örneğin:

setSerializationInclusion(JsonInclude.Include.NON_NULL)

Soru, örtük JSON eşleştiricisini özelleştirmenin en basit yolu nedir?

Bu blog gönderisindeki yaklaşımı , bir CustomObjectMapper oluşturmayı vb. Denedim , ancak adım 3, "Sınıfları Bahar bağlamında kaydet" başarısız oluyor:

org.springframework.beans.factory.BeanCreationException: 
  Error creating bean with name 'jacksonFix': Injection of autowired dependencies failed; 
  nested exception is org.springframework.beans.factory.BeanCreationException: 
  Could not autowire method: public void com.acme.project.JacksonFix.setAnnotationMethodHandlerAdapter(org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter); 
  nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: 
  No qualifying bean of type [org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter]   
  found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}

Görünüşe göre bu talimatlar Spring MVC'nin eski sürümleri için, ancak bunu en son Spring Boot ile çalıştırmanın basit bir yolunu arıyorum.


Bu Ek Açıklamayı eklediniz mi ?: @SuppressWarnings ({"SpringJavaAutowiringInspection"})
sven.kwiotek

Spring Web'i de kullanıyorsanız, bu ObjectMapper'ı kullanmasını manuel olarak söylemeniz gerekeceğine dikkat edin, aksi takdirde yapılandırılmayacak olan kendi örneğini oluşturacaktır. Stackoverflow.com/questions/7854030/… sayfasına
Constantino Cronemberger

Yanıtlar:


117

Spring Boot 1.3 kullanıyorsanız, serileştirme dahil etmeyi şu şekilde yapılandırabilirsiniz application.properties:

spring.jackson.serialization-inclusion=non_null

Jackson 2.7'deki değişikliklerin ardından Spring Boot 1.4, spring.jackson.default-property-inclusionbunun yerine adlandırılmış bir özellik kullanır :

spring.jackson.default-property-inclusion=non_null

"Bölümüne bakın Jackson ObjectMapper özelleştirme Bahar Boot belgelerinde bölümü".

Spring Boot'un önceki bir sürümünü kullanıyorsanız, Spring Boot'a serileştirme dahil etmeyi yapılandırmanın en kolay yolu, kendi, uygun şekilde yapılandırılmış Jackson2ObjectMapperBuilderbean'inizi bildirmektir . Örneğin:

@Bean
public Jackson2ObjectMapperBuilder objectMapperBuilder() {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    builder.serializationInclusion(JsonInclude.Include.NON_NULL);
    return builder;
}

1
Pekala, bu işe yarıyor gibi görünüyor. Böyle bir yöntemi nereye koyarsınız? Belki bir ana Uygulama sınıfında (with @ComponentScan, @EnableAutoConfigurationvb.)?
Jonik

2
Evet. Bu yöntem, @Configurationuygulamanızdaki herhangi bir sınıfa girebilir . Ana Applicationsınıf bunun için iyi bir yer.
Andy Wilkinson

2
Önemli not: Jackson2ObjectMapperBuilder sınıfı, yaylı web bileşeninin bir parçasıdır ve 4.1.1 sürümüne eklenmiştir.
gaoagong

2
@Deprecated setSerializationInclusion
Dimitri Kopriwa

6
Kullanımdan kaldırıldı: ObjectMapper.setSerializationInclusion, Jackson 2.7'de kullanımdan kaldırıldı ... yerine stackoverflow.com/a/44137972/6785908 spring.jackson.default-property-inclusion = non_null
so-random-dude

24

Bu soruya biraz geç cevap veriyorum, ancak gelecekte birisi bunu yararlı bulabilir. Aşağıdaki yaklaşım, diğer birçok yaklaşımın yanı sıra en iyi sonucu verir ve kişisel olarak bir web uygulamasına daha uygun olacağını düşünüyorum.

@Configuration
@EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter {

 ... other configurations

@Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        builder.serializationInclusion(JsonInclude.Include.NON_NULL);
        builder.propertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
        builder.serializationInclusion(Include.NON_EMPTY);
        builder.indentOutput(true).dateFormat(new SimpleDateFormat("yyyy-MM-dd"));
        converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
        converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
    }
}

1
Son sürümde uygulamanız gerekirWebMvcConfigurer
João Pedro Schmitt

evet, insanlar, bu çözümü deneyin, ObjectMapper için Bean sağlamaya çalıştım, sonra da Jackson2ObjectMapperBuilder için Bean satın almanın işe yaramadı ve neden hala bir fikrim yok. Kapakçı eklemek işe yaradı!
Somal Somalski

22

Uygulama özelliklerinde birçok şey yapılandırılabilir. Maalesef bu özellik yalnızca Sürüm 1.3'te, ancak bir Yapılandırma Sınıfı ekleyebilirsiniz

@Autowired(required = true)
public void configureJackson(ObjectMapper jackson2ObjectMapper) {
    jackson2ObjectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}

[GÜNCELLEME: ObjectMapper üzerinde çalışmalısınız çünkü build()yapılandırma çalıştırılmadan önce-yöntemi çağrılır.]


Günümü kurtaran çözüm buydu. Bunun dışında, bu yöntemi yapılandırma sınıfı yerine REST denetleyicisinin kendisine ekledim.
Nestor Milyaev

21

Belgeler , bunu yapmanın birkaç yolunu belirtir.

Varsayılanı ObjectMappertamamen değiştirmek istiyorsanız @Bean, bu türden a tanımlayın ve olarak işaretleyin @Primary.

Bir tanımlama @BeanÇeşidi Jackson2ObjectMapperBuildervarsayılanı hem özelleştirmek sağlayacak ObjectMapperve XmlMapper(kullanılan MappingJackson2HttpMessageConverterve MappingJackson2XmlHttpMessageConvertersırasıyla).


2
Varsayılanı değiştirmeden aynısı nasıl yapılır ObjectMapper? Varsayılanı bir gelenek olarak tutmak demek istiyorum.
soufrk

13

Bootstrap sınıfınızın içine aşağıdaki yöntemi ekleyebilirsiniz. @SpringBootApplication

    @Bean
    @Primary
    public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
    ObjectMapper objectMapper = builder.createXmlMapper(false).build();
    objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    objectMapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false);

    objectMapper.registerModule(new JodaModule());

    return objectMapper;
}

Bu benim için Boot 2.1.3 kullanarak çalıştı. Spring.jackson özelliklerinin hiçbir etkisi olmadı.
Richtopia

9

spring.jackson.serialization-inclusion=non_null bizim için çalışırdı

Ancak yay önyükleme sürümünü 1.4.2.RELEASE veya üstüne yükselttiğimizde çalışmayı durdurdu.

Şimdi, başka bir özellik spring.jackson.default-property-inclusion=non_nullsihir yapıyor.

aslında, serialization-inclusionkullanımdan kaldırılmıştır. Benim istihbaratımın bana fırlattığı şey bu.

Kullanımdan kaldırıldı: ObjectMapper.setSerializationInclusion, Jackson 2.7'de kullanımdan kaldırıldı

Yani, kullanmaya başlamak spring.jackson.default-property-inclusion=non_nullyerine


4

Oldukça güzel olan başka bir çözüme rastladım.

Temel olarak, sadece bahsedilen blogdan 2. adımı uygulayın ve özel bir ObjectMapper'ı Spring olarak tanımlayın @Component. ( 3. adımdaki tüm AnnotationMethodHandlerAdapter öğelerini kaldırdığımda işler çalışmaya başladı .)

@Component
@Primary
public class CustomObjectMapper extends ObjectMapper {
    public CustomObjectMapper() {
        setSerializationInclusion(JsonInclude.Include.NON_NULL); 
        configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 
    }
}

Bileşen, Spring tarafından taranan bir pakette olduğu sürece çalışır. ( @PrimaryBenim durumumda kullanmak zorunlu değil, ama neden her şeyi açıklığa kavuşturmayalım.)

Benim için diğer yaklaşıma kıyasla iki fayda var:

  • Bu daha basit; Sadece Jackson'dan bir dersi uzatabilirim ve gibi Spring'e özel şeyleri bilmeme gerek yok Jackson2ObjectMapperBuilder.
  • JSON'un serisini kaldırmak için aynı Jackson yapılandırmalarını uygulamamın başka bir bölümünde kullanmak istiyorum ve bu şekilde çok basit: new CustomObjectMapper()yerine new ObjectMapper().

Bu yaklaşımın dezavantajı, özel yapılandırmanızın ObjectMapperSpring Boot tarafından oluşturulan veya yapılandırılan herhangi bir örneğe uygulanmamasıdır .
Andy Wilkinson

Hmm, özel yapılandırma olduğunu ima edilen serileştirme için kullanılan @RestControllerşu anda benim için yeterli sınıflar. (Yani bu örneklerin Spring Boot tarafından değil, Spring MVC tarafından oluşturulduğunu mu söylüyorsunuz?) Ancak ObjectMappers'ın başlatılması gereken başka durumlarla karşılaşırsam, Jackson2ObjectMapperBuilder yaklaşımını aklımda tutacağım!
Jonik

3

İlkbahar önyüklemesinde 2.0.6 ObjectMapper'ı birincil yapmaya çalıştığımda hatalar aldım, bu yüzden benim için oluşturduğum bahar önyüklemesini değiştirdim

Ayrıca bkz. Https://stackoverflow.com/a/48519868/255139

@Lazy
@Autowired
ObjectMapper mapper;

@PostConstruct
public ObjectMapper configureMapper() {
    mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);

    mapper.configure(MapperFeature.ALLOW_COERCION_OF_SCALARS, true);
    mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);

    SimpleModule module = new SimpleModule();
    module.addDeserializer(LocalDate.class, new LocalDateDeserializer());
    module.addSerializer(LocalDate.class, new LocalDateSerializer());
    mapper.registerModule(module);

    return mapper;
}

1

Yukarıda açıklanan çözümü şununla buldum:

spring.jackson.serialization-inclusion = non_null

Sadece yaylı önyüklemenin 1.4.0.RELEASE sürümünden başlayarak çalışmak için. Diğer tüm durumlarda yapılandırma göz ardı edilir.

Bunu, "spring-boot-sample-jersey" yaylı bot örneğinin bir modifikasyonunu deneyerek doğruladım


0

Spring boot için sorulan soruyu biliyorum, ancak neredeyse bütün gün arama yaptığım gibi, Spring botta bunu nasıl yapacağını arayan birçok insanın olduğuna inanıyorum.

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

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