web-dev-qa-db-ja.com

javax.validation.constraintsからの注釈が機能しない

javax.validation.constraints@Sizeなどの@NotNullからの注釈を使用するには、どのような構成が必要ですか?ここに私のコードがあります:

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

public class Person {
      @NotNull
      private String id;

      @Size(max = 3)
      private String name;

      private int age;

      public Person(String id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
      }
}

別のクラスで使用しようとすると、検証が機能しません(つまり、オブジェクトはエラーなしで作成されます):

Person P = new Person(null, "Richard3", 8229));

なぜこれはidnameの制約を適用しないのですか?他に何をする必要がありますか?

45
Darshan Patil

JSR-303 Bean検証をSpringで機能させるには、次のものが必要です。

  1. 注釈のMVC名前空間の構成:<mvc:annotation-driven />
  2. JSR-303仕様JAR:validation-api-1.0.0.GA.jar(既にお持ちのようです)
  3. Hibernate Validationなど、最も一般的に使用される例のように見える仕様の実装:hibernate-validator-4.1.0.Final.jar
  4. 検証するBeanで、仕様JARまたは実装JAR(既に実行済み)からの検証アノテーション
  5. 検証するハンドラーで、検証するオブジェクトに@Valid注釈を付けてから、メソッドシグネチャにBindingResultを含めてエラーをキャプチャします。

例:

@RequestMapping("handler.do")
public String myHandler(@Valid @ModelAttribute("form") SomeFormBean myForm, BindingResult result, Model model) {
    if(result.hasErrors()) {
      ...your error handling...
    } else {
      ...your non-error handling....
    }
}
50
atrain

Validatorを使用して、クラスが有効かどうかを確認する必要があります。

Person person = ....;
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
Set<ConstraintViolation<Person>> violations = validator.validate(person);

次に、違反セットを繰り返し、違反を見つけることができます。

28
Artem

Validatorを呼び出す必要があります検証する場合はエンティティです。その後、ConstraintViolationExceptionのセットを取得します。これは基本的にエンティティのどのフィールドに制約違反があり、正確に何であったかを表示です。エンティティを検証する予定のコードの一部を共有することもできます。

頻繁に使用される手法は、トランザクション中に複数のデータ変更を使用する場合に@PrePersistで検証を行い、トランザクションをロールバックするか、検証例外を取得したときに他のアクションを実行することです。

コードは次のようになります。

@PrePersist
public void prePersist(SomeEntity someEntity){
    Validator validator = Validation.buildDefaultValidatorFactory.getValidator();
    Set<ConstraintViolation<SomeEntity>> = validator.validate(someEntity);
    //do stuff with them, like notify client what was the wrong field, log them, or, if empty, be happy
}
5
Nikola Yovchev

また、@NonNulllombokライブラリと一緒に使用することもできます、少なくともfor @NotNullシナリオ。詳細: https://projectlombok.org/api/lombok/NonNull.html

4

私の場合、呼び出されていないカスタムクラスレベルの制約がありました。

@CustomValidation // not called
public class MyClass {
    @Lob
    @Column(nullable = false)
    private String name;
}

クラスまたはフィールドレベルの制約をカスタムクラスまたは標準クラスに追加するとすぐに、クラスレベルの制約が機能し始めました。

@CustomValidation // now it works. super.
public class MyClass {
    @Lob
    @Column(nullable = false)
    @NotBlank // adding this made @CustomValidation start working
    private String name;
}

私にはバグのある行動のようですが、回避するには十分簡単です

1
ChetPrickles

数年後にここに来て、 atrain上記のコメント のおかげで修正できました。私の場合、[〜#〜] api [〜#〜]@Validがありませんでした。 @Sizeの注釈が付けられています。問題を解決しました。

私は、not@Valid@NotBlankなどの追加の注釈を、@Sizeで注釈された変数に追加する必要がありました。変数と私がAPIで言及したこと...

Pojoクラス:

...
@Size(min = MIN_LENGTH, max = MAX_LENGTH);
private String exampleVar;
...

APIクラス:

...
public void exampleApiCall(@RequestBody @Valid PojoObject pojoObject){
  ...
}

感謝と歓声

1
xCovelus

メソッドパラメータには、Objects.requireNonNull()を次のように使用できます。test(String str) { Objects.requireNonNull(str); }ただし、これは実行時にのみチェックされ、nullの場合はNPEをスローします。これは前提条件チェックのようなものです。しかし、それはあなたが探しているものかもしれません。

0
Edward

したがって、サービスインターフェイスの@Validは、そのオブジェクトに対してのみ機能します。 ServiceRequestオブジェクトの階層内にさらに検証がある場合、明示的に検証をトリガーすることができます。だからこれは私がそれをやった方法です:

public class ServiceRequestValidator {

      private static Validator validator;

      @PostConstruct
      public void init(){
         validator = Validation.buildDefaultValidatorFactory().getValidator();
      }

      public static <T> void validate(T t){
        Set<ConstraintViolation<T>> errors = validator.validate(t);
        if(CollectionUtils.isNotEmpty(errors)){
          throw new ConstraintViolationException(errors);
        }
     }

}

そのオブジェクトの検証をトリガーする場合は、オブジェクトレベルで次の注釈が必要です。

@Valid
@NotNull
0
Akshay

@ Valid各メンバー変数に追加する必要があります。検証制約。

0
Chad

atrainからのすばらしい答えですが、例外をキャッチするためのより良い解決策は、独自のHandlerExceptionResolverとcatchを利用することです。

@Override
public ModelAndView resolveException(
    HttpServletRequest aReq, 
    HttpServletResponse aRes,
    Object aHandler, 
    Exception anExc
){
    // ....
    if(anExc instanceof MethodArgumentNotValidException) // do your handle     error here
}

その後、ハンドラーを可能な限りクリーンに保つことができます。 myHandlerMethodのBindingResult、Model、SomeFormBeanはもう必要ありません。

0
PavelP