Як налаштувати картограф Jackson JSON, який явно використовує Spring Boot?


101

Я використовую Spring Boot (1.2.1) аналогічним чином, як і у їхньому навчальному посібнику " Створення RESTful Web Service" :

@RestController
public class EventController {

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

}

Отже вище, Spring MVC неявно використовує Джексона для серіалізації мого EventListоб'єкта в JSON.

Але я хочу зробити прості налаштування формату JSON, такі як:

setSerializationInclusion(JsonInclude.Include.NON_NULL)

Питання полягає в тому, який найпростіший спосіб налаштувати неявний відображувач JSON?

Я спробував підхід у цій публікації в блозі , створивши CustomObjectMapper тощо, але крок 3, "Реєстрація класів у контексті весни", не вдається:

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


У вас вставлено цю Анотацію ?: @SuppressWarnings ({"SpringJavaAutowiringInspection"})
sven.kwiotek

Зауважте, що якщо ви також використовуєте Spring Web, вам потрібно буде сказати йому вручну, щоб використовувати цей ObjectMapper, інакше він створить власний екземпляр, який не буде налаштований. Див stackoverflow.com/questions/7854030 / ...
Костянтино Cronemberger

Відповіді:


116

Якщо ви використовуєте 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;
}

1
Добре, здається, це працює. Куди б ви поділили такий метод? Можливо, в основному класі Application (with @ComponentScan, @EnableAutoConfigurationetc)?
Джонік

2
Так. Цей метод можна використовувати в будь-якому @Configurationкласі вашого додатка. Основний Applicationклас - це гарне місце для нього.
Енді Вілкінсон,

2
Важливе зауваження: Клас Jackson2ObjectMapperBuilder є частиною компонента spring-web і був доданий у версії 4.1.1.
gaoagong

2
@ Створений набірSerializationInclusion
Димитрі Копріва

6
Заборонено: ObjectMapper.setSerializationInclusion засуджувався в Джексон 2,7 ... використання stackoverflow.com/a/44137972/6785908 spring.jackson.default-властивості-включенні = non_null замість
так випадкових чуваків

24

Я відповідаю на це питання трохи пізно, але хтось, у майбутньому, може виявити це корисним. Наведений нижче підхід, крім багатьох інших підходів, працює найкраще, і я особисто вважаю, що він краще підходить для веб-додатків.

@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
Останню версію потрібно виконатиWebMvcConfigurer
Жоао Педро Шмітт,

так, люди, спробуйте це рішення, я намагався надати Bean для ObjectMapper, потім Bean для Jackson2ObjectMapperBuilder купувати, що не працювало, і я все ще не знаю, чому. Працюючий прикривач працював!
Somal Somalski

23

Багато можливостей можна налаштувати в властивостях програми. На жаль, ця функція доступна лише у версії 1.3, але ви можете додати її в Config-Class

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

[ОНОВЛЕННЯ: Ви повинні працювати над ObjectMapper, оскільки -method build()викликається перед запуском конфігурації.]


Це було рішення, яке врятувало мені день. За винятком того, що я додав цей метод до самого контролера REST, а не до класу конфігурації.
Нестор Міляєв

20

У документації зазначено кілька способів зробити це.

Якщо ви хочете повністю замінити за замовчуванням ObjectMapper, визначте @Beanтип цього типу та позначте його як @Primary.

Визначення @Beanтипу Jackson2ObjectMapperBuilderдозволить вам налаштувати як за замовчуванням, так ObjectMapperі XmlMapper(використовується в MappingJackson2HttpMessageConverterі MappingJackson2XmlHttpMessageConverterвідповідно).


2
Як зробити те ж саме, не замінюючи типовий ObjectMapper? Я маю на увазі збереження за замовчуванням також спеціальних.
суфрк

12

Ви можете додати наступний метод у свій клас завантаження, до якого додано примітки @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;
}

Цей працював для мене за допомогою Boot 2.1.3. Властивості spring.jackson не впливали.
Річтопія

9

spring.jackson.serialization-inclusion=non_null раніше працював у нас

Але коли ми оновили версію весняного завантаження до 1.4.2.RELEASE або вище, вона перестала працювати.

Зараз ще одна властивість spring.jackson.default-property-inclusion=non_nullробить магію.

насправді serialization-inclusionє застарілим. Це те, що мені кидає мій intellij.

Застаріле: ObjectMapper.setSerializationInclusion був застарілим у Jackson 2.7

Отже, почніть використовувати spring.jackson.default-property-inclusion=non_nullзамість цього


4

Я наткнувся на інше рішення, яке є досить приємним.

В основному, зробіть лише крок 2 із згаданого блогу , і визначте власну ObjectMapper як весну @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в моєму випадку не є обов'язковим, але чому б не зробити речі явними.)

Для мене є дві переваги порівняно з іншими підходами:

  • Це простіше; Я можу просто продовжити клас від Джексона, і мені не потрібно знати про дуже специфічні для Spring речі, наприкладJackson2ObjectMapperBuilder .
  • Я хочу використовувати ті самі конфігурації Джексона для десериалізації JSON в іншій частині мого додатка, і таким чином це дуже просто: new CustomObjectMapper()замість new ObjectMapper().

Недоліком цього підходу є те, що ваша власна конфігурація не застосовуватиметься до будь-яких ObjectMapperекземплярів, створених або налаштованих Spring Boot.
Енді Уілкінсон,

Хм, призначені для користувача конфігурації буде використовуватися для неявного сериализации в @RestControllerкласах , які в даний час досить для мене. (Тобто ви маєте на увазі, що ці екземпляри створюються Spring MVC, а не Spring Boot?) Але якщо я зіткнуся з іншими випадками, коли ObjectMappers потрібно інстанціювати, я буду пам'ятати про підхід Jackson2ObjectMapperBuilder!
Джонік

3

Коли я спробував зробити ObjectMapper первинним при весняному завантаженні 2.0.6, у мене виникли помилки, тому я змінив ту, яку створив для мене весняний бут

Також дивіться 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

Я знайшов описане вище рішення за допомогою:

spring.jackson.serialization-enable = non_null

Працювати лише починаючи з версії 1.4.0.RELEASE з весняним завантаженням. У всіх інших випадках конфігурація ігнорується.

Я перевірив це, експериментуючи з модифікацією зразка весняного завантаження "spring-boot-sample-jersey"


0

Я знаю питання про весняний завантаження, але я вважаю, що багато людей, які шукають, як це зробити у весняних черевиках, як я шукаю майже цілий день.

Вище весни 4 налаштовувати не потрібно, MappingJacksonHttpMessageConverterякщо ви лише маєте намір налаштувати ObjectMapper.

Вам просто потрібно зробити:

public class MyObjectMapper extends ObjectMapper {

    private static final long serialVersionUID = 4219938065516862637L;

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

А у своїй весняній конфігурації створіть цей боб:

@Bean 
public MyObjectMapper myObjectMapper() {        
    return new MyObjectMapper();
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.