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でこれを動作させる簡単な方法を探しています。
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;
}
Applicationpropertiesで多くのことが設定できます。残念ながら、この機能はバージョン1.3でのみ使用できますが、Config-Classに追加できます
@Autowired(required = true)
public void configureJackson(ObjectMapper jackson2ObjectMapper) {
jackson2ObjectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
[更新:構成が実行される前にbuild()
- methodが呼び出されるため、ObjectMapperで作業する必要があります。]
私はこの質問に少し遅れて答えていますが、将来誰かがこれを役に立つと思うかもしれません。他の多くのアプローチに加えて、以下のアプローチが最適に機能し、個人的には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()));
}
}
ドキュメント は、これを行ういくつかの方法を示しています。
デフォルトの
ObjectMapper
を完全に置き換える場合は、そのタイプの@Bean
を定義し、@Primary
としてマークします。タイプ
@Bean
のJackson2ObjectMapperBuilder
を定義すると、デフォルトのObjectMapper
とXmlMapper
(それぞれMappingJackson2HttpMessageConverter
とMappingJackson2XmlHttpMessageConverter
で使用)の両方をカスタマイズできます。
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
の使用を開始
@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;
}
私は別の解決策に出くわしました。
基本的に、 ブログ投稿のステップ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つの利点があります。
Jackson2ObjectMapperBuilder
のような高度にSpring固有のものについて知る必要はありません。new CustomObjectMapper()
ではなくnew ObjectMapper()
。スプリングブート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;
}
私は上記の解決策を見つけました:
spring.jackson.serialization-inclusion = non_null
スプリングブートの1.4.0.RELEASEバージョン以降でのみ動作します。他のすべての場合、構成は無視されます。
スプリングブートサンプル "spring-boot-sample-jersey"の変更を試して、これを検証しました。
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();
}