かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

Spring Boot 1.4.x の Web アプリを 1.5.x へバージョンアップする ( その3 )( Run 'All Tests' with Coverage 実行時に出るエラーを解消する )

概要

記事一覧はこちらです。

Spring Boot 1.4.x の Web アプリを 1.5.x へバージョンアップする ( その1 )( 概要 ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Run ‘All Tests’ with Coverage 実行時に出るエラーの解消

参照したサイト・書籍

目次

  1. java.lang.IllegalStateException: Failed to load ApplicationContext
  2. 次回は。。。

手順

java.lang.IllegalStateException: Failed to load ApplicationContext

java.lang.IllegalStateException: Failed to load ApplicationContext の下に出力されるメッセージの内、Caused by: から始まるエラーメッセージは以下のものでした。

  • Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'webSecurityConfig': Unsatisfied dependency expressed through method 'setContentNegotationStrategy' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$EnableWebMvcConfiguration': Invocation of init method failed; nested exception is java.lang.IllegalStateException: Found unexpected validator configuration. A Spring Boot MVC validator should be registered as bean named 'mvcValidator' and not returned from WebMvcConfigurer.getValidator()
  • Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$EnableWebMvcConfiguration': Invocation of init method failed; nested exception is java.lang.IllegalStateException: Found unexpected validator configuration. A Spring Boot MVC validator should be registered as bean named 'mvcValidator' and not returned from WebMvcConfigurer.getValidator()
  • Caused by: java.lang.IllegalStateException: Found unexpected validator configuration. A Spring Boot MVC validator should be registered as bean named 'mvcValidator' and not returned from WebMvcConfigurer.getValidator()

Spring Boot MVC validator は mvcValidator という名前の Bean で登録されているべきなのに、WebMvcConfigurer.getValidator() が返さない、ということのようです。

例外に出力されているソースを追ってみると、org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration.EnableWebMvcConfiguration#afterPropertiesSet でこのメッセージを出力していることが確認できます。getValidator() == null でないと Assert に引っかかります。

f:id:ksby:20170516055744p:plain

getValidator() は org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration#getValidator のことで、以下のコードです。

f:id:ksby:20170516060229p:plain

configurers.getValidator() は org.springframework.web.servlet.config.annotation.WebMvcConfigurerComposite#getValidator のことで、以下のコードです。このメソッドが null を返さないのでエラーになるようですね。

f:id:ksby:20170516060625p:plain

デバッガで確認してみると、確かに null ではなく LocalValidatorFactoryBean を返しています。

f:id:ksby:20170516061605p:plain

f:id:ksby:20170516061206p:plain

自分で実装したコードを見ると、確かに Validator インターフェースの Bean は mvcValidator ではなく validator という名前にしています。

f:id:ksby:20170516062010p:plain

そして validator Bean を ksbysample.webapp.lending.config.WebMvcConfig#getValidator で返しています。

f:id:ksby:20170516062154p:plain

Spring Boot 1.3.x の Web アプリを 1.4.x へバージョンアップする ( その20 )( 気になった点を修正する ) の記事で ValidationMessages_ja_JP.properties をやめて messages.properties に1本化するために書いたものでした。

ここまでの調査から対応方法を考えると、以下のようにすれば良い気がします。

  • ksbysample.webapp.lending.config.WebMvcConfig#getValidator は null を返さないといけないようなので、ksbysample.webapp.lending.config.WebMvcConfig 自体は削除する。
  • validator Bean ではなく mvcValidator Bean にする。

“mvcValidator” で検索してみると org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration.EnableWebMvcConfiguration#mvcValidator に mvcValidator Bean を取得して mvcValidator Bean を生成する?、というよく分からないコードがありました。

f:id:ksby:20170516063841p:plain

Spring Boot 1.4.6 を使用している時のコードに戻してみると、org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration.EnableWebMvcConfiguration#mvcValidator は 1.5.3 と同じでした。

f:id:ksby:20170516070741p:plain

org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration.EnableWebMvcConfiguration#afterPropertiesSet は存在しませんでした。

おそらく 1.4 の頃から mvcValidator という名前の Bean として登録しておけばよいだけで、WebMvcConfigurerAdapter の継承クラスで getValidator メソッドを Override する必要はなかった、のではないかと思います。

上に書いた2点の対応方法で良さそうなので、コードを修正します。

まず src/main/java/ksbysample/webapp/lending/config/WebMvcConfig.java を削除します。

次に src/main/java/ksbysample/webapp/lending/config/ApplicationConfig.javaリンク先の内容 に変更します。

最後に以下のクラスのフィールド private final Validator validator;private final Validator mvcValidator; に変更します。

  • src/main/java/ksbysample/webapp/lending/web/springmvcmemo/BeanValidationGroupController.java
  • src/test/java/ksbysample/webapp/lending/values/validation/ValuesEnumValidatorTest.java

コードを修正したら clean タスク → Rebuild Project → build タスクを実行してみます。今度は “BUILD SUCCESSFUL” が表示されて成功しました。

f:id:ksby:20170517002651p:plain

Project Tool Window の src/test から「Run ‘All Tests’ with Coverage」も実行してみます。こちらも無事全てのテストが成功しました。

f:id:ksby:20170517003210p:plain

Hibernate Validator を使用しているところで messages.properties に記述した日本語のメッセージが使用されるか確認します。

bootRun で Tomcat を起動した後、Hibernate Validator の @NotBlank アノテーションで入力チェックをしている http://localhost:8080/springMvcMemo/beanValidationGroup にアクセスします。

f:id:ksby:20170520143025p:plain

「データ更新」ボタンをクリックすると、日本語のメッセージ「必須の入力項目です。」が表示されました。

f:id:ksby:20170520143232p:plain

mvcValidator Bean をコメントアウトしてから Tomcat を再起動して同じ操作をしてみると、

f:id:ksby:20170520143455p:plain

今度は英語のメッセージが表示されました。mvcValidator Bean を定義するだけで messages.properties の日本語メッセージが使用されるようになるようです。

f:id:ksby:20170520143722p:plain

次回は。。。

1.5 系ではこう書くべきという点があるか確認し、変更した方がよいところを修正します。

ソースコード

ApplicationConfig.java

    @Bean
    public Validator mvcValidator() {
        LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
        localValidatorFactoryBean.setValidationMessageSource(this.messageSource);
        return localValidatorFactoryBean;
    }
  • メソッド名を validatormvcValidator に変更します。

履歴

2017/05/17
初版発行。
2017/05/20
* http://localhost:8080/springMvcMemo/beanValidationGroup での動作確認を追加しました。