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日付型が使えるようになります。
import org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters;
@SpringBootApplication
@EntityScan(basePackageClasses = {Application.class, Jsr310JpaConverters.class})
public class Application {
Jackson
非標準型の対応方法
JacksonではJsonSerializerとJsonDeserializerを実装してObjectMapperに登録することで非標準の型に対応できます。
JSR-310の対応方法
JSR-310日付型のSerializer/Deserializerはjackson-datatype-jsr310という追加モジュールに用意してあります。
これを依存関係に追加しておけばSpring Boot環境ではObjectMapperにモジュールを自動で追加してくれるのでJSR-310日付型が使えるようになります。
ただし、これだけだとEntityの属性に@JsonFormatでフォーマットを指定しないと[2015,12,1]
というような配列になってしまうのでイマイチです。
そこで、次のようにJSR310日付型のモジュールを追加する際にフォーマットを指定しておく事で、@JsonFormatが指定されていない時のデフォルトとして使用されます。
@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ではConversionServiceにFormatterやConverterを登録して型変換を行います。
Spring BootではFormatterやConverterをコンポーネントとして登録しておけば自動でConversionServiceに追加されます。
Spring Boot Reference Guide - 27.1.1 Spring MVC auto-configuration
JSR-310の対応方法
Jsr310DateTimeFormatAnnotationFormatterFactoryクラスが予め登録されているので、@DateTimeFormatを使用すればJSR-310日付型を使用できます。
@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
が効かなくなるようなので注意が必要です。
@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"));
}
};
}