java - जेएसआर 303 प्रमाणीकरण, यदि एक फ़ील्ड "कुछ" के बराबर है, तो इन अन्य क्षेत्रों को शून्य नहीं होना चाहिए




validation bean-validation (4)

मैं JSR-303 javax.validation साथ थोड़ा कस्टम सत्यापन करना चाहता 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();panel.status.getValue(); मुझे परेशानी दे रही है .. यह सुनिश्चित नहीं है कि इसे कैसे पूरा किया जाए।


आपको कस्टम DefaultGroupSequenceProvider<T> का उपयोग करना चाहिए:

ConditionalValidation.java

// Marker interface
public interface ConditionalValidation {}

MyCustomFormSequenceProvider.java

public class MyCustomFormSequenceProvider
    implements DefaultGroupSequenceProvider<MyCustomForm> {

    @Override
    public List<Class<?>> getValidationGroups(MyCustomForm myCustomForm) {

        List<Class<?>> sequence = new ArrayList<>();

        // Apply all validation rules from ConditionalValidation group
        // only if someField has given value
        if ("some value".equals(myCustomForm.getSomeField())) {
            sequence.add(ConditionalValidation.class);
        }

        // Apply all validation rules from default group
        sequence.add(MyCustomForm.class);

        return sequence;
    }
}

MyCustomForm.java

@GroupSequenceProvider(MyCustomFormSequenceProvider.class)
public class MyCustomForm {

    private String someField;

    @NotEmpty(groups = ConditionalValidation.class)
    private String fieldTwo;

    @NotEmpty(groups = ConditionalValidation.class)
    private String fieldThree;

    @NotEmpty
    private String fieldAlwaysValidated;


    // getters, setters omitted
}

इस विषय पर भी संबंधित प्रश्न देखें।


इस मामले में मैं कस्टम सत्यापनकर्ता लिखने का सुझाव देता हूं, जो कक्षा स्तर पर मान्य होगा (हमें ऑब्जेक्ट के फ़ील्ड तक पहुंच प्राप्त करने की अनुमति देने के लिए) कि एक फ़ील्ड केवल तभी जरूरी है जब किसी अन्य फ़ील्ड का विशेष मूल्य हो। ध्यान दें कि आपको सामान्य सत्यापनकर्ता लिखना चाहिए जो 2 फ़ील्ड नाम प्राप्त करता है और केवल इन 2 फ़ील्ड के साथ काम करता है। एक से अधिक फ़ील्ड की आवश्यकता के लिए आपको प्रत्येक फ़ील्ड के लिए यह सत्यापनकर्ता जोड़ना चाहिए।

निम्नलिखित कोड का उपयोग एक विचार के रूप में करें (मैंने इसका परीक्षण नहीं किया है)।

  • वैलिडेटर इंटरफ़ेस

    /**
     * Validates that field {@code dependFieldName} is not null if
     * field {@code fieldName} has value {@code fieldValue}.
     **/
    @Target({TYPE, ANNOTATION_TYPE})
    @Retention(RUNTIME)
    @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;
        }
    
    }
    
  • सत्यापनकर्ता उदाहरण उदाहरण

    @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
    }
    

ध्यान दें कि सत्यापनकर्ता कार्यान्वयन commons-beanutils लाइब्रेरी commons-beanutils क्लास का उपयोग करता है लेकिन आप स्प्रिंग फ्रेमवर्क से BeanWrapperImpl भी उपयोग कर सकते हैं।

यह भी महान उत्तर देखें: हाइबरनेट वैलिडेटर (जेएसआर 303) के साथ क्रॉस फील्ड सत्यापन


यहां मेरा ले लिया गया है, इसे यथासंभव सरल रखने की कोशिश की।

अंतरपटल:

@Target({TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = OneOfValidator.class)
@Documented
public @interface OneOf {

    String message() default "{one.of.message}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    String[] value();
}

प्रमाणीकरण कार्यान्वयन:

public class OneOfValidator implements ConstraintValidator<OneOf, Object> {

    private String[] fields;

    @Override
    public void initialize(OneOf annotation) {
        this.fields = annotation.value();
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {

        BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(value);

        int matches = countNumberOfMatches(wrapper);

        if (matches > 1) {
            setValidationErrorMessage(context, "one.of.too.many.matches.message");
            return false;
        } else if (matches == 0) {
            setValidationErrorMessage(context, "one.of.no.matches.message");
            return false;
        }

        return true;
    }

    private int countNumberOfMatches(BeanWrapper wrapper) {
        int matches = 0;
        for (String field : fields) {
            Object value = wrapper.getPropertyValue(field);
            boolean isPresent = detectOptionalValue(value);

            if (value != null && isPresent) {
                matches++;
            }
        }
        return matches;
    }

    private boolean detectOptionalValue(Object value) {
        if (value instanceof Optional) {
            return ((Optional) value).isPresent();
        }
        return true;
    }

    private void setValidationErrorMessage(ConstraintValidatorContext context, String template) {
        context.disableDefaultConstraintViolation();
        context
            .buildConstraintViolationWithTemplate("{" + template + "}")
            .addConstraintViolation();
    }

}

उपयोग:

@OneOf({"stateType", "modeType"})
public class OneOfValidatorTestClass {

    private StateType stateType;

    private ModeType modeType;

}

संदेश:

one.of.too.many.matches.message=Only one of the following fields can be specified: {value}
one.of.no.matches.message=Exactly one of the following fields must be specified: {value}

विधि को परिभाषित करें जो सत्य पर मान्य होना चाहिए और इसके शीर्ष पर @AssertTrue एनोटेशन @AssertTrue चाहिए:

  @AssertTrue
  private boolean isOk() {
    return someField != something || otherField != null;
  }

विधि 'है' के साथ शुरू होनी चाहिए।







bean-validation