Edited at

Spring Boot環境でJava8日付型(JSR-310)を使うための設定

More than 3 years have passed since last update.

Springでは既にJava8で導入された新日付型(以下、JSR-310日付型)をサポートしていますが、実際に使用する際には各コンポーネントで設定が必要だったり、フォーマットを指定したかったりするので設定方法をまとめておきます。

サンプルはこちら。

https://github.com/tag1216/example-spring-boot-jsr310

合わせてSpringの各コンポーネントで標準で対応していない型(以下、非標準型)を扱う方法を軽く解説します。


構成


  • Spring Boot(1.3.0.RELEASE)

  • Spring MVC

  • Spring Data JPA

  • Jackson


Spring Data JPA


非標準型の対応方法

Entityクラスやクエリーメソッドの引数で非標準型を使うには、AttributeConverterインターフェースの実装クラスを作成して標準型への変換を行います。


JSR-310の対応方法

Spring Data JPA ではJsr310JpaConvertersというクラスにJSR-310日付型の変換が用意してあります。

これをスキャン対象に設定すればでJSR-310日付型が使えるようになります。


application.java

import org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters;

@SpringBootApplication
@EntityScan(basePackageClasses = {Application.class, Jsr310JpaConverters.class})
public class Application {



Jackson


非標準型の対応方法

JacksonではJsonSerializerJsonDeserializerを実装してObjectMapperに登録することで非標準の型に対応できます。


JSR-310の対応方法

JSR-310日付型のSerializer/Deserializerはjackson-datatype-jsr310という追加モジュールに用意してあります。

これを依存関係に追加しておけばSpring Boot環境ではObjectMapperにモジュールを自動で追加してくれるのでJSR-310日付型が使えるようになります。

ただし、これだけだとEntityの属性に@JsonFormatでフォーマットを指定しないと[2015,12,1]というような配列になってしまうのでイマイチです。

そこで、次のようにJSR310日付型のモジュールを追加する際にフォーマットを指定しておく事で、@JsonFormatが指定されていない時のデフォルトとして使用されます。


Application.java

    @Bean

public ObjectMapper jsonObjectMapper() {
JavaTimeModule module = new JavaTimeModule();
module.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy/MM/dd")));
module.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy/MM/dd")));
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);
return mapper;
}


Spring MVC


非標準型の対応方法

SpringではConversionServiceFormatterConverterを登録して型変換を行います。

Spring BootではFormatterやConverterをコンポーネントとして登録しておけば自動でConversionServiceに追加されます。

Spring Boot Reference Guide - 27.1.1 Spring MVC auto-configuration


JSR-310の対応方法

Jsr310DateTimeFormatAnnotationFormatterFactoryクラスが予め登録されているので、@DateTimeFormatを使用すればJSR-310日付型を使用できます。


PlanRestController.java

  @RequestMapping(method = GET)

public List<Plan> index(
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy/MM/dd") LocalDate date,
@RequestParam(required = false) String title) {

また、以下のようにFormatterを登録しておけば@DateTimeFormatを使用せずにJSR-310日付型を使用する事ができます。

ただし、Formatterを登録すると@DateTimeFormatが効かなくなるようなので注意が必要です。


Application.java

    @Bean

public Formatter<LocalDate> localDateFormatter() {
return new Formatter<LocalDate>() {
@Override
public String print(LocalDate object, Locale locale) {
return object.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
}
@Override
public LocalDate parse(String text, Locale locale) throws ParseException {
return LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyy/MM/dd"));
}
};
}