1. ホーム
  2. java

[解決済み] JSR 303 バリデーション、あるフィールドが "何か "に等しい場合、他のフィールドはNULLであってはならない

2022-10-20 13:58:19

質問

JSR-303でちょっとしたカスタムバリデーションを行いたいのですが、どうすればよいでしょうか? javax.validation .

私はあるフィールドを持っています。そして、もしある値がこのフィールドに入力された場合、他のいくつかのフィールドが入力されないように要求したいのです。 null .

私はこれを理解しようとしています。説明を見つけるのに役立つように、これを何と呼べばいいのか正確にはわかりません。

どんな助けでも感謝します。私はこのことについてかなり新しいです。

今のところ、私はカスタム制約を考えています。しかし、私はアノテーション内から従属フィールドの値をテストする方法がわかりません。基本的に、私はアノテーションからパネルオブジェクトにアクセスする方法がわかりません。

public class StatusValidator implements ConstraintValidator<NotNull, String> {

    @Override
    public void initialize(NotNull constraintAnnotation) {}

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if ("Canceled".equals(panel.status.getValue())) {
            if (value != null) {
                return true;
            }
        } else {
            return false;
        }
    }
}

これは panel.status.getValue(); であり、これをどのように実現するかは不明です。

どのように解決するのですか?

この場合、カスタムバリデータを作成し、クラスレベルで (オブジェクトのフィールドにアクセスできるように) 別のフィールドが特定の値を持つ場合にのみ、あるフィールドが必須であることを検証することをお勧めします。2 つのフィールド名を取得し、その 2 つのフィールドのみを処理する汎用的なバリデータを書く必要があることに注意しましょう。複数のフィールドを必須とするには、各フィールドにこのバリデータを追加する必要があります。

以下のコードを参考にしてください(未検証)。

  • Validatorインターフェース

    /**
     * Validates that field {@code dependFieldName} is not null if
     * field {@code fieldName} has value {@code fieldValue}.
     **/
    @Target({TYPE, ANNOTATION_TYPE})
    @Retention(RUNTIME)
    @Repeatable(NotNullIfAnotherFieldHasValue.List.class) // only with hibernate-validator >= 6.x
    @Constraint(validatedBy = NotNullIfAnotherFieldHasValueValidator.class)
    @Documented
    public @interface NotNullIfAnotherFieldHasValue {
    
        String fieldName();
        String fieldValue();
        String dependFieldName();
    
        String message() default "{NotNullIfAnotherFieldHasValue.message}";
        Class<?>[] groups() default {};
        Class<? extends Payload>[] payload() default {};
    
        @Target({TYPE, ANNOTATION_TYPE})
        @Retention(RUNTIME)
        @Documented
        @interface List {
            NotNullIfAnotherFieldHasValue[] value();
        }
    
    }
    
    
  • バリデータの実装

    /**
     * Implementation of {@link NotNullIfAnotherFieldHasValue} validator.
     **/
    public class NotNullIfAnotherFieldHasValueValidator
        implements ConstraintValidator<NotNullIfAnotherFieldHasValue, Object> {
    
        private String fieldName;
        private String expectedFieldValue;
        private String dependFieldName;
    
        @Override
        public void initialize(NotNullIfAnotherFieldHasValue annotation) {
            fieldName          = annotation.fieldName();
            expectedFieldValue = annotation.fieldValue();
            dependFieldName    = annotation.dependFieldName();
        }
    
        @Override
        public boolean isValid(Object value, ConstraintValidatorContext ctx) {
    
            if (value == null) {
                return true;
            }
    
            try {
                String fieldValue       = BeanUtils.getProperty(value, fieldName);
                String dependFieldValue = BeanUtils.getProperty(value, dependFieldName);
    
                if (expectedFieldValue.equals(fieldValue) && dependFieldValue == null) {
                    ctx.disableDefaultConstraintViolation();
                    ctx.buildConstraintViolationWithTemplate(ctx.getDefaultConstraintMessageTemplate())
                        .addNode(dependFieldName)
                        .addConstraintViolation();
                        return false;
                }
    
            } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) {
                throw new RuntimeException(ex);
            }
    
            return true;
        }
    
    }
    
    
  • バリデータの使用例(hibernate-validator >= 6とJava 8+)。

    @NotNullIfAnotherFieldHasValue(
        fieldName = "status",
        fieldValue = "Canceled",
        dependFieldName = "fieldOne")
    @NotNullIfAnotherFieldHasValue(
        fieldName = "status",
        fieldValue = "Canceled",
        dependFieldName = "fieldTwo")
    public class SampleBean {
        private String status;
        private String fieldOne;
        private String fieldTwo;
    
        // getters and setters omitted
    }
    
    
  • バリデータの使用例(hibernate-validator < 6;古い例です。)

    @NotNullIfAnotherFieldHasValue.List({
        @NotNullIfAnotherFieldHasValue(
            fieldName = "status",
            fieldValue = "Canceled",
            dependFieldName = "fieldOne"),
        @NotNullIfAnotherFieldHasValue(
            fieldName = "status",
            fieldValue = "Canceled",
            dependFieldName = "fieldTwo")
    })
    public class SampleBean {
        private String status;
        private String fieldOne;
        private String fieldTwo;
    
        // getters and setters omitted
    }
    
    

バリデータの実装では BeanUtils クラスから commons-beanutils ライブラリにありますが BeanWrapperImpl はSpringフレームワークから .

こちらの素晴らしい回答もご覧ください。 Hibernate Validator (JSR 303)によるクロスフィールド検証。