You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bval.apache.org by mb...@apache.org on 2010/09/03 18:51:24 UTC
svn commit: r992372 -
/incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/ClassValidator.java
Author: mbenson
Date: Fri Sep 3 16:51:24 2010
New Revision: 992372
URL: http://svn.apache.org/viewvc?rev=992372&view=rev
Log:
format
Modified:
incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/ClassValidator.java
Modified: incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/ClassValidator.java
URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/ClassValidator.java?rev=992372&r1=992371&r2=992372&view=diff
==============================================================================
--- incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/ClassValidator.java (original)
+++ incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/ClassValidator.java Fri Sep 3 16:51:24 2010
@@ -18,7 +18,6 @@
*/
package org.apache.bval.jsr303;
-
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -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,645 +53,693 @@ import org.apache.commons.lang.ClassUtil
* API class
*
* @author Roman Stumm
- * @author Carlos Vara
- * <br/>
+ * @author Carlos Vara <br/>
*/
public class ClassValidator implements Validator {
- /**
- * {@link ApacheFactoryContext} used
- */
- protected final ApacheFactoryContext factoryContext;
- /**
- * {@link GroupsComputer} used
- */
- protected final GroupsComputer groupsComputer = new GroupsComputer();
-
- private final NestedPathNavigator nestedPathNavigator = new NestedPathNavigator();
-
- /**
- * 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 <code>object</code>.
- *
- * @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 <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) {
- if (object == null) throw new IllegalArgumentException("cannot validate null");
- checkGroups(groups);
-
- try {
-
- Class<T> objectClass = (Class<T>) object.getClass();
- MetaBean objectMetaBean = factoryContext.getMetaBeanFinder().findForClass(objectClass);
-
- final GroupValidationContext<T> context =
- createContext(objectMetaBean, object, objectClass, groups);
- final ConstraintValidationListener<T> 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<Group> 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 <code>object</code>
- * named <code>propertyName</code>.
- *
- * @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 <code>object</code> is null,
- * if <code>propertyName</code> 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 <T> Set<ConstraintViolation<T>> validateProperty(T object, String propertyName,
- Class<?>... groups) {
- if (object == null) throw new IllegalArgumentException("cannot validate null");
-
- checkPropertyName(propertyName);
- checkGroups(groups);
-
- try {
-
- Class<T> objectClass = (Class<T>) object.getClass();
- MetaBean objectMetaBean = factoryContext.getMetaBeanFinder().findForClass(objectClass);
-
- GroupValidationContext<T> context =
- createContext(objectMetaBean, object, objectClass, groups);
- ConstraintValidationListener<T> result = context.getListener();
- nestedPathNavigator.navigate(context, propertyName);
- Groups sequence = context.getGroups();
-
- // 1. process groups
- for (Group current : sequence.getGroups()) {
- context.setCurrentGroup(current);
- validatePropertyInGroup(context);
- }
-
- // 2. process sequences
- for (List<Group> 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
- * <code>propertyName</code> of the class <code>beanType</code> would the
- * property value be <code>value</code>
- * <p/>
- * <code>ConstraintViolation</code> 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 <code>beanType</code> is null,
- * if <code>propertyName</code> 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 <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType,
- String propertyName, Object value,
- Class<?>... groups) {
-
- checkBeanType(beanType);
- checkPropertyName(propertyName);
- checkGroups(groups);
-
- try {
- MetaBean metaBean = factoryContext.getMetaBeanFinder().findForClass(beanType);
- GroupValidationContext<T> context =
- createContext(metaBean, null, beanType, groups);
- ConstraintValidationListener<T> result = context.getListener();
- nestedPathNavigator.navigate(context, propertyName);
- 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<Group> 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
- * <code>ConstraintDescriptor<code>s) 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,
- * <code>ValidationException</code> 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.
- */
- @SuppressWarnings("unchecked")
- // @Override - not allowed in 1.5 for Interface methods
- public <T> T unwrap(Class<T> type) {
- if (type.isAssignableFrom(getClass())) {
- return (T) this;
- } else if (!type.isInterface()) {
- return SecureActions.newInstance(type, new Class[]{ApacheFactoryContext.class},
- new Object[]{factoryContext});
- } else {
- try {
- Class<T> cls = ClassUtils.getClass(type.getName() + "Impl");
- return SecureActions.newInstance(cls,
- 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.
- * <p>
- * 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<Group> 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();
+
+ private final NestedPathNavigator nestedPathNavigator =
+ new NestedPathNavigator();
+
+ /**
+ * 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 <code>object</code>.
+ *
+ * @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 <T> Set<ConstraintViolation<T>> validate(T object,
+ Class<?>... groups) {
+ if (object == null)
+ throw new IllegalArgumentException("cannot validate null");
+ checkGroups(groups);
+
+ try {
+
+ Class<T> objectClass = (Class<T>) object.getClass();
+ MetaBean objectMetaBean =
+ factoryContext.getMetaBeanFinder().findForClass(objectClass);
+
+ final GroupValidationContext<T> context =
+ createContext(objectMetaBean, object, objectClass, groups);
+ final ConstraintValidationListener<T> 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<Group> 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
+ * <code>object</code> named <code>propertyName</code>.
+ *
+ * @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 <code>object</code> is null, if <code>propertyName</code>
+ * 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 <T> Set<ConstraintViolation<T>> validateProperty(T object,
+ String propertyName, Class<?>... groups) {
+ if (object == null)
+ throw new IllegalArgumentException("cannot validate null");
+
+ checkPropertyName(propertyName);
+ checkGroups(groups);
+
+ try {
+
+ Class<T> objectClass = (Class<T>) object.getClass();
+ MetaBean objectMetaBean =
+ factoryContext.getMetaBeanFinder().findForClass(objectClass);
+
+ GroupValidationContext<T> context =
+ createContext(objectMetaBean, object, objectClass, groups);
+ ConstraintValidationListener<T> result = context.getListener();
+ nestedPathNavigator.navigate(context, 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<Class<?>> classHierarchy = new ArrayList<Class<?>>();
- 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<Group> ownerDefaultGroups =
- context.getMetaBean().getFeature("{GroupSequence:" + owner.getCanonicalName() + "}");
- for (Group each : ownerDefaultGroups) {
- context.setCurrentGroup(each);
+ // 2. process sequences
+ for (List<Group> 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
+ * <code>propertyName</code> of the class <code>beanType</code> would the
+ * property value be <code>value</code>
+ * <p/>
+ * <code>ConstraintViolation</code> 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 <code>beanType</code> is null, if
+ * <code>propertyName</code> 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 <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType,
+ String propertyName, Object value, Class<?>... groups) {
+
+ checkBeanType(beanType);
+ checkPropertyName(propertyName);
+ checkGroups(groups);
+
+ try {
+ MetaBean metaBean =
+ factoryContext.getMetaBeanFinder().findForClass(beanType);
+ GroupValidationContext<T> context =
+ createContext(metaBean, null, beanType, groups);
+ ConstraintValidationListener<T> result = context.getListener();
+ nestedPathNavigator.navigate(context, propertyName);
+ 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<Group> 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
+ * <code>ConstraintDescriptor<code>s) 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, <code>ValidationException</code> 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.
+ */
+ @SuppressWarnings("unchecked")
+ // @Override - not allowed in 1.5 for Interface methods
+ public <T> T unwrap(Class<T> type) {
+ if (type.isAssignableFrom(getClass())) {
+ return (T) this;
+ } else if (!type.isInterface()) {
+ return SecureActions.newInstance(type,
+ new Class[] { ApacheFactoryContext.class },
+ new Object[] { factoryContext });
+ } else {
+ try {
+ Class<T> cls = ClassUtils.getClass(type.getName() + "Impl");
+ return SecureActions.newInstance(cls,
+ 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.
+ * <p>
+ * 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<Group> 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<Class<?>> classHierarchy = new ArrayList<Class<?>>();
+ 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<Group> 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 <code>prop</code> 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 <code>true</code> if the validator can access the related bean,
- * <code>false</code> 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<Group> expandDefaultGroup(GroupValidationContext<?> context) {
- if (context.getCurrentGroup().isDefault()) {
- // mention if metaBean redefines the default group
- List<Group> 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<Group> 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);
- }
- }
-
- /**
- * Create a {@link GroupValidationContext}.
- * @param <T>
- * @param metaBean
- * @param object
- * @param objectClass
- * @param groups
- * @return {@link GroupValidationContext} instance
- */
- protected <T> GroupValidationContext<T> createContext(
- MetaBean metaBean, T object, Class<T> objectClass, Class<?>[] groups) {
- ConstraintValidationListener<T> listener = new ConstraintValidationListener<T>(object, objectClass);
- GroupValidationContextImpl<T> context =
- new GroupValidationContextImpl<T>(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 -
- * <pre>
- * 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)
- * </pre>
- * (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 <code>prop</code> 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 <code>true</code> if the validator can access the related bean,
+ * <code>false</code> 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<Group> expandDefaultGroup(GroupValidationContext<?> context) {
+ if (context.getCurrentGroup().isDefault()) {
+ // mention if metaBean redefines the default group
+ List<Group> groupSeq =
+ context.getMetaBean().getFeature(
+ Jsr303Features.Bean.GROUP_SEQUENCE);
+ if (groupSeq != null) {
+ context.getGroups().assertDefaultGroupSequenceIsExpandable(
+ groupSeq);
+ }
+ return groupSeq;
+ } else {
+ return null;
+ }
}
- public void validate() {
- validateBeanNet(context);
+ /**
+ * 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<Group> 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);
+ }
+ }
+
+ /**
+ * Create a {@link GroupValidationContext}.
+ *
+ * @param <T>
+ * @param metaBean
+ * @param object
+ * @param objectClass
+ * @param groups
+ * @return {@link GroupValidationContext} instance
+ */
+ protected <T> GroupValidationContext<T> createContext(MetaBean metaBean,
+ T object, Class<T> objectClass, Class<?>[] groups) {
+ ConstraintValidationListener<T> listener =
+ new ConstraintValidationListener<T>(object, objectClass);
+ GroupValidationContextImpl<T> context =
+ new GroupValidationContextImpl<T>(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 -
+ *
+ * <pre>
+ * 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)
+ * </pre>
+ *
+ * (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);
+ }
+
}
- }
-
}