wake-up-neo.com

Wie kann ich den von Spring Boot implizit verwendeten Jackson JSON-Mapper anpassen?

Ich verwende Spring Boot (1.2.1) auf ähnliche Weise wie im Erstellen eines RESTful-Webdienstes Tutorial:

@RestController
public class EventController {

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

}

Daher verwendet Spring MVC Jackson implizit, um mein EventList -Objekt in JSON zu serialisieren.

Ich möchte jedoch einige einfache Anpassungen am JSON-Format vornehmen, z.

setSerializationInclusion(JsonInclude.Include.NON_NULL)

Die Frage ist: Was ist der einfachste Weg, um den impliziten JSON-Mapper anzupassen?

Ich habe den Ansatz in diesem Blogbeitrag ausprobiert, einen CustomObjectMapper erstellt und so weiter, aber in Schritt 3 "Registrieren von Klassen in der Frühlingskontext ", scheitert:

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: {}

Es sieht so aus, als ob diese Anweisungen für ältere Versionen von Spring MVC gelten, während ich nach einer einfachen Möglichkeit suche, dies mit dem neuesten Spring Boot zum Laufen zu bringen.

82
Jonik

Wenn Sie Spring Boot 1.3 verwenden, können Sie die Einbeziehung der Serialisierung über application.properties Konfigurieren:

spring.jackson.serialization-inclusion=non_null

Nach den Änderungen in Jackson 2.7 verwendet Spring Boot 1.4 stattdessen eine Eigenschaft mit dem Namen spring.jackson.default-property-inclusion:

spring.jackson.default-property-inclusion=non_null

Siehe " Anpassen des Jackson ObjectMapper " in der Spring Boot-Dokumentation.

Wenn Sie eine frühere Version von Spring Boot verwenden, können Sie die Serialisierungseinbeziehung in Spring Boot am einfachsten konfigurieren, indem Sie Ihre eigene, entsprechend konfigurierte Jackson2ObjectMapperBuilder - Bean deklarieren. Zum Beispiel:

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

Viele Dinge können in Anwendungseigenschaften konfiguriert werden. Leider ist diese Funktion nur in Version 1.3 verfügbar, aber Sie können eine Config-Klasse hinzufügen

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

[UPDATE: Sie müssen am ObjectMapper arbeiten, da die build()- -Methode aufgerufen wird, bevor die Konfiguration ausgeführt wird.]

20
nbank

Ich beantworte diese Frage etwas zu spät, aber in Zukunft könnte dies für jemanden nützlich sein. Der folgende Ansatz funktioniert neben vielen anderen Ansätzen am besten, und ich persönlich denke, er passt besser zu einer Webanwendung.

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

Die Dokumentation gibt mehrere Möglichkeiten an, dies zu tun.

Wenn Sie den Standardwert ObjectMapper vollständig ersetzen möchten, definieren Sie einen @Bean Dieses Typs und markieren Sie ihn als @Primary.

Wenn Sie einen @Bean - Wert vom Typ Jackson2ObjectMapperBuilder Definieren, können Sie sowohl die Standardwerte ObjectMapper als auch XmlMapper (verwendet in MappingJackson2HttpMessageConverter Und MappingJackson2XmlHttpMessageConverter beziehungsweise).

18
Predrag Maric

spring.jackson.serialization-inclusion=non_null hat früher für uns gearbeitet

Als wir jedoch die Spring Boot-Version auf 1.4.2.RELEASE oder höher aufrüsteten, funktionierte sie nicht mehr.

Nun, eine andere Eigenschaft spring.jackson.default-property-inclusion=non_null macht die Magie.

eigentlich, serialization-inclusion ist veraltet. Das ist es, was mein Verstand auf mich wirft.

Veraltet: ObjectMapper.setSerializationInclusion wurde in Jackson 2.7 nicht mehr weiterentwickelt

Also, beginne mit spring.jackson.default-property-inclusion=non_null statt

9
so-random-dude

Sie können in Ihrer bootstrap Klasse, die mit @SpringBootApplication Kommentiert ist, eine der folgenden Methoden hinzufügen:

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

Ich bin auf eine andere Lösung gestoßen, die ganz nett ist.

Grundsätzlich tun Sie nur Schritt 2 aus dem erwähnten Blog und definieren einen benutzerdefinierten ObjectMapper als Quelle @Component. (Dinge begannen zu funktionieren, als ich gerade entfernt ​​das gesamte AnnotationMethodHandlerAdapter-Zeug von Schritt 3)

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

Funktioniert, solange sich die Komponente in einem von Spring gescannten Paket befindet. (Die Verwendung von @Primary Ist in meinem Fall nicht obligatorisch, aber warum nicht explizit angeben.)

Für mich gibt es zwei Vorteile gegenüber dem anderen Ansatz:

  • Das ist einfacher; Ich kann einfach eine Klasse von Jackson aus verlängern und muss nichts über hochgradig frühlingsspezifische Dinge wie Jackson2ObjectMapperBuilder Wissen.
  • Ich möchte die gleichen Jackson-Konfigurationen zum Deserialisieren von JSON in einem anderen Teil meiner App verwenden, und auf diese Weise ist es sehr einfach: new CustomObjectMapper() anstelle von new ObjectMapper().
4
Jonik

Als ich versuchte, ObjectMapper in Spring Boot 2.0.6 als primären Server zu definieren, wurden Fehler gemeldet. Daher habe ich denjenigen geändert, den Spring Boot für mich erstellt hat

Siehe auch 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
Kalpesh Soni

Ich habe die oben beschriebene Lösung gefunden mit:

spring.jackson.serialization-included = non_null

Funktioniert nur ab der Version 1.4.0.RELEASE von Spring Boot. In allen anderen Fällen wird die Konfiguration ignoriert.

Ich habe dies durch Experimentieren mit einer Modifikation des Spring-Boot-Musters "Spring-Boot-Sample-Jersey" überprüft.

0
Tim Dugan

Ich kenne die Frage nach Spring-Stiefeln, aber ich glaube, dass viele Leute, die danach suchen, wie man das in Nicht-Spring-Stiefeln macht, wie ich fast den ganzen Tag suchen.

Über Spring 4 muss MappingJacksonHttpMessageConverter nicht konfiguriert werden, wenn Sie nur ObjectMapper konfigurieren möchten.

Sie müssen nur Folgendes tun:

public class MyObjectMapper extends ObjectMapper {

    private static final long serialVersionUID = 4219938065516862637L;

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

Erstellen Sie in Ihrer Spring-Konfiguration diese Bean:

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