java Primitives के संग्रह की हाइबरनेट मान्य




collections bean-validation (5)

मैं कुछ ऐसा करने में सक्षम होना चाहता हूं:

@Email
public List<String> getEmailAddresses()
{
   return this.emailAddresses;
}

दूसरे शब्दों में, मैं चाहता हूं कि सूची में प्रत्येक आइटम को ईमेल पते के रूप में सत्यापित किया जाए। बेशक, इस तरह के संग्रह को एनोटेट करना स्वीकार्य नहीं है।

क्या इसे करने का कोई तरीका है?


Becomputer06 से महान जवाब के लिए धन्यवाद। लेकिन मुझे लगता है कि निम्नलिखित टिप्पणियां ValidCollection परिभाषा में जोड़ दी जानी चाहिए:

@Target( { ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ValidCollectionValidator.class)

और मैं अभी भी समझ में नहीं आता कि आदिम प्रकार के रैपरों के संग्रह के साथ क्या करना है और @Size, @Min, @Max इत्यादि जैसी टिप्पणियां बाधित हैं, क्योंकि मूल्य becomputer06 के माध्यम से पारित नहीं किया जा सकता है।

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


जावा एनोटेशन की सीमाओं के कारण - किसी भी बाधा एनोटेशन को लपेटने के लिए @EachElement जैसे जेनेरिक रैपर एनोटेशन लिखना संभव नहीं है। हालांकि, आप एक सामान्य बाधा वैधता वर्ग लिख सकते हैं जो प्रत्येक तत्व के वास्तविक सत्यापन को मौजूदा बाधा सत्यापनकर्ता को दर्शाता है। आपको प्रत्येक बाधा के लिए एक रैपर एनोटेशन लिखना है, लेकिन केवल एक वैधकर्ता है।

मैंने इस दृष्टिकोण को jirutka/validator-collection ( jirutka/validator-collection सेंट्रल में उपलब्ध) में लागू किया है। उदाहरण के लिए:

@EachSize(min = 5, max = 255)
List<String> values;

यह लाइब्रेरी आपको प्रत्येक संग्रह के लिए एक अतिरिक्त वैधकर्ता या अनावश्यक रैपर कक्षाओं को लिखने के बिना, सरल प्रकार के संग्रह को एनोटेट करने के लिए किसी भी सत्यापन बाधा के लिए आसानी से "छद्म बाधा" बनाने की अनुमति देती है। EachX बाधा सभी मानक बीन सत्यापन बाधाओं और हाइबरनेट विशिष्ट बाधाओं के लिए समर्थित है।

अपने स्वयं के @Awesome बाधा के लिए @EachAwesome बनाने के लिए, बस एनोटेशन क्लास की प्रतिलिपि बनाएं और पेस्ट करें, @Constraint(validatedBy = CommonEachValidator.class) साथ @Constraint(validatedBy = CommonEachValidator.class) एनोटेशन को प्रतिस्थापित करें और एनोटेशन @EachConstraint(validateAs = Awesome.class) । बस इतना ही!

// common boilerplate
@Documented
@Retention(RUNTIME)
@Target({METHOD, FIELD, ANNOTATION_TYPE})
// this is important!
@EachConstraint(validateAs = Awesome.class)
@Constraint(validatedBy = CommonEachValidator.class)
public @interface EachAwesome {

    // copy&paste all attributes from Awesome annotation here
    String message() default "";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
    String someAttribute();
}

संपादित करें: लाइब्रेरी के वर्तमान संस्करण के लिए अपडेट किया गया।


मेरे पास मूल उत्तर पर टिप्पणी करने के लिए पर्याप्त प्रतिष्ठा नहीं है, लेकिन शायद इस सवाल पर ध्यान देने योग्य है कि JSR-308 अपने अंतिम रिलीज चरण में है और रिलीज होने पर इस समस्या को संबोधित करेगा! हालांकि, कम से कम जावा 8 की आवश्यकता होगी।

एकमात्र अंतर यह होगा कि प्रमाणीकरण एनोटेशन प्रकार की घोषणा के अंदर जाएगा।

//@Email
public List<@Email String> getEmailAddresses()
{
   return this.emailAddresses;
}

कृपया मुझे बताएं कि आप कहां सोचते हैं कि मैं इस जानकारी को दूसरों के लिए सबसे अच्छा लगा सकता हूं। धन्यवाद!

पीएस अधिक जानकारी के लिए, इस एसओ पोस्ट को देखें


एक बहुत ही सरल कामकाज संभव है। आप इसके बजाय अपनी कक्षाओं के संग्रह को मान्य कर सकते हैं जो साधारण मूल्य संपत्ति को लपेटते हैं। इस काम के लिए आपको संग्रह पर @Valid एनोटेशन का उपयोग करने की आवश्यकता है।

उदाहरण:

public class EmailAddress {

  @Email
  String email;

  public EmailAddress(String email){
    this.email = email;
  }
}

public class Foo {

  /* Validation that works */
  @Valid
  List<EmailAddress> getEmailAddresses(){
    return this.emails.stream().map(EmailAddress::new).collect(toList());
  }

}

न तो जेएसआर -303 और न ही हाइबरनेट वैलिडेटर में कोई भी तैयार बाधा है जो संग्रह के प्रत्येक तत्व को मान्य कर सकती है।

इस समस्या को हल करने का एक संभावित समाधान कस्टम @ValidCollection बाधा और संबंधित सत्यापनकर्ता कार्यान्वयन ValidCollectionValidator

संग्रह के प्रत्येक तत्व को प्रमाणित करने के लिए हमें ValidCollectionValidator अंदर Validator का एक उदाहरण ValidCollectionValidator ; और इस तरह के उदाहरण प्राप्त करने के लिए हमें ConstraintValidatorFactory कस्टम कार्यान्वयन की आवश्यकता है।

देखें कि क्या आपको निम्नलिखित समाधान पसंद है ...

सीधे शब्दों में,

  • इन सभी जावा वर्गों की प्रतिलिपि बनाएं (और आयात वर्गों को आयात करें);
  • प्रमाणीकरण-एपीआई, हाइबेनेट-सत्यापनकर्ता, slf4j-log4j12, और classpath पर testng jars जोड़ें;
  • टेस्ट केस चलाएं।

ValidCollection

    public @interface ValidCollection {

    Class<?> elementType();

    /* Specify constraints when collection element type is NOT constrained 
     * validator.getConstraintsForClass(elementType).isBeanConstrained(); */
    Class<?>[] constraints() default {};

    boolean allViolationMessages() default true;

    String message() default "{ValidCollection.message}";

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

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

}

ValidCollectionValidator

    public class ValidCollectionValidator implements ConstraintValidator<ValidCollection, Collection>, ValidatorContextAwareConstraintValidator {

    private static final Logger logger = LoggerFactory.getLogger(ValidCollectionValidator.class);

    private ValidatorContext validatorContext;

    private Class<?> elementType;
    private Class<?>[] constraints;
    private boolean allViolationMessages;

    @Override
    public void setValidatorContext(ValidatorContext validatorContext) {
        this.validatorContext = validatorContext;
    }

    @Override
    public void initialize(ValidCollection constraintAnnotation) {
        elementType = constraintAnnotation.elementType();
        constraints = constraintAnnotation.constraints();
        allViolationMessages = constraintAnnotation.allViolationMessages();
    }

    @Override
    public boolean isValid(Collection collection, ConstraintValidatorContext context) {
        boolean valid = true;

        if(collection == null) {
            //null collection cannot be validated
            return false;
        }

        Validator validator = validatorContext.getValidator();

        boolean beanConstrained = validator.getConstraintsForClass(elementType).isBeanConstrained();

        for(Object element : collection) {
            Set<ConstraintViolation<?>> violations = new HashSet<ConstraintViolation<?>> ();

            if(beanConstrained) {
                boolean hasValidCollectionConstraint = hasValidCollectionConstraint(elementType);
                if(hasValidCollectionConstraint) {
                    // elementType has @ValidCollection constraint
                    violations.addAll(validator.validate(element));
                } else {
                    violations.addAll(validator.validate(element));
                }
            } else {
                for(Class<?> constraint : constraints) {
                    String propertyName = constraint.getSimpleName();
                    propertyName = Introspector.decapitalize(propertyName);
                    violations.addAll(validator.validateValue(CollectionElementBean.class, propertyName, element));
                }
            }

            if(!violations.isEmpty()) {
                valid = false;
            }

            if(allViolationMessages) { //TODO improve
                for(ConstraintViolation<?> violation : violations) {
                    logger.debug(violation.getMessage());
                    ConstraintViolationBuilder violationBuilder = context.buildConstraintViolationWithTemplate(violation.getMessage());
                    violationBuilder.addConstraintViolation();
                }
            }

        }

        return valid;
    }

    private boolean hasValidCollectionConstraint(Class<?> beanType) {
        BeanDescriptor beanDescriptor = validatorContext.getValidator().getConstraintsForClass(beanType);
        boolean isBeanConstrained = beanDescriptor.isBeanConstrained();
        if(!isBeanConstrained) {
            return false;
        }
        Set<ConstraintDescriptor<?>> constraintDescriptors = beanDescriptor.getConstraintDescriptors(); 
        for(ConstraintDescriptor<?> constraintDescriptor : constraintDescriptors) {
            if(constraintDescriptor.getAnnotation().annotationType().getName().equals(ValidCollection.class.getName())) {
                return true;
            }
        }
        Set<PropertyDescriptor> propertyDescriptors = beanDescriptor.getConstrainedProperties();
        for(PropertyDescriptor propertyDescriptor : propertyDescriptors) {
            constraintDescriptors = propertyDescriptor.getConstraintDescriptors();
            for(ConstraintDescriptor<?> constraintDescriptor : constraintDescriptors) {
                if(constraintDescriptor.getAnnotation().annotationType().getName().equals(ValidCollection.class.getName())) {
                    return true;
                }
            }    
        }
        return false;
    }

}

ValidatorContextAwareConstraintValidator

public interface ValidatorContextAwareConstraintValidator {

    void setValidatorContext(ValidatorContext validatorContext);

}

CollectionElementBean

    public class CollectionElementBean {

    /* add more properties on-demand */
    private Object notNull;
    private String notBlank;
    private String email;

    protected CollectionElementBean() {
    }

    @NotNull
    public Object getNotNull() { return notNull; }
    public void setNotNull(Object notNull) { this.notNull = notNull; }

    @NotBlank
    public String getNotBlank() { return notBlank; }
    public void setNotBlank(String notBlank) { this.notBlank = notBlank; }

    @Email
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }

}

ConstraintValidatorFactoryImpl

public class ConstraintValidatorFactoryImpl implements ConstraintValidatorFactory {

    private ValidatorContext validatorContext;

    public ConstraintValidatorFactoryImpl(ValidatorContext nativeValidator) {
        this.validatorContext = nativeValidator;
    }

    @Override
    public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) {
        T instance = null;

        try {
            instance = key.newInstance();
        } catch (Exception e) { 
            // could not instantiate class
            e.printStackTrace();
        }

        if(ValidatorContextAwareConstraintValidator.class.isAssignableFrom(key)) {
            ValidatorContextAwareConstraintValidator validator = (ValidatorContextAwareConstraintValidator) instance;
            validator.setValidatorContext(validatorContext);
        }

        return instance;
    }

}

कर्मचारी

public class Employee {

    private String firstName;
    private String lastName;
    private List<String> emailAddresses;

    @NotNull
    public String getFirstName() { return firstName; }
    public void setFirstName(String firstName) { this.firstName = firstName; }

    public String getLastName() { return lastName; }
    public void setLastName(String lastName) { this.lastName = lastName; }

    @ValidCollection(elementType=String.class, constraints={Email.class})
    public List<String> getEmailAddresses() { return emailAddresses; }
    public void setEmailAddresses(List<String> emailAddresses) { this.emailAddresses = emailAddresses; }

}

टीम

public class Team {

    private String name;
    private Set<Employee> members;

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    @ValidCollection(elementType=Employee.class)
    public Set<Employee> getMembers() { return members; }
    public void setMembers(Set<Employee> members) { this.members = members; }

}

शॉपिंग कार्ट

public class ShoppingCart {

    private List<String> items;

    @ValidCollection(elementType=String.class, constraints={NotBlank.class})
    public List<String> getItems() { return items; }
    public void setItems(List<String> items) { this.items = items; }

}

ValidCollectionTest

public class ValidCollectionTest {

    private static final Logger logger = LoggerFactory.getLogger(ValidCollectionTest.class);

    private ValidatorFactory validatorFactory;

    @BeforeClass
    public void createValidatorFactory() {
        validatorFactory = Validation.buildDefaultValidatorFactory();
    }

    private Validator getValidator() {
        ValidatorContext validatorContext = validatorFactory.usingContext();
        validatorContext.constraintValidatorFactory(new ConstraintValidatorFactoryImpl(validatorContext));
        Validator validator = validatorContext.getValidator();
        return validator;
    }

    @Test
    public void beanConstrained() {
        Employee se = new Employee();
        se.setFirstName("Santiago");
        se.setLastName("Ennis");
        se.setEmailAddresses(new ArrayList<String> ());
        se.getEmailAddresses().add("segmail.com");
        Employee me = new Employee();
        me.setEmailAddresses(new ArrayList<String> ());
        me.getEmailAddresses().add("[email protected]");

        Team team = new Team();
        team.setMembers(new HashSet<Employee>());
        team.getMembers().add(se);
        team.getMembers().add(me);

        Validator validator = getValidator();

        Set<ConstraintViolation<Team>> violations = validator.validate(team);
        for(ConstraintViolation<Team> violation : violations) {
            logger.info(violation.getMessage());
        }
    }

    @Test
    public void beanNotConstrained() {
        ShoppingCart cart = new ShoppingCart();
        cart.setItems(new ArrayList<String> ());
        cart.getItems().add("JSR-303 Book");
        cart.getItems().add("");

        Validator validator = getValidator();

        Set<ConstraintViolation<ShoppingCart>> violations = validator.validate(cart, Default.class);
        for(ConstraintViolation<ShoppingCart> violation : violations) {
            logger.info(violation.getMessage());
        }
    }

}

उत्पादन

02:16:37,581  INFO main validation.ValidCollectionTest:66 - {ValidCollection.message}
02:16:38,303  INFO main validation.ValidCollectionTest:66 - may not be null
02:16:39,092  INFO main validation.ValidCollectionTest:66 - not a well-formed email address

02:17:46,460  INFO main validation.ValidCollectionTest:81 - may not be empty
02:17:47,064  INFO main validation.ValidCollectionTest:81 - {ValidCollection.message}

नोट: - जब बीन की बाधाएं होती हैं तो @ValidCollection बाधा की constraints निर्दिष्ट नहीं करते हैं। बीन की कोई बाधा नहीं होने पर constraints विशेषता जरूरी है।





hibernate-validator