Как настроить Jackson JSON mapper, неявно используемый Spring Boot?
Я использую Spring Boot (1.2.1), так же как в Создание RESTful Web Service:
@RestController
public class EventController {
@RequestMapping("/events/all")
EventList events() {
return proxyService.getAllEvents();
}
}
Итак, Spring MVC неявно использует Jackson для сериализации моего объекта EventList
в JSON.
Но я хочу сделать некоторые простые настройки в формате JSON, например:
setSerializationInclusion(JsonInclude.Include.NON_NULL)
Вопрос: Каков самый простой способ настроить неявный JSON файл?
Я пробовал подход в этом сообщении в блоге, создав CustomObjectMapper и т.д., но шаг 3, "Зарегистрировать классы в Spring контексте", не удается:
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: {}
Похоже, что эти инструкции предназначены для более старых версий Spring MVC, в то время как я ищу простой способ получить эту работу с последней загрузкой Spring.
Ответы
Ответ 1
Если вы используете Spring Boot 1.3, вы можете настроить включение сериализации через application.properties
:
spring.jackson.serialization-inclusion=non_null
После изменений в Jackson 2.7 Spring Boot 1.4 вместо этого использует свойство с именем spring.jackson.default-property-inclusion
:
spring.jackson.default-property-inclusion=non_null
См. Раздел " Настройка Jackson ObjectMapper " в документации по Spring Boot.
Если вы используете более раннюю версию Spring Boot, самый простой способ настроить включение сериализации в Spring Boot - это объявить свой собственный, соответствующим образом настроенный компонент Jackson2ObjectMapperBuilder
. Например:
@Bean
public Jackson2ObjectMapperBuilder objectMapperBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.serializationInclusion(JsonInclude.Include.NON_NULL);
return builder;
}
Ответ 2
Многое можно настроить в свойствах приложения. К сожалению, эта функция только в версии 1.3, но вы можете добавить в Config-Class
@Autowired(required = true)
public void configureJackson(ObjectMapper jackson2ObjectMapper) {
jackson2ObjectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
[ОБНОВЛЕНИЕ: Вы должны работать с ObjectMapper, потому что build()
-method вызывается до запуска конфигурации.]
Ответ 3
Я немного отвечаю на этот вопрос, но кто-то в будущем может найти это полезным. Подход ниже, помимо множества других подходов, работает лучше всего, и я лично думаю, что лучше подходит для веб-приложения.
@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()));
}
}
Ответ 4
В документации указано несколько способов сделать это.
Если вы хотите полностью заменить стандартный ObjectMapper
, определите @Bean
этого типа и отметьте его как @Primary
.
Определение @Bean
типа Jackson2ObjectMapperBuilder
позволит вам настроить как стандартные ObjectMapper
, так и XmlMapper
(используемые в MappingJackson2HttpMessageConverter
и MappingJackson2XmlHttpMessageConverter
соответственно).
Ответ 5
spring.jackson.serialization-inclusion=non_null
раньше работала на нас
Но когда мы обновили весеннюю загрузочную версию до 1.4.2. RELEASE или выше, она перестала работать.
Теперь еще одно свойство spring.jackson.default-property-inclusion=non_null
делает магию.
фактически serialization-inclusion
не рекомендуется. Это то, что мой интеллиг бросает в меня.
Устаревший: ObjectMapper.setSerializationInclusion устарел в Джексоне 2.7
Итак, вместо этого начните использовать spring.jackson.default-property-inclusion=non_null
Ответ 6
Вы можете добавить следующий метод в ваш класс начальной загрузки, который аннотируется @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;
}
Ответ 7
Я наткнулся на другое решение, которое довольно приятно.
В принципе, сделайте шаг 2 из опубликованного блога и определите пользовательский ObjectMapper как Spring @Component
. (Вещи начали работать, когда я только что удалил все материалы AnnotationMethodHandlerAdapter с шага 3.)
@Component
@Primary
public class CustomObjectMapper extends ObjectMapper {
public CustomObjectMapper() {
setSerializationInclusion(JsonInclude.Include.NON_NULL);
configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
}
Работает, пока компонент находится в пакете, отсканированном Spring. (Использование @Primary
не является обязательным в моем случае, но почему бы не сделать вещи явными.)
Для меня есть два преимущества по сравнению с другим подходом:
- Это проще; Я могу просто расширить класс от Jackson и не нужно знать о высоко Spring -специфических материалах, таких как
Jackson2ObjectMapperBuilder
.
- Я хочу использовать те же настройки Jackson для десериализации JSON в другой части моего приложения, и это очень просто:
new CustomObjectMapper()
вместо new ObjectMapper()
.
Ответ 8
Я нашел решение, описанное выше, с помощью
spring.jackson.serialization-включение = non_null
Работает только с версии 1.4.0.RELEASE для загрузки spring. Во всех остальных случаях config игнорируется.
Я проверил это, экспериментируя с модификацией образца загрузки spring "spring -boot-sample-jersey"
Ответ 9
Я знаю вопрос о загрузке Spring, но я считаю, что многие люди ищут, как это сделать при загрузке без Spring, например, я ищу почти целый день.
Выше Spring 4 нет необходимости настраивать MappingJacksonHttpMessageConverter
, если вы только собираетесь настроить ObjectMapper
.
Вам просто нужно сделать:
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();
}
Ответ 10
Когда я попытался сделать ObjectMapper первичным в весенней загрузке 2.0.6, я получил ошибки, поэтому я изменил тот, который весенний загрузчик создал для меня
Также см. fooobar.com/info/15071225/...
@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;
}