web-dev-qa-db-ja.com

Spring Bootで暗黙的に使用されるJackson JSONマッパーをカスタマイズする方法

RESTful Webサービスの構築 チュートリアルと同様の方法で、Spring Boot(1.2.1)を使用しています。

@RestController
public class EventController {

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

}

そのため、Spring MVCはEventListオブジェクトをJSONにシリアル化するために暗黙的にJacksonを使用します。

しかし、次のような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 Bootでこれを動作させる簡単な方法を探しています。

77
Jonik

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

Spring Bootドキュメントの「 Jackson ObjectMapperのカスタマイズ 」セクションを参照してください。

以前のバージョンのSpring Bootを使用している場合、Spring Bootにシリアル化を含めるように構成する最も簡単な方法は、適切に構成された独自のJackson2ObjectMapperBuilder Beanを宣言することです。例えば:

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

Applicationpropertiesで多くのことが設定できます。残念ながら、この機能はバージョン1.3でのみ使用できますが、Config-Classに追加できます

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

[更新:構成が実行される前にbuild()- methodが呼び出されるため、ObjectMapperで作業する必要があります。]

20
nbank

私はこの質問に少し遅れて答えていますが、将来誰かがこれを役に立つと思うかもしれません。他の多くのアプローチに加えて、以下のアプローチが最適に機能し、個人的にはWebアプリケーションに適していると思います。

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

ドキュメント は、これを行ういくつかの方法を示しています。

デフォルトのObjectMapperを完全に置き換える場合は、そのタイプの@Beanを定義し、@Primaryとしてマークします。

タイプ@BeanJackson2ObjectMapperBuilderを定義すると、デフォルトのObjectMapperXmlMapper(それぞれMappingJackson2HttpMessageConverterMappingJackson2XmlHttpMessageConverterで使用)の両方をカスタマイズできます。

17
Predrag Maric

spring.jackson.serialization-inclusion=non_nullは私たちのために働いていた

しかし、スプリングブートバージョンを1.4.2.RELEASE以降にアップグレードすると、機能しなくなりました。

今、別のプロパティspring.jackson.default-property-inclusion=non_nullが魔法をやっています。

実際、serialization-inclusionは非推奨です。これは私のインテリが私に投げるものです。

非推奨:ObjectMapper.setSerializationInclusionはJackson 2.7で非推奨になりました

つまり、代わりにspring.jackson.default-property-inclusion=non_nullの使用を開始

9
so-random-dude

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

私は別の解決策に出くわしました。

基本的に、 ブログ投稿のステップ2 のみを実行し、カスタムObjectMapperをSpring @Componentとして定義します。 (ステップ3のすべてのAnnotationMethodHandlerAdapterのものをremovedしたときに動作が開始されました。)

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

コンポーネントがSpringによってスキャンされたパッケージ内にある限り機能します。 (私の場合、@Primaryの使用は必須ではありませんが、なぜ物事を明確にしないのですか?)

私にとって、他のアプローチと比較して2つの利点があります。

  • これは簡単です。 Jacksonからクラスを拡張するだけで、Jackson2ObjectMapperBuilderのような高度にSpring固有のものについて知る必要はありません。
  • アプリの別の部分でJSONを逆シリアル化するために同じJackson構成を使用したいので、この方法は非常に簡単です:new CustomObjectMapper()ではなくnew ObjectMapper()
3
Jonik

スプリングブート2.0.6でObjectMapperをプライマリにしようとしたときにエラーが発生したため、スプリングブートで作成されたものを変更しました

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

私は上記の解決策を見つけました:

spring.jackson.serialization-inclusion = non_null

スプリングブートの1.4.0.RELEASEバージョン以降でのみ動作します。他のすべての場合、構成は無視されます。

スプリングブートサンプル "spring-boot-sample-jersey"の変更を試して、これを検証しました。

0
Tim Dugan

Springブートを求める質問は知っていますが、Spring以外のブートでこれを行う方法を探している多くの人が、ほぼ1日中検索しているように思います。

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