Spring Data 2.2.8はDomainClassConverterが死んでいるので注意
更新情報
2020/07/24に2.2.9がリリースされ無事に以下で説明する不具合は起こらなくなりました。
はじめに
Spring Dataにはリクエストパラメータ(クエリストリングもしくはフォーム)や@PathVariable
としてidを渡すとドメインオブジェクトを検索して設定してくれるDomainClassConverter
という超便利な機能があります。
https://docs.spring.io/spring-data/jpa/docs/2.2.8.RELEASE/reference/html/#core.web.basic
@GetMapping("/users/{id}")
public User show(@PathVariable("id") User user) {
return user;
}
が、バージョン2.2.8ではこの機能が死んでいます。
上で例に示した/users/1
にアクセスすると以下のように500エラーになります。
There was an unexpected error (type=Internal Server Error, status=500).
Failed to convert value of type 'java.lang.String' to required type 'com.example.demo.User';
nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'com.example.demo.User': no matching editors or conversion strategy found
なお私が報告を受けたのはSpring Data JPAを使っているプロジェクトでフォーム送信(POST)が死ぬという状況だったのですが、この場合、フォームに埋めてある関連オブジェクトを検索しようとして死亡、ステータスとしては400が返されてました。
解決方法
ありません。
不具合報告されており、修正もされています。2.2.9ではこの不具合は発生しません。
2.2.9がリリースされるまではpom.xmlをいじるなどして2.2.7に戻しましょう(個人的に致命的なので早めにリリースされてほしい)
何が問題なのか
2.2.8に含まれるDomainClassConverterには以下の修正が行われています。
Defer initialization of Repositories in DomainClassConverter.
この結果、2.2.7まではアプリ起動時に行われていたConverterの登録処理が
public void setApplicationContext(ApplicationContext context) {
this.repositories = new Repositories(context);
this.toEntityConverter = Optional.of(new ToEntityConverter(this.repositories, this.conversionService));
this.toEntityConverter.ifPresent(it -> this.conversionService.addConverter(it));
this.toIdConverter = Optional.of(new ToIdConverter());
this.toIdConverter.ifPresent(it -> this.conversionService.addConverter(it));
}
2.2.8では遅延実行されることになり、
public void setApplicationContext(ApplicationContext context) {
this.repositories = Lazy.of(() -> {
Repositories repositories = new Repositories(context);
this.toEntityConverter = Optional.of(new ToEntityConverter(repositories, conversionService));
this.toEntityConverter.ifPresent(it -> conversionService.addConverter(it));
this.toIdConverter = Optional.of(new ToIdConverter(repositories, conversionService));
this.toIdConverter.ifPresent(it -> conversionService.addConverter(it));
return repositories;
});
}
this.repositories
はsetApplicationContext
メソッドの上にあるgetConverter
メソッドが呼び出されたとき1に遅延初期化されるものの、
もうおわかりだろう・・・
誰も!!getConverterメソッドを呼んでいないのである!!!
どうにか呼び出す方法はないものかと小一時間悩んでも解決できなかったので最新だと修正されてるか確認したら初めに挙げたコミットを見つけたというオチです。
あとがき
というわけで今回はSpring Dataの修正によりはまったというお話でした。一つバグを直したら別のところが壊れたという状況ですね。
ただ遅延初期化を導入したコミット自体はとなっており、「テストしてない部分は壊れててもわからない」ということはSpringのように規模が大きくなってくると起こりえるのだなと自戒も含めて思いました。
-
getConverter
メソッドはconvert
メソッド(このメソッドはSpringのコア機能)が呼ばれたときに使われる。 ↩
Author And Source
この問題について(Spring Data 2.2.8はDomainClassConverterが死んでいるので注意), 我々は、より多くの情報をここで見つけました https://qiita.com/junjis0203/items/874845ba314fbf3767ad著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .