Return-Path: Delivered-To: apmail-incubator-bval-commits-archive@minotaur.apache.org Received: (qmail 84677 invoked from network); 3 Sep 2010 16:23:03 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 3 Sep 2010 16:23:03 -0000 Received: (qmail 49475 invoked by uid 500); 3 Sep 2010 16:23:03 -0000 Delivered-To: apmail-incubator-bval-commits-archive@incubator.apache.org Received: (qmail 49440 invoked by uid 500); 3 Sep 2010 16:23:03 -0000 Mailing-List: contact bval-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: bval-dev@incubator.apache.org Delivered-To: mailing list bval-commits@incubator.apache.org Received: (qmail 49433 invoked by uid 99); 3 Sep 2010 16:23:03 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 03 Sep 2010 16:23:03 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 03 Sep 2010 16:23:00 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 8010C2388A1C; Fri, 3 Sep 2010 16:22:37 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r992353 - /incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/ClassValidator.java Date: Fri, 03 Sep 2010 16:22:37 -0000 To: bval-commits@incubator.apache.org From: mbenson@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100903162237.8010C2388A1C@eris.apache.org> Author: mbenson Date: Fri Sep 3 16:22:37 2010 New Revision: 992353 URL: http://svn.apache.org/viewvc?rev=992353&view=rev Log: run formatter Modified: incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/ClassValidator.java Modified: incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/ClassValidator.java URL: http://svn.apache.org/viewvc/incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/ClassValidator.java?rev=992353&r1=992352&r2=992353&view=diff ============================================================================== --- incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/ClassValidator.java (original) +++ incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/ClassValidator.java Fri Sep 3 16:22:37 2010 @@ -18,7 +18,6 @@ */ package org.apache.bval.jsr303; - import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; @@ -43,7 +42,6 @@ import org.apache.bval.util.AccessStrate import org.apache.bval.util.ValidationHelper; import org.apache.commons.lang.ClassUtils; - // TODO: centralize treatMapsLikeBeans /** @@ -55,668 +53,719 @@ import org.apache.commons.lang.ClassUtil * API class * * @author Roman Stumm - * @author Carlos Vara - *
+ * @author Carlos Vara
*/ public class ClassValidator implements Validator { - /** - * {@link ApacheFactoryContext} used - */ - protected final ApacheFactoryContext factoryContext; - /** - * {@link GroupsComputer} used - */ - protected final GroupsComputer groupsComputer = new GroupsComputer(); - - /** - * Create a new ClassValidator instance. - * @param factoryContext - */ - public ClassValidator(ApacheFactoryContext factoryContext) { - this.factoryContext = factoryContext; - } - - /** - * Create a new ClassValidator instance. - * @param factory - * @deprecated provided for backward compatibility - */ - public ClassValidator(ApacheValidatorFactory factory) { - this(factory.usingContext()); - } - - /** - * Get the metabean finder associated with this validator. - * - * @return a MetaBeanFinder - * @see org.apache.bval.MetaBeanManagerFactory#getFinder() - */ - public MetaBeanFinder getMetaBeanFinder() { - return factoryContext.getMetaBeanFinder(); - } - - // Validator implementation -------------------------------------------------- - - /** - * {@inheritDoc} - * Validates all constraints on object. - * - * @param object - * object to validate - * @param groups - * group or list of groups targeted for validation - * (default to {@link javax.validation.groups.Default}) - * - * @return constraint violations or an empty Set if none - * - * @throws IllegalArgumentException - * if object is null - * or if null is passed to the varargs groups - * @throws ValidationException - * if a non recoverable error happens - * during the validation process - */ - // @Override - not allowed in 1.5 for Interface methods - @SuppressWarnings("unchecked") - public Set> validate(T object, Class... groups) { - if (object == null) throw new IllegalArgumentException("cannot validate null"); - checkGroups(groups); - - try { - - Class objectClass = (Class) object.getClass(); - MetaBean objectMetaBean = factoryContext.getMetaBeanFinder().findForClass(objectClass); - - final GroupValidationContext context = - createContext(objectMetaBean, object, objectClass, groups); - final ConstraintValidationListener result = context.getListener(); - final Groups sequence = context.getGroups(); - - // 1. process groups - for (Group current : sequence.getGroups()) { - context.setCurrentGroup(current); - validateBeanNet(context); - } - - // 2. process sequences - for (List eachSeq : sequence.getSequences()) { - for (Group current : eachSeq) { - context.setCurrentGroup(current); - validateBeanNet(context); - // if one of the group process in the sequence leads to one or more validation failure, - // the groups following in the sequence must not be processed - if (!result.isEmpty()) break; - } - if (!result.isEmpty()) break; - } - return result.getConstraintViolations(); - } catch (RuntimeException ex) { - throw unrecoverableValidationError(ex, object); - } - } - - /** - * {@inheritDoc} - * Validates all constraints placed on the property of object - * named propertyName. - * - * @param object - * object to validate - * @param propertyName - * property to validate (ie field and getter constraints). Nested - * properties may be referenced (e.g. prop[2].subpropA.subpropB) - * @param groups - * group or list of groups targeted for validation - * (default to {@link javax.validation.groups.Default}) - * - * @return constraint violations or an empty Set if none - * - * @throws IllegalArgumentException - * if object is null, - * if propertyName null, empty or not a valid - * object property - * or if null is passed to the varargs groups - * @throws ValidationException - * if a non recoverable error happens - * during the validation process - */ - // @Override - not allowed in 1.5 for Interface methods - @SuppressWarnings("unchecked") - public Set> validateProperty(T object, String propertyName, - Class... groups) { - if (object == null) throw new IllegalArgumentException("cannot validate null"); - - checkPropertyName(propertyName); - checkGroups(groups); - - try { - - Class objectClass = (Class) object.getClass(); - MetaBean objectMetaBean = factoryContext.getMetaBeanFinder().findForClass(objectClass); - - GroupValidationContext context = - createContext(objectMetaBean, object, objectClass, groups); - ConstraintValidationListener result = context.getListener(); - NestedMetaProperty nestedProp = getNestedProperty(objectMetaBean, object, propertyName); - context.setMetaProperty(nestedProp.getMetaProperty()); - if (nestedProp.isNested()) { - context.setFixedValue(nestedProp.getValue()); - } - if (context.getMetaProperty() == null) throw new IllegalArgumentException( - "Unknown property " + object.getClass().getName() + "." + propertyName); - Groups sequence = context.getGroups(); - - // 1. process groups - for (Group current : sequence.getGroups()) { - context.setCurrentGroup(current); - validatePropertyInGroup(context); - } - - // 2. process sequences - for (List eachSeq : sequence.getSequences()) { - for (Group current : eachSeq) { - context.setCurrentGroup(current); - validatePropertyInGroup(context); - /** - * if one of the group process in the sequence leads to one or more validation failure, - * the groups following in the sequence must not be processed - */ - if (!result.isEmpty()) break; - } - if (!result.isEmpty()) break; - } - return result.getConstraintViolations(); - } catch (RuntimeException ex) { - throw unrecoverableValidationError(ex, object); - } - } - - /** - * {@inheritDoc} - * Validates all constraints placed on the property named - * propertyName of the class beanType would the - * property value be value - *

- * ConstraintViolation objects return null for - * {@link ConstraintViolation#getRootBean()} and - * {@link ConstraintViolation#getLeafBean()} - * - * @param beanType - * the bean type - * @param propertyName - * property to validate - * @param value - * property value to validate - * @param groups - * group or list of groups targeted for validation - * (default to {@link javax.validation.groups.Default}) - * - * @return constraint violations or an empty Set if none - * - * @throws IllegalArgumentException - * if beanType is null, - * if propertyName null, empty or not a valid - * object property - * or if null is passed to the varargs groups - * @throws ValidationException - * if a non recoverable error happens - * during the validation process - */ - // @Override - not allowed in 1.5 for Interface methods - public Set> validateValue(Class beanType, - String propertyName, Object value, - Class... groups) { - - checkBeanType(beanType); - checkPropertyName(propertyName); - checkGroups(groups); - - try { - MetaBean metaBean = factoryContext.getMetaBeanFinder().findForClass(beanType); - GroupValidationContext context = - createContext(metaBean, null, beanType, groups); - ConstraintValidationListener result = context.getListener(); - context.setMetaProperty( - getNestedProperty(metaBean, null, propertyName).getMetaProperty()); - context.setFixedValue(value); - Groups sequence = context.getGroups(); - - // 1. process groups - for (Group current : sequence.getGroups()) { - context.setCurrentGroup(current); - validatePropertyInGroup(context); - } - // 2. process sequences - for (List eachSeq : sequence.getSequences()) { - for (Group current : eachSeq) { - context.setCurrentGroup(current); - validatePropertyInGroup(context); - // if one of the group process in the sequence leads to one or more validation failure, - // the groups following in the sequence must not be processed - if (!result.isEmpty()) break; - } - if (!result.isEmpty()) break; - } - return result.getConstraintViolations(); - } catch (RuntimeException ex) { - throw unrecoverableValidationError(ex, value); - } - } - - /** - * {@inheritDoc} - * Return the descriptor object describing bean constraints. - * The returned object (and associated objects including - * ConstraintDescriptors) are immutable. - * - * @param clazz - * class or interface type evaluated - * - * @return the bean descriptor for the specified class. - * - * @throws IllegalArgumentException - * if clazz is null - * @throws ValidationException - * if a non recoverable error happens - * during the metadata discovery or if some - * constraints are invalid. - */ - // @Override - not allowed in 1.5 for Interface methods - public BeanDescriptor getConstraintsForClass(Class clazz) { - if (clazz == null) { - throw new IllegalArgumentException("Class cannot be null"); - } - try { - MetaBean metaBean = factoryContext.getMetaBeanFinder().findForClass(clazz); - BeanDescriptorImpl edesc = - metaBean.getFeature(Jsr303Features.Bean.BEAN_DESCRIPTOR); - if (edesc == null) { - edesc = createBeanDescriptor(metaBean); - metaBean.putFeature(Jsr303Features.Bean.BEAN_DESCRIPTOR, edesc); - } - return edesc; - } catch (RuntimeException ex) { - throw new ValidationException("error retrieving constraints for " + clazz, ex); - } - } - - /** - * {@inheritDoc} - * Return an instance of the specified type allowing access to - * provider-specific APIs. If the Bean Validation provider - * implementation does not support the specified class, - * ValidationException is thrown. - * - * @param type - * the class of the object to be returned. - * - * @return an instance of the specified class - * - * @throws ValidationException - * if the provider does not support the call. - */ - // @Override - not allowed in 1.5 for Interface methods - public T unwrap(Class type) { - if (type.isAssignableFrom(getClass())) { - @SuppressWarnings("unchecked") - final T result = (T) this; - return result; - } else if (!(type.isInterface() || Modifier.isAbstract(type.getModifiers()))) { - return SecureActions.newInstance(type, new Class[]{ApacheFactoryContext.class}, - new Object[]{factoryContext}); - } else { - try { - Class cls = ClassUtils.getClass(type.getName() + "Impl"); - if (type.isAssignableFrom(cls)) { - @SuppressWarnings("unchecked") - final Class implClass = (Class) cls; - return SecureActions.newInstance(implClass, - new Class[]{ApacheFactoryContext.class}, new Object[]{factoryContext}); - } - } catch (ClassNotFoundException e) { - } - throw new ValidationException("Type " + type + " not supported"); - } - } - - - // Helpers ------------------------------------------------------------------- - - /** - * Validates a bean and all its cascaded related beans for the currently - * defined group. - *

- * Special code is present to manage the {@link Default} group. - * - * @param validationContext - * The current context of this validation call. Must have its - * {@link GroupValidationContext#getCurrentGroup()} field set. - */ - protected void validateBeanNet(GroupValidationContext context) { - - // If reached a cascaded bean which is null - if (context.getBean() == null) { - return; - } - - // If reached a cascaded bean which has already been validated for the current group - if (!context.collectValidated()) { - return; - } - - - // ### First, validate the bean - - // Default is a special case - if (context.getCurrentGroup().isDefault()) { - - List defaultGroups = expandDefaultGroup(context); - final ConstraintValidationListener result = (ConstraintValidationListener) context.getListener(); + /** + * {@link ApacheFactoryContext} used + */ + protected final ApacheFactoryContext factoryContext; + /** + * {@link GroupsComputer} used + */ + protected final GroupsComputer groupsComputer = new GroupsComputer(); + + /** + * Create a new ClassValidator instance. + * + * @param factoryContext + */ + public ClassValidator(ApacheFactoryContext factoryContext) { + this.factoryContext = factoryContext; + } + + /** + * Create a new ClassValidator instance. + * + * @param factory + * @deprecated provided for backward compatibility + */ + public ClassValidator(ApacheValidatorFactory factory) { + this(factory.usingContext()); + } + + /** + * Get the metabean finder associated with this validator. + * + * @return a MetaBeanFinder + * @see org.apache.bval.MetaBeanManagerFactory#getFinder() + */ + public MetaBeanFinder getMetaBeanFinder() { + return factoryContext.getMetaBeanFinder(); + } + + // Validator implementation + // -------------------------------------------------- + + /** + * {@inheritDoc} Validates all constraints on object. + * + * @param object + * object to validate + * @param groups + * group or list of groups targeted for validation (default to + * {@link javax.validation.groups.Default}) + * + * @return constraint violations or an empty Set if none + * + * @throws IllegalArgumentException + * if object is null or if null is passed to the varargs groups + * @throws ValidationException + * if a non recoverable error happens during the validation + * process + */ + // @Override - not allowed in 1.5 for Interface methods + @SuppressWarnings("unchecked") + public Set> validate(T object, + Class... groups) { + if (object == null) + throw new IllegalArgumentException("cannot validate null"); + checkGroups(groups); + + try { + + Class objectClass = (Class) object.getClass(); + MetaBean objectMetaBean = + factoryContext.getMetaBeanFinder().findForClass(objectClass); + + final GroupValidationContext context = + createContext(objectMetaBean, object, objectClass, groups); + final ConstraintValidationListener result = + context.getListener(); + final Groups sequence = context.getGroups(); + + // 1. process groups + for (Group current : sequence.getGroups()) { + context.setCurrentGroup(current); + validateBeanNet(context); + } - // If the rootBean defines a GroupSequence - if (defaultGroups.size() > 1) { + // 2. process sequences + for (List eachSeq : sequence.getSequences()) { + for (Group current : eachSeq) { + context.setCurrentGroup(current); + validateBeanNet(context); + // if one of the group process in the sequence leads to one + // or more validation failure, + // the groups following in the sequence must not be + // processed + if (!result.isEmpty()) + break; + } + if (!result.isEmpty()) + break; + } + return result.getConstraintViolations(); + } catch (RuntimeException ex) { + throw unrecoverableValidationError(ex, object); + } + } - int numViolations = result.violationsSize(); + /** + * {@inheritDoc} Validates all constraints placed on the property of + * object named propertyName. + * + * @param object + * object to validate + * @param propertyName + * property to validate (ie field and getter constraints). Nested + * properties may be referenced (e.g. prop[2].subpropA.subpropB) + * @param groups + * group or list of groups targeted for validation (default to + * {@link javax.validation.groups.Default}) + * + * @return constraint violations or an empty Set if none + * + * @throws IllegalArgumentException + * if object is null, if propertyName + * null, empty or not a valid object property or if null is + * passed to the varargs groups + * @throws ValidationException + * if a non recoverable error happens during the validation + * process + */ + // @Override - not allowed in 1.5 for Interface methods + @SuppressWarnings("unchecked") + public Set> validateProperty(T object, + String propertyName, Class... groups) { + if (object == null) + throw new IllegalArgumentException("cannot validate null"); + + checkPropertyName(propertyName); + checkGroups(groups); + + try { + + Class objectClass = (Class) object.getClass(); + MetaBean objectMetaBean = + factoryContext.getMetaBeanFinder().findForClass(objectClass); + + GroupValidationContext context = + createContext(objectMetaBean, object, objectClass, groups); + ConstraintValidationListener result = context.getListener(); + NestedMetaProperty nestedProp = + getNestedProperty(objectMetaBean, object, propertyName); + context.setMetaProperty(nestedProp.getMetaProperty()); + if (nestedProp.isNested()) { + context.setFixedValue(nestedProp.getValue()); + } + if (context.getMetaProperty() == null) + throw new IllegalArgumentException("Unknown property " + + object.getClass().getName() + "." + propertyName); + Groups sequence = context.getGroups(); + + // 1. process groups + for (Group current : sequence.getGroups()) { + context.setCurrentGroup(current); + validatePropertyInGroup(context); + } - // Validate the bean for each group in the sequence - Group currentGroup = context.getCurrentGroup(); - for (Group each : defaultGroups) { - context.setCurrentGroup(each); - ValidationHelper.validateBean(context); - // Spec 3.4.3 - Stop validation if errors already found - if (result.violationsSize() > numViolations) { - break; - } - } - context.setCurrentGroup(currentGroup); - } else { - - // For each class in the hierarchy of classes of rootBean, - // validate the constraints defined in that class according - // to the GroupSequence defined in the same class - - // Obtain the full class hierarchy - List> classHierarchy = new ArrayList>(); - ClassHelper.fillFullClassHierarchyAsList(classHierarchy, context.getMetaBean().getBeanClass()); - Class initialOwner = context.getCurrentOwner(); - - // For each owner in the hierarchy - for (Class owner : classHierarchy) { - context.setCurrentOwner(owner); - - int numViolations = result.violationsSize(); - - // Obtain the group sequence of the owner, and use it for the constraints that belong to it - List ownerDefaultGroups = - context.getMetaBean().getFeature("{GroupSequence:" + owner.getCanonicalName() + "}"); - for (Group each : ownerDefaultGroups) { - context.setCurrentGroup(each); + // 2. process sequences + for (List eachSeq : sequence.getSequences()) { + for (Group current : eachSeq) { + context.setCurrentGroup(current); + validatePropertyInGroup(context); + /** + * if one of the group process in the sequence leads to one + * or more validation failure, the groups following in the + * sequence must not be processed + */ + if (!result.isEmpty()) + break; + } + if (!result.isEmpty()) + break; + } + return result.getConstraintViolations(); + } catch (RuntimeException ex) { + throw unrecoverableValidationError(ex, object); + } + } + + /** + * {@inheritDoc} Validates all constraints placed on the property named + * propertyName of the class beanType would the + * property value be value + *

+ * ConstraintViolation objects return null for + * {@link ConstraintViolation#getRootBean()} and + * {@link ConstraintViolation#getLeafBean()} + * + * @param beanType + * the bean type + * @param propertyName + * property to validate + * @param value + * property value to validate + * @param groups + * group or list of groups targeted for validation (default to + * {@link javax.validation.groups.Default}) + * + * @return constraint violations or an empty Set if none + * + * @throws IllegalArgumentException + * if beanType is null, if + * propertyName null, empty or not a valid object + * property or if null is passed to the varargs groups + * @throws ValidationException + * if a non recoverable error happens during the validation + * process + */ + // @Override - not allowed in 1.5 for Interface methods + public Set> validateValue(Class beanType, + String propertyName, Object value, Class... groups) { + + checkBeanType(beanType); + checkPropertyName(propertyName); + checkGroups(groups); + + try { + MetaBean metaBean = + factoryContext.getMetaBeanFinder().findForClass(beanType); + GroupValidationContext context = + createContext(metaBean, null, beanType, groups); + ConstraintValidationListener result = context.getListener(); + context.setMetaProperty(getNestedProperty(metaBean, null, + propertyName).getMetaProperty()); + context.setFixedValue(value); + Groups sequence = context.getGroups(); + + // 1. process groups + for (Group current : sequence.getGroups()) { + context.setCurrentGroup(current); + validatePropertyInGroup(context); + } + // 2. process sequences + for (List eachSeq : sequence.getSequences()) { + for (Group current : eachSeq) { + context.setCurrentGroup(current); + validatePropertyInGroup(context); + // if one of the group process in the sequence leads to one + // or more validation failure, + // the groups following in the sequence must not be + // processed + if (!result.isEmpty()) + break; + } + if (!result.isEmpty()) + break; + } + return result.getConstraintViolations(); + } catch (RuntimeException ex) { + throw unrecoverableValidationError(ex, value); + } + } + + /** + * {@inheritDoc} Return the descriptor object describing bean constraints. + * The returned object (and associated objects including + * ConstraintDescriptors) are immutable. + * + * @param clazz + * class or interface type evaluated + * + * @return the bean descriptor for the specified class. + * + * @throws IllegalArgumentException + * if clazz is null + * @throws ValidationException + * if a non recoverable error happens during the metadata + * discovery or if some constraints are invalid. + */ + // @Override - not allowed in 1.5 for Interface methods + public BeanDescriptor getConstraintsForClass(Class clazz) { + if (clazz == null) { + throw new IllegalArgumentException("Class cannot be null"); + } + try { + MetaBean metaBean = + factoryContext.getMetaBeanFinder().findForClass(clazz); + BeanDescriptorImpl edesc = + metaBean.getFeature(Jsr303Features.Bean.BEAN_DESCRIPTOR); + if (edesc == null) { + edesc = createBeanDescriptor(metaBean); + metaBean.putFeature(Jsr303Features.Bean.BEAN_DESCRIPTOR, edesc); + } + return edesc; + } catch (RuntimeException ex) { + throw new ValidationException("error retrieving constraints for " + + clazz, ex); + } + } + + /** + * {@inheritDoc} Return an instance of the specified type allowing access to + * provider-specific APIs. If the Bean Validation provider implementation + * does not support the specified class, ValidationException is + * thrown. + * + * @param type + * the class of the object to be returned. + * + * @return an instance of the specified class + * + * @throws ValidationException + * if the provider does not support the call. + */ + // @Override - not allowed in 1.5 for Interface methods + public T unwrap(Class type) { + if (type.isAssignableFrom(getClass())) { + @SuppressWarnings("unchecked") + final T result = (T) this; + return result; + } else if (!(type.isInterface() || Modifier.isAbstract(type + .getModifiers()))) { + return SecureActions.newInstance(type, + new Class[] { ApacheFactoryContext.class }, + new Object[] { factoryContext }); + } else { + try { + Class cls = ClassUtils.getClass(type.getName() + "Impl"); + if (type.isAssignableFrom(cls)) { + @SuppressWarnings("unchecked") + final Class implClass = + (Class) cls; + return SecureActions.newInstance(implClass, + new Class[] { ApacheFactoryContext.class }, + new Object[] { factoryContext }); + } + } catch (ClassNotFoundException e) { + } + throw new ValidationException("Type " + type + " not supported"); + } + } + + // Helpers + // ------------------------------------------------------------------- + + /** + * Validates a bean and all its cascaded related beans for the currently + * defined group. + *

+ * Special code is present to manage the {@link Default} group. + * + * @param validationContext + * The current context of this validation call. Must have its + * {@link GroupValidationContext#getCurrentGroup()} field set. + */ + protected void validateBeanNet(GroupValidationContext context) { + + // If reached a cascaded bean which is null + if (context.getBean() == null) { + return; + } + + // If reached a cascaded bean which has already been validated for the + // current group + if (!context.collectValidated()) { + return; + } + + // ### First, validate the bean + + // Default is a special case + if (context.getCurrentGroup().isDefault()) { + + List defaultGroups = expandDefaultGroup(context); + final ConstraintValidationListener result = + (ConstraintValidationListener) context.getListener(); + + // If the rootBean defines a GroupSequence + if (defaultGroups.size() > 1) { + + int numViolations = result.violationsSize(); + + // Validate the bean for each group in the sequence + Group currentGroup = context.getCurrentGroup(); + for (Group each : defaultGroups) { + context.setCurrentGroup(each); + ValidationHelper.validateBean(context); + // Spec 3.4.3 - Stop validation if errors already found + if (result.violationsSize() > numViolations) { + break; + } + } + context.setCurrentGroup(currentGroup); + } else { + + // For each class in the hierarchy of classes of rootBean, + // validate the constraints defined in that class according + // to the GroupSequence defined in the same class + + // Obtain the full class hierarchy + List> classHierarchy = new ArrayList>(); + ClassHelper.fillFullClassHierarchyAsList(classHierarchy, + context.getMetaBean().getBeanClass()); + Class initialOwner = context.getCurrentOwner(); + + // For each owner in the hierarchy + for (Class owner : classHierarchy) { + context.setCurrentOwner(owner); + + int numViolations = result.violationsSize(); + + // Obtain the group sequence of the owner, and use it for + // the constraints that belong to it + List ownerDefaultGroups = + context.getMetaBean().getFeature( + "{GroupSequence:" + owner.getCanonicalName() + "}"); + for (Group each : ownerDefaultGroups) { + context.setCurrentGroup(each); + ValidationHelper.validateBean(context); + // Spec 3.4.3 - Stop validation if errors already found + if (result.violationsSize() > numViolations) { + break; + } + } + + } + context.setCurrentOwner(initialOwner); + context.setCurrentGroup(Group.DEFAULT); + + } + + } + // if not the default group, proceed as normal + else { ValidationHelper.validateBean(context); - // Spec 3.4.3 - Stop validation if errors already found - if (result.violationsSize() > numViolations) { - break; - } - } - - } - context.setCurrentOwner(initialOwner); - context.setCurrentGroup(Group.DEFAULT); - - } - - } - // if not the default group, proceed as normal - else { - ValidationHelper.validateBean(context); - } - - - // ### Then, the cascaded beans (@Valid) - for (MetaProperty prop : context.getMetaBean().getProperties()) { - validateCascadedBean(context, prop); - } - - } - - /** - * Checks if the the meta property prop defines a cascaded - * bean, and in case it does, validates it. - * - * @param context - * The current validation context. - * @param prop - * The property to cascade from (in case it is possible). - */ - private void validateCascadedBean(GroupValidationContext context, MetaProperty prop) { - AccessStrategy[] access = prop.getFeature(Features.Property.REF_CASCADE); - if (access != null) { // different accesses to relation - // save old values from context - final Object bean = context.getBean(); - final MetaBean mbean = context.getMetaBean(); - for (AccessStrategy each : access) { - if (isCascadable(context, prop, each)) { - // modify context state for relationship-target bean - context.moveDown(prop, each); - // Now, if the related bean is an instance of Map/Array/etc, - ValidationHelper.validateContext(context, new Jsr303ValidationCallback(context), treatMapsLikeBeans); - // restore old values in context - context.moveUp(bean, mbean); - } - } - } - } - - /** - * Before accessing a related bean (marked with {@link javax.validation.Valid}), the - * validator has to check if it is reachable and cascadable. - * - * @param context The current validation context. - * @param prop The property of the related bean. - * @param access The access strategy used to get the related bean value. - * @return true if the validator can access the related bean, - * false otherwise. - */ - private boolean isCascadable(GroupValidationContext context, MetaProperty prop, AccessStrategy access) { - - PathImpl beanPath = context.getPropertyPath(); - NodeImpl node = new NodeImpl(prop.getName()); - if (beanPath == null) { - beanPath = PathImpl.create(null); - } - try { - if (!context.getTraversableResolver().isReachable( - context.getBean(), node, - context.getRootMetaBean().getBeanClass(), beanPath, - access.getElementType())) - return false; - } catch (RuntimeException e) { - throw new ValidationException("Error in TraversableResolver.isReachable() for " + context.getBean(), e); - } - - try { - if (!context.getTraversableResolver().isCascadable( - context.getBean(), node, - context.getRootMetaBean().getBeanClass(), beanPath, - access.getElementType())) - return false; - } catch (RuntimeException e) { - throw new ValidationException("Error TraversableResolver.isCascadable() for " + context.getBean(), e); - } - - return true; - } - - /** - * in case of a default group return the list of groups - * for a redefined default GroupSequence - * - * @return null when no in default group or default group sequence not redefined - */ - private List expandDefaultGroup(GroupValidationContext context) { - if (context.getCurrentGroup().isDefault()) { - // mention if metaBean redefines the default group - List groupSeq = - context.getMetaBean().getFeature(Jsr303Features.Bean.GROUP_SEQUENCE); - if (groupSeq != null) { - context.getGroups().assertDefaultGroupSequenceIsExpandable(groupSeq); - } - return groupSeq; - } else { - return null; - } - } - - /** - * Generate an unrecoverable validation error - * @param ex - * @param object - * @return a {@link RuntimeException} of the appropriate type - */ - protected static RuntimeException unrecoverableValidationError(RuntimeException ex, - Object object) { - if (ex instanceof UnknownPropertyException) { - // Convert to IllegalArgumentException - return new IllegalArgumentException(ex.getMessage(), ex); - } else if (ex instanceof ValidationException) { - return ex; // do not wrap specific ValidationExceptions (or instances from subclasses) - } else { - return new ValidationException("error during validation of " + object, ex); - } - } - - private void validatePropertyInGroup(GroupValidationContext context) { - Group currentGroup = context.getCurrentGroup(); - List defaultGroups = expandDefaultGroup(context); - if (defaultGroups != null) { - for (Group each : defaultGroups) { - context.setCurrentGroup(each); - ValidationHelper.validateProperty(context); - // continue validation, even if errors already found: if (!result.isEmpty()) - } - context.setCurrentGroup(currentGroup); // restore - } else { - ValidationHelper.validateProperty(context); - } - } - - /** - * find the MetaProperty for the given propertyName, - * which could contain a path, following the path on a given object to resolve - * types at runtime from the instance - */ - private NestedMetaProperty getNestedProperty(MetaBean metaBean, Object t, - String propertyName) { - NestedMetaProperty nested = new NestedMetaProperty(propertyName, t); - nested.setMetaBean(metaBean); - nested.parse(); - return nested; - } - - /** - * Create a {@link GroupValidationContext}. - * @param - * @param metaBean - * @param object - * @param objectClass - * @param groups - * @return {@link GroupValidationContext} instance - */ - protected GroupValidationContext createContext( - MetaBean metaBean, T object, Class objectClass, Class[] groups) { - ConstraintValidationListener listener = new ConstraintValidationListener(object, objectClass); - GroupValidationContextImpl context = - new GroupValidationContextImpl(listener, - this.factoryContext.getMessageInterpolator(), - this.factoryContext.getTraversableResolver(), metaBean); - context.setBean(object, metaBean); - context.setGroups(groupsComputer.computeGroups(groups)); - return context; - } - - /** - * Create a {@link BeanDescriptorImpl} - * @param metaBean - * @return {@link BeanDescriptorImpl} instance - */ - protected BeanDescriptorImpl createBeanDescriptor(MetaBean metaBean) { - return new BeanDescriptorImpl(factoryContext, metaBean, metaBean.getValidations()); - } - - private boolean treatMapsLikeBeans = false; - - /** - * Behavior configuration - - *

-   * parameter: treatMapsLikeBeans - true (validate maps like beans, so that
-   *                             you can use Maps to validate dynamic classes or
-   *                             beans for which you have the MetaBean but no instances)
-   *                           - false (default), validate maps like collections
-   *                             (validating the values only)
-   * 
- * (is still configuration to better in BeanValidationContext?) - */ - public boolean isTreatMapsLikeBeans() { - return treatMapsLikeBeans; - } - - - public void setTreatMapsLikeBeans(boolean treatMapsLikeBeans) { - this.treatMapsLikeBeans = treatMapsLikeBeans; - } - - /** - * Checks that beanType is valid according to spec Section 4.1.1 i. Throws - * an {@link IllegalArgumentException} if it is not. - * - * @param beanType Bean type to check. - */ - private void checkBeanType(Class beanType) { - if (beanType == null) { - throw new IllegalArgumentException("Bean type cannot be null."); - } - } - - /** - * Checks that the property name is valid according to spec Section 4.1.1 i. - * Throws an {@link IllegalArgumentException} if it is not. - * - * @param propertyName Property name to check. - */ - private void checkPropertyName(String propertyName) { - if (propertyName == null || propertyName.trim().length() == 0) { - throw new IllegalArgumentException("Property path cannot be null or empty."); - } - } - - /** - * Checks that the groups array is valid according to spec Section 4.1.1 i. - * Throws an {@link IllegalArgumentException} if it is not. - * - * @param groups The groups to check. - */ - private void checkGroups(Class[] groups) { - if (groups == null) { - throw new IllegalArgumentException("Groups cannot be null."); - } - } - - /** - * Dispatches a call from {@link #validate()} to - * {@link ClassValidator#validateBeanNet(GroupValidationContext)} with the - * current context set. - */ - protected class Jsr303ValidationCallback implements ValidationHelper.ValidateCallback { - - private final GroupValidationContext context; - - public Jsr303ValidationCallback(GroupValidationContext context) { - this.context = context; + } + + // ### Then, the cascaded beans (@Valid) + for (MetaProperty prop : context.getMetaBean().getProperties()) { + validateCascadedBean(context, prop); + } + + } + + /** + * Checks if the the meta property prop defines a cascaded + * bean, and in case it does, validates it. + * + * @param context + * The current validation context. + * @param prop + * The property to cascade from (in case it is possible). + */ + private void validateCascadedBean(GroupValidationContext context, + MetaProperty prop) { + AccessStrategy[] access = + prop.getFeature(Features.Property.REF_CASCADE); + if (access != null) { // different accesses to relation + // save old values from context + final Object bean = context.getBean(); + final MetaBean mbean = context.getMetaBean(); + for (AccessStrategy each : access) { + if (isCascadable(context, prop, each)) { + // modify context state for relationship-target bean + context.moveDown(prop, each); + // Now, if the related bean is an instance of Map/Array/etc, + ValidationHelper.validateContext(context, + new Jsr303ValidationCallback(context), + treatMapsLikeBeans); + // restore old values in context + context.moveUp(bean, mbean); + } + } + } + } + + /** + * Before accessing a related bean (marked with + * {@link javax.validation.Valid}), the validator has to check if it is + * reachable and cascadable. + * + * @param context + * The current validation context. + * @param prop + * The property of the related bean. + * @param access + * The access strategy used to get the related bean value. + * @return true if the validator can access the related bean, + * false otherwise. + */ + private boolean isCascadable(GroupValidationContext context, + MetaProperty prop, AccessStrategy access) { + + PathImpl beanPath = context.getPropertyPath(); + NodeImpl node = new NodeImpl(prop.getName()); + if (beanPath == null) { + beanPath = PathImpl.create(null); + } + try { + if (!context.getTraversableResolver().isReachable( + context.getBean(), node, + context.getRootMetaBean().getBeanClass(), beanPath, + access.getElementType())) + return false; + } catch (RuntimeException e) { + throw new ValidationException( + "Error in TraversableResolver.isReachable() for " + + context.getBean(), e); + } + + try { + if (!context.getTraversableResolver().isCascadable( + context.getBean(), node, + context.getRootMetaBean().getBeanClass(), beanPath, + access.getElementType())) + return false; + } catch (RuntimeException e) { + throw new ValidationException( + "Error TraversableResolver.isCascadable() for " + + context.getBean(), e); + } + + return true; + } + + /** + * in case of a default group return the list of groups for a redefined + * default GroupSequence + * + * @return null when no in default group or default group sequence not + * redefined + */ + private List expandDefaultGroup(GroupValidationContext context) { + if (context.getCurrentGroup().isDefault()) { + // mention if metaBean redefines the default group + List groupSeq = + context.getMetaBean().getFeature( + Jsr303Features.Bean.GROUP_SEQUENCE); + if (groupSeq != null) { + context.getGroups().assertDefaultGroupSequenceIsExpandable( + groupSeq); + } + return groupSeq; + } else { + return null; + } + } + + /** + * Generate an unrecoverable validation error + * + * @param ex + * @param object + * @return a {@link RuntimeException} of the appropriate type + */ + protected static RuntimeException unrecoverableValidationError( + RuntimeException ex, Object object) { + if (ex instanceof UnknownPropertyException) { + // Convert to IllegalArgumentException + return new IllegalArgumentException(ex.getMessage(), ex); + } else if (ex instanceof ValidationException) { + return ex; // do not wrap specific ValidationExceptions (or + // instances from subclasses) + } else { + return new ValidationException("error during validation of " + + object, ex); + } } - public void validate() { - validateBeanNet(context); + private void validatePropertyInGroup(GroupValidationContext context) { + Group currentGroup = context.getCurrentGroup(); + List defaultGroups = expandDefaultGroup(context); + if (defaultGroups != null) { + for (Group each : defaultGroups) { + context.setCurrentGroup(each); + ValidationHelper.validateProperty(context); + // continue validation, even if errors already found: if + // (!result.isEmpty()) + } + context.setCurrentGroup(currentGroup); // restore + } else { + ValidationHelper.validateProperty(context); + } + } + + /** + * find the MetaProperty for the given propertyName, which could contain a + * path, following the path on a given object to resolve types at runtime + * from the instance + */ + private NestedMetaProperty getNestedProperty(MetaBean metaBean, Object t, + String propertyName) { + NestedMetaProperty nested = new NestedMetaProperty(propertyName, t); + nested.setMetaBean(metaBean); + nested.parse(); + return nested; + } + + /** + * Create a {@link GroupValidationContext}. + * + * @param + * @param metaBean + * @param object + * @param objectClass + * @param groups + * @return {@link GroupValidationContext} instance + */ + protected GroupValidationContext createContext(MetaBean metaBean, + T object, Class objectClass, Class[] groups) { + ConstraintValidationListener listener = + new ConstraintValidationListener(object, objectClass); + GroupValidationContextImpl context = + new GroupValidationContextImpl(listener, this.factoryContext + .getMessageInterpolator(), this.factoryContext + .getTraversableResolver(), metaBean); + context.setBean(object, metaBean); + context.setGroups(groupsComputer.computeGroups(groups)); + return context; + } + + /** + * Create a {@link BeanDescriptorImpl} + * + * @param metaBean + * @return {@link BeanDescriptorImpl} instance + */ + protected BeanDescriptorImpl createBeanDescriptor(MetaBean metaBean) { + return new BeanDescriptorImpl(factoryContext, metaBean, metaBean + .getValidations()); + } + + private boolean treatMapsLikeBeans = false; + + /** + * Behavior configuration - + * + *
+     * parameter: treatMapsLikeBeans - true (validate maps like beans, so that
+     *                             you can use Maps to validate dynamic classes or
+     *                             beans for which you have the MetaBean but no instances)
+     *                           - false (default), validate maps like collections
+     *                             (validating the values only)
+     * 
+ * + * (is still configuration to better in BeanValidationContext?) + */ + public boolean isTreatMapsLikeBeans() { + return treatMapsLikeBeans; + } + + public void setTreatMapsLikeBeans(boolean treatMapsLikeBeans) { + this.treatMapsLikeBeans = treatMapsLikeBeans; + } + + /** + * Checks that beanType is valid according to spec Section 4.1.1 i. Throws + * an {@link IllegalArgumentException} if it is not. + * + * @param beanType + * Bean type to check. + */ + private void checkBeanType(Class beanType) { + if (beanType == null) { + throw new IllegalArgumentException("Bean type cannot be null."); + } + } + + /** + * Checks that the property name is valid according to spec Section 4.1.1 i. + * Throws an {@link IllegalArgumentException} if it is not. + * + * @param propertyName + * Property name to check. + */ + private void checkPropertyName(String propertyName) { + if (propertyName == null || propertyName.trim().length() == 0) { + throw new IllegalArgumentException( + "Property path cannot be null or empty."); + } + } + + /** + * Checks that the groups array is valid according to spec Section 4.1.1 i. + * Throws an {@link IllegalArgumentException} if it is not. + * + * @param groups + * The groups to check. + */ + private void checkGroups(Class[] groups) { + if (groups == null) { + throw new IllegalArgumentException("Groups cannot be null."); + } + } + + /** + * Dispatches a call from {@link #validate()} to + * {@link ClassValidator#validateBeanNet(GroupValidationContext)} with the + * current context set. + */ + protected class Jsr303ValidationCallback implements + ValidationHelper.ValidateCallback { + + private final GroupValidationContext context; + + public Jsr303ValidationCallback(GroupValidationContext context) { + this.context = context; + } + + public void validate() { + validateBeanNet(context); + } + } - } - }