web-dev-qa-db-ja.com

Autowiredがカスタム制約バリデーターにNull値を与える

私は完全にSpringを使い始めたばかりで、SOについての質問に対していくつかの回答を調べました。ここにリンクがあります:

Spring 3.1自動配線はカスタム制約バリデーター内では機能しません

サービスをバリデーターに自動配線する

Autowiredリポジトリがカスタム制約バリデーターでNull

オブジェクトの検証にHibernate Validatorを使用したいSpringプロジェクトがあります。オンラインで読んだ内容といくつかのフォーラムに基づいて、次のようにバリデーターを挿入しようとしました:

@Bean
  public Validator validator() {
    return new LocalValidatorFactoryBean().getValidator();
  }

しかし、私が使用していたところはどこでも

@Autowired
Validator validator;

Hibernateのバリデーターの代わりに、Springのバリデーター実装を使用していました。 Hibernateバリデーターを正確に挿入する方法がわからなかったため、他のクラスに単純にAutowireするため、安価なトリックを使用しましたが、Java Configは次のようになります

@Bean
      public Validator validator() {
        // ValidatorImpl is Hibernate's implementation of the Validator
        return new ValidatorImpl();
      }

このハッキーな方法でHibernate Validatorを取得しないようにする方法について、誰かが実際に私に正しい方向を示すことができれば私は本当に感謝します

しかし、ここで主要な問題に行きましょう:

これはカスタム検証定義です

@Target( { METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER } )
@Retention(RUNTIME)
@Constraint(validatedBy = EmployeeValidator.class)
@Documented
public @interface EmployeeValidation {
String message() default "{constraints.employeeConstraints}";
public abstract Class<?>[] groups() default {};
public abstract Class<? extends Payload>[] payload() default {};
}

私のカスタムバリデーター

public class EmployeeValidator implements ConstraintValidator<EmployeeValidation , Object> {

@Autowired
private EmployeeService employeeService;

@Override
public void initialize(EmployeeValidation constraintAnnotation) {
//do Something
 }

@Override
public boolean isValid(String type, ConstraintValidatorContext context) {
    return false;
}
}

上記のカスタム制約バリデーターでは、employeeServiceをnullにしています。 Springの起動時にConstraintValidatorの実装がインスタンス化されないことは知っていますが、ValidatorImpl()を追加すると実際に修正されると思いました。しかし、そうではありませんでした。

今、私は本当にハックな回避策で立ち往生しており、そのようなコードを続行したくありません。誰かが私の状況を助けてくれますか?.

追伸これらは、Java構成ファイル内の私のインポートです。

import org.hibernate.validator.HibernateValidator; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.context.MessageSource; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.ComponentScan; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.context.annotation.PropertySource; 
import org.springframework.context.support.ReloadableResourceBundleMessageSource; 
import org.springframework.core.env.Environment; 
import org.springframework.validation.Validator; 
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; 
import org.springframework.web.servlet.LocaleResolver; 
import org.springframework.web.servlet.ViewResolver; 
import org.springframework.web.servlet.config.annotation.EnableWebMvc; 
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; 
import org.springframework.web.servlet.i18n.CookieLocaleResolver; 
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; 
import org.springframework.web.servlet.view.InternalResourceViewResolver; 
14
Nick Div

私は解決策が誰かを助けることを願っています:

@Bean
public Validator validator () {

    ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
        .configure().constraintValidatorFactory(new SpringConstraintValidatorFactory(autowireCapableBeanFactory))
        .buildValidatorFactory();
    Validator validator = validatorFactory.getValidator();

    return validator;
}

インジェクションが機能するようにSpringConstraintValidatorFactoryを使用してバリデーターを初期化し、バリデーター実装をHibernate.classとして提供すると、次のように機能します。

  1. オブジェクトは、選択したライブラリによって検証されます
  2. カスタムバリデーターは、Hibernateで検証を実行しながら、Springの機能を使用できます。

動作方法:HibernateのConstraintValidatorFactoryは、呼び出されない限りConstraintValidatorsを初期化しませんが、SpringConstraintValidatorFactoryAutowireCapableBeanFactoryを指定して初期化します。

[〜#〜]編集[〜#〜]

@shabyasaschiのコメントの1つで述べたように、autowireCapableBeanFactoryを挿入するには、メソッドのシグネチャを次のように変更します。

Validator validator(final AutowireCapableBeanFactory autowireCapableBeanFactory) {

または、次のように設定ファイルにgetterとsetterを追加します。

public AutowireCapableBeanFactory getAutowireCapableBeanFactory() {
        return autowireCapableBeanFactory;
}

public void setAutowireCapableBeanFactory(AutowireCapableBeanFactory autowireCapableBeanFactory) {
        this.autowireCapableBeanFactory = autowireCapableBeanFactory;
}
18
Nick Div

これは2つのアプローチで修正できます。

  • Springを使用してバリデーターにサービスを注入してみてください。

  • Validatorのinitializeメソッドをオーバーライドして、手動で初期化します。

私は同じ時間前に同じ問題を抱えていましたが、最後に、大量の問題を回避するために2番目のオプションを使用することにしました。

あなたが指摘するように、あなたはあなたのバリデーターで1つの初期化メソッドを定義する必要があり、そこでServiceUtilsを使用して必要なサービスBeanを取得することができます:

@Autowired
private EmployeeService employeeService;

@Override
public void initialize(EmployeeValidation constraintAnnotation) {
  //Use an utility service to get Spring beans
  employeeService = ServiceUtils.getEmployeeService();
}

また、ServiceUtilsは、静的メソッドで使用される自身への静的参照を持つ通常のSpring Beanです。

@Component
public class ServiceUtils {
  private static ServiceUtils instance;

  @Autowired
  private EmployeeService employeeService;

  /* Post constructor */

  @PostConstruct
  public void fillInstance() {
    instance = this;
  }

  /*static methods */

  public static EmployeeService getEmployeeService) {
    return instance.employeeService;
  }
}

したがって、Springを使用して必要なサービスを注入していますが、通常の方法ではありません。お役に立てれば。

2
Ricardo Vila

あなたの豆の定義で

@Bean
public Validator validator() {
    return new LocalValidatorFactoryBean().getValidator();
}

メソッド定義のValidatorのタイプは何ですか? Springからjavax.validation.ValidatornotValidatorが返されることを確認してください。

Spring bootstrapバリデーターを許可すると、SpringConstraintValidatorFactoryがHibernate Validatorに渡され、制約バリデーター内での依存性注入が可能になります。

2
Gunnar

それは私のために働いた。現在検索している人のために

public class EmployeeValidator implements ConstraintValidator<EmployeeValidation , Object> {


    private EmployeeService employeeService;

    public EmployeeValidator(EmployeeService employeeService){
        this.employeeService = employeeService;
    }

    ...
}
0
ykembayev