Używam Spring Boot (1.2.1), w podobny sposób, jak w ich samouczku Tworzenie usługi sieci Web RESTful :
@RestController
public class EventController {
@RequestMapping("/events/all")
EventList events() {
return proxyService.getAllEvents();
}
}
Tak więc powyżej, Spring MVC niejawnie używa Jacksona do serializacji mojego EventList
obiektu do formatu JSON.
Ale chcę zrobić kilka prostych dostosowań do formatu JSON, na przykład:
setSerializationInclusion(JsonInclude.Include.NON_NULL)
Pytanie brzmi, jaki jest najprostszy sposób dostosowania niejawnego mapowania JSON?
Wypróbowałem podejście opisane w tym poście na blogu , tworząc CustomObjectMapper i tak dalej, ale krok 3, „Rejestracja klas w kontekście Spring”, kończy się niepowodzeniem:
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: {}
Wygląda na to, że te instrukcje dotyczą starszych wersji Spring MVC, a ja szukam prostego sposobu, aby to działało z najnowszym Spring Boot.
java
spring
spring-mvc
jackson
spring-boot
Jonik
źródło
źródło
Odpowiedzi:
Jeśli używasz Spring Boot 1.3, możesz skonfigurować włączenie serializacji poprzez
application.properties
:Po zmianach w Jackson 2.7, Spring Boot 1.4 używa właściwości o nazwie
spring.jackson.default-property-inclusion
:spring.jackson.default-property-inclusion=non_null
Zobacz sekcję „ Dostosuj Jackson ObjectMapper ” w dokumentacji Spring Boot.
Jeśli używasz wcześniejszej wersji Spring Boot, najłatwiejszym sposobem skonfigurowania włączenia serializacji do Spring Boot jest zadeklarowanie własnego, odpowiednio skonfigurowanego
Jackson2ObjectMapperBuilder
komponentu bean. Na przykład:@Bean public Jackson2ObjectMapperBuilder objectMapperBuilder() { Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); builder.serializationInclusion(JsonInclude.Include.NON_NULL); return builder; }
źródło
@ComponentScan
,@EnableAutoConfiguration
etc)?@Configuration
klasie w Twojej aplikacji.Application
Klasa główna jest do tego dobrym miejscem.Trochę późno odpowiadam na to pytanie, ale ktoś w przyszłości może uznać to za przydatne. Poniższe podejście, oprócz wielu innych podejść, działa najlepiej i osobiście uważam, że lepiej pasowałoby do aplikacji internetowej.
@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())); } }
źródło
WebMvcConfigurer
Wiele rzeczy można skonfigurować we właściwościach aplikacji. Niestety ta funkcja jest dostępna tylko w wersji 1.3, ale można dodać ją w klasie Config
@Autowired(required = true) public void configureJackson(ObjectMapper jackson2ObjectMapper) { jackson2ObjectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); }
[AKTUALIZACJA: Musisz pracować na ObjectMapper, ponieważ
build()
-method jest wywoływana przed uruchomieniem konfiguracji.]źródło
Dokumentacja podaje kilka sposobów, aby to zrobić.
źródło
ObjectMapper
? Mam na myśli zachowanie wartości domyślnej, jak również zwyczaju.Możesz dodać następującą metodę wewnątrz swojej klasy bootstrap, która jest opatrzona adnotacją
@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; }
źródło
spring.jackson.serialization-inclusion=non_null
pracował dla nasAle kiedy zaktualizowaliśmy wersję Spring Boot do 1.4.2.RELEASE lub nowszej, przestała działać.
Teraz kolejna nieruchomość
spring.jackson.default-property-inclusion=non_null
robi magię.w rzeczywistości
serialization-inclusion
jest przestarzały. To właśnie rzuca we mnie mój intellij.Więc zacznij używać
spring.jackson.default-property-inclusion=non_null
zamiast tegoźródło
Natknąłem się na inne rozwiązanie, które jest całkiem miłe.
Zasadniczo wykonaj tylko krok 2 ze wspomnianego blogu i zdefiniuj niestandardowy obiekt ObjectMapper jako Spring
@Component
. (Wszystko zaczęło działać, gdy właśnie usunąłem wszystkie elementy AnnotationMethodHandlerAdapter z kroku 3).@Component @Primary public class CustomObjectMapper extends ObjectMapper { public CustomObjectMapper() { setSerializationInclusion(JsonInclude.Include.NON_NULL); configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); } }
Działa tak długo, jak długo komponent znajduje się w pakiecie skanowanym przez Spring. (Za pomocą
@Primary
nie jest obowiązkowe w moim przypadku, ale dlaczego nie wyjaśnić rzeczy).Dla mnie są dwie korzyści w porównaniu z innym podejściem:
Jackson2ObjectMapperBuilder
.new CustomObjectMapper()
zamiastnew ObjectMapper()
.źródło
ObjectMapper
instancji, które są tworzone lub konfigurowane przez Spring Boot.@RestController
klasach, które obecnie mi wystarczają. (Więc masz na myśli, że te instancje są tworzone przez Spring MVC, a nie Spring Boot?) Ale jeśli napotkam inne przypadki, w których trzeba utworzyć instancję ObjectMappers, będę pamiętać o podejściu Jackson2ObjectMapperBuilder!Kiedy próbowałem ustawić ObjectMapper jako podstawowy w Spring Boot 2.0.6, otrzymałem błędy Więc zmodyfikowałem ten, który utworzył dla mnie Spring Boot
Zobacz też 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; }
źródło
Znalazłem rozwiązanie opisane powyżej z:
spring.jackson.serialization-inclusive = non_null
Działa tylko od wersji 1.4.0.RELEASE buta sprężynowego. We wszystkich innych przypadkach konfiguracja jest ignorowana.
Sprawdziłem to, eksperymentując z modyfikacją próbki buta sprężynowego „spring-boot-sample-jersey”
źródło
Znam pytanie dotyczące butów wiosennych, ale wydaje mi się, że wiele osób, które szukają sposobu na zrobienie tego w butach innych niż wiosenne, jak ja, szukam prawie cały dzień.
Powyżej Spring 4 nie ma potrzeby konfigurowania,
MappingJacksonHttpMessageConverter
jeśli zamierzasz tylko konfigurowaćObjectMapper
.Musisz tylko:
public class MyObjectMapper extends ObjectMapper { private static final long serialVersionUID = 4219938065516862637L; public MyObjectMapper() { super(); enable(SerializationFeature.INDENT_OUTPUT); } }
A w konfiguracji Spring utwórz tę fasolkę:
@Bean public MyObjectMapper myObjectMapper() { return new MyObjectMapper(); }
źródło