17
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

Spring BootでカスタムValidatorにInjectionしたい時の設定

以下のようにコンテナからInjectionされた値(Bean)を使ったカスタムValidatorがあったとする。

MyConstraintValidator.java
/**
 * コンテナで"hoge"に登録された文字列と一致するか検証する。
 */
public class MyConstraintValidator implements ConstraintValidator<MyConstraint, String> {
    @Autowired
    private String hoge;
    @Override
    public void initialize(MyConstraint paramA) {
    }
    @Override
    public boolean isValid(String value, ConstraintValidatorContext paramConstraintValidatorContext) {
        Objects.requireNonNull(hoge);
        return Objects.equals(value, hoge);
    }
}

このValidatorにInjectionして使うには、Springのドキュメントでここらへんを見ると以下のような設定が必要になる。

<bean id="validator"
    class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>

@Configurationなクラスで設定する場合はこうなる。

@Bean
public javax.validation.Validator localValidatorFactoryBean() {
   return new LocalValidatorFactoryBean();
}

コントローラでバリデーションする場合なんかには上記だけでも良いが、Hibernateで使う場合には以下の設定でEntityManagerFactoryにValidatorの参照を渡す必要がある。
http://stackoverflow.com/questions/2712345/jsr-303-dependency-injection-and-hibernate

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
 <property name="jpaPropertyMap">
  <map>
   <entry key="javax.persistence.validation.factory" value-ref="validator" />               
  </map>
 </property>
</bean>

これをSpring Bootで設定する場合、SpringBootのドキュメントでここを見るとapplication.propertiesでspring.jpa.properties.*にJPAプロパティを指定すればいいのだがなんか嫌な予感。。。

application.properties
spring.jpa.properties.javax.persistence.validation.factory=validator

これでは"validator"という文字列を設定しているだけなのでエラーになってしまう。試しにクラス名を指定してみてもダメ。

Caused by: org.hibernate.cfg.beanvalidation.IntegrationException: Given object was not an instance of javax.validation.ValidatorFactory[java.lang.String]

Beanの参照を設定するにはプロパティファイルではだめぽなので@Configurationなクラスで設定するしかなさそう。

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
            EntityManagerFactoryBuilder builder, DataSource dataSource, JpaProperties jpaProperties) {

        LocalContainerEntityManagerFactoryBean factory = builder
                .dataSource(dataSource)
                .packages(Application.class)
                .persistenceUnit("default")
                .properties(jpaProperties.getHibernateProperties(dataSource))
                .build();

        Map<String, Object> jpaPropertyMap = new HashMap<>();
        jpaPropertyMap.put("javax.persistence.validation.factory", validator());
        factory.setJpaPropertyMap(jpaPropertyMap);
        return factory;
    }

LocalContainerEntityManagerFactoryBeanの生成部分はJpaBaseConfiguration.entityManagerFactory()のソースを参考にした。

やりたい事はjpaPropertyMap.put("javax.persistence.validation.factory", validator();の1行だけなんだけど、もっといいやり方はないんだろうか?

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
17
Help us understand the problem. What are the problem?