Author: hardy.ferentschik
Date: 2009-01-13 09:46:34 -0500 (Tue, 13 Jan 2009)
New Revision: 15773
Added:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ConstraintTree.java
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/BeanMetaDataImpl.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/MetaConstraint.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidationContext.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidatorImpl.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ValidatorBuilderImpl.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ValidatorFactoryImpl.java
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/constraints/composition/GermanZipcode.java
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/ConstraintCompositionTest.java
validator/trunk/hibernate-validator/src/test/resources/log4j.properties
validator/trunk/pom.xml
validator/trunk/validation-api/src/main/java/javax/validation/Validator.java
Log:
BVAL-31 - Added support for @ReportAsViolationFromCompositeConstraint
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/BeanMetaDataImpl.java
===================================================================
---
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/BeanMetaDataImpl.java 2009-01-12
22:07:51 UTC (rev 15772)
+++
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/BeanMetaDataImpl.java 2009-01-13
14:46:34 UTC (rev 15773)
@@ -32,6 +32,8 @@
import javax.validation.PropertyDescriptor;
import javax.validation.Valid;
import javax.validation.ValidationException;
+import javax.validation.MessageResolver;
+import javax.validation.ConstraintFactory;
import org.slf4j.Logger;
@@ -47,13 +49,16 @@
* instantiate an instance of this class and delegate the metadata extraction to it.
*
* @author Hardy Ferentschik
- * FIXME create an interface for MetadataProvider
*/
public class BeanMetaDataImpl<T> implements BeanMetaData<T> {
private static final Logger log = LoggerFactory.make();
+ private final MessageResolver messageResolver;
+
+ private final ConstraintFactory constraintFactory;
+
/**
* The root bean class for this validator.
*/
@@ -90,8 +95,10 @@
*/
private Map<Class<?>, List<Class<?>>> groupSequences = new
HashMap<Class<?>, List<Class<?>>>();
- public BeanMetaDataImpl(Class<T> beanClass) {
+ public BeanMetaDataImpl(Class<T> beanClass, MessageResolver messageResolver,
ConstraintFactory constraintFactory) {
this.beanClass = beanClass;
+ this.messageResolver = messageResolver;
+ this.constraintFactory = constraintFactory;
createMetaData();
}
@@ -190,7 +197,7 @@
List<ConstraintDescriptorImpl> fieldMetadata = findFieldLevelConstraints( field
);
for ( ConstraintDescriptorImpl constraintDescription : fieldMetadata ) {
ReflectionHelper.setAccessibility( field );
- MetaConstraint metaConstraint = new MetaConstraint( field, constraintDescription );
+ MetaConstraint metaConstraint = new MetaConstraint( field, constraintDescription,
messageResolver, constraintFactory );
metaConstraintList.add( metaConstraint );
}
if ( field.isAnnotationPresent( Valid.class ) ) {
@@ -205,7 +212,7 @@
List<ConstraintDescriptorImpl> methodMetadata = findMethodLevelConstraints(
method );
for ( ConstraintDescriptorImpl constraintDescription : methodMetadata ) {
ReflectionHelper.setAccessibility( method );
- MetaConstraint metaConstraint = new MetaConstraint( method, constraintDescription );
+ MetaConstraint metaConstraint = new MetaConstraint( method, constraintDescription,
messageResolver, constraintFactory );
metaConstraintList.add( metaConstraint );
}
if ( method.isAnnotationPresent( Valid.class ) ) {
@@ -218,7 +225,7 @@
private void initClassConstraints(Class clazz) {
List<ConstraintDescriptorImpl> classMetadata = findClassLevelConstraints( clazz
);
for ( ConstraintDescriptorImpl constraintDescription : classMetadata ) {
- MetaConstraint metaConstraint = new MetaConstraint( clazz, constraintDescription );
+ MetaConstraint metaConstraint = new MetaConstraint( clazz, constraintDescription,
messageResolver, constraintFactory );
metaConstraintList.add( metaConstraint );
}
}
Added:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ConstraintTree.java
===================================================================
---
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ConstraintTree.java
(rev 0)
+++
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ConstraintTree.java 2009-01-13
14:46:34 UTC (rev 15773)
@@ -0,0 +1,164 @@
+// $Id$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2008, Red Hat Middleware LLC, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.hibernate.validation.engine;
+
+import java.util.List;
+import java.util.ArrayList;
+import javax.validation.Constraint;
+import javax.validation.ConstraintDescriptor;
+import javax.validation.ValidationException;
+import javax.validation.ConstraintFactory;
+import javax.validation.MessageResolver;
+
+import org.slf4j.Logger;
+
+import org.hibernate.validation.impl.ConstraintViolationImpl;
+import org.hibernate.validation.util.LoggerFactory;
+
+/**
+ * Due to constraint conposition a single constraint annotation can lead to a whole
constraint tree beeing validated.
+ * This class encapsulates such a tree for a single constraint annotation.
+ *
+ * @author Hardy Ferentschik
+ */
+public class ConstraintTree {
+
+ private static final Logger log = LoggerFactory.make();
+
+ private final ConstraintTree parent;
+ private final List<ConstraintTree> children;
+ private Constraint constraint;
+ private final ConstraintDescriptor descriptor;
+ private final ConstraintFactory constraintFactory;
+ private final MessageResolver messageResolver;
+
+ public ConstraintTree(ConstraintDescriptor descriptor, ConstraintFactory
constraintFactory, MessageResolver messageResolver) {
+ this( descriptor, null, constraintFactory, messageResolver );
+ }
+
+ private ConstraintTree(ConstraintDescriptor descriptor, ConstraintTree parent,
ConstraintFactory constraintFactory, MessageResolver messageResolver) {
+ this.parent = parent;
+ this.descriptor = descriptor;
+ this.constraintFactory = constraintFactory;
+ this.messageResolver = messageResolver;
+ this.constraint = getConstraint( descriptor );
+ children = new ArrayList<ConstraintTree>(
descriptor.getComposingConstraints().size() );
+
+ for ( ConstraintDescriptor composingDescriptor : descriptor.getComposingConstraints() )
{
+ ConstraintTree treeNode = new ConstraintTree(
+ composingDescriptor, this, constraintFactory, messageResolver
+ );
+ children.add( treeNode );
+ }
+ }
+
+ public boolean isRoot() {
+ return parent == null;
+ }
+
+ public ConstraintTree getParent() {
+ return parent;
+ }
+
+ public List<ConstraintTree> getChildren() {
+ return children;
+ }
+
+ public boolean hasChildren() {
+ return children.size() > 0;
+ }
+
+ public Constraint getConstraint() {
+ return constraint;
+ }
+
+ public ConstraintDescriptor getDescriptor() {
+ return descriptor;
+ }
+
+ public <T> void validateConstraints(Object value, Class<T> beanClass,
ValidationContext<T> validationContext) {
+ for ( ConstraintTree tree : getChildren() ) {
+ tree.validateConstraints( value, beanClass, validationContext );
+ }
+
+ final Object leafBeanInstance = validationContext.peekValidatedObject();
+ ConstraintContextImpl constraintContext = new ConstraintContextImpl( descriptor );
+ if ( log.isTraceEnabled() ) {
+ log.trace( "Validating value {} against constraint defined by {}", value,
descriptor );
+ }
+ if ( !constraint.isValid( value, constraintContext ) ) {
+ for ( ConstraintContextImpl.ErrorMessage error : constraintContext.getErrorMessages()
) {
+ final String message = error.getMessage();
+ createConstraintViolation( value, beanClass, validationContext, leafBeanInstance,
message, descriptor );
+ }
+ }
+ if ( reportAsSingleViolation()
+ && validationContext.getFailingConstraints().size() > 0 ) {
+ validationContext.clearFailingConstraints();
+ final String message = ( String ) getParent().getDescriptor().getParameters().get(
"message" );
+ createConstraintViolation(
+ value, beanClass, validationContext, leafBeanInstance, message,
getParent().descriptor
+ );
+ }
+ }
+
+ private boolean reportAsSingleViolation() {
+ return getParent() != null
+ && getParent().getDescriptor().isReportAsViolationFromCompositeConstraint();
+ }
+
+ private <T> void createConstraintViolation(Object value, Class<T> beanClass,
ValidationContext<T> validationContext, Object leafBeanInstance, String message,
ConstraintDescriptor descriptor) {
+ String interpolatedMessage = messageResolver.interpolate(
+ message,
+ descriptor,
+ leafBeanInstance
+ );
+ ConstraintViolationImpl<T> failingConstraintViolation = new
ConstraintViolationImpl<T>(
+ message,
+ interpolatedMessage,
+ validationContext.getRootBean(),
+ beanClass,
+ leafBeanInstance,
+ value,
+ validationContext.peekPropertyPath(), //FIXME use error.getProperty()
+ validationContext.getCurrentGroup(),
+ descriptor
+ );
+ validationContext.addConstraintFailure( failingConstraintViolation );
+ }
+
+ @SuppressWarnings("unchecked")
+ private Constraint getConstraint(ConstraintDescriptor descriptor) {
+ Constraint constraint;
+ try {
+ //unchecked
+ constraint = constraintFactory.getInstance( descriptor.getConstraintClass() );
+ }
+ catch ( RuntimeException e ) {
+ throw new ValidationException( "Unable to instantiate " +
descriptor.getConstraintClass(), e );
+ }
+
+ try {
+ constraint.initialize( descriptor.getAnnotation() );
+ }
+ catch ( RuntimeException e ) {
+ throw new ValidationException( "Unable to intialize " +
constraint.getClass().getName(), e );
+ }
+ return constraint;
+ }
+}
Property changes on:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ConstraintTree.java
___________________________________________________________________
Name: svn:keywords
+ Id
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/MetaConstraint.java
===================================================================
---
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/MetaConstraint.java 2009-01-12
22:07:51 UTC (rev 15772)
+++
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/MetaConstraint.java 2009-01-13
14:46:34 UTC (rev 15773)
@@ -21,10 +21,11 @@
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
+import javax.validation.ConstraintDescriptor;
import javax.validation.ValidationException;
-import javax.validation.ConstraintDescriptor;
+import javax.validation.MessageResolver;
+import javax.validation.ConstraintFactory;
-import org.hibernate.validation.impl.ConstraintDescriptorImpl;
import org.hibernate.validation.util.ReflectionHelper;
/**
@@ -36,9 +37,9 @@
public class MetaConstraint {
/**
- * The constraint specific meta data.
+ * The constraint tree created from the constraint annotation.
*/
- private final ConstraintDescriptorImpl descriptor;
+ private final ConstraintTree constraintTree;
/**
* The type (class) the constraint was defined on. <code>null</code> if the
constraint was specified on method or
@@ -69,31 +70,34 @@
*/
private final ElementType elementType;
- public MetaConstraint(Type t, ConstraintDescriptorImpl constraintDescriptor) {
- this.type = t;
- this.method = null;
- this.field = null;
- this.descriptor = constraintDescriptor;
- this.elementType = ElementType.TYPE;
- this.propertyName = "";
+ public MetaConstraint(Type t, ConstraintDescriptor constraintDescriptor, MessageResolver
messageResolver, ConstraintFactory factory) {
+ this( t, null, null, ElementType.FIELD, constraintDescriptor, "",
messageResolver, factory );
}
- public MetaConstraint(Method m, ConstraintDescriptorImpl constraintDescriptor) {
- this.method = m;
- this.type = null;
- this.field = null;
- this.descriptor = constraintDescriptor;
- this.elementType = ElementType.METHOD;
- this.propertyName = ReflectionHelper.getPropertyName( m );
+ public MetaConstraint(Method m, ConstraintDescriptor constraintDescriptor,
MessageResolver messageResolver, ConstraintFactory factory) {
+ this(
+ null,
+ m,
+ null,
+ ElementType.METHOD,
+ constraintDescriptor,
+ ReflectionHelper.getPropertyName( m ),
+ messageResolver,
+ factory
+ );
}
- public MetaConstraint(Field f, ConstraintDescriptorImpl constraintDescriptor) {
+ public MetaConstraint(Field f, ConstraintDescriptor constraintDescriptor,
MessageResolver messageResolver, ConstraintFactory factory) {
+ this( null, null, f, ElementType.FIELD, constraintDescriptor, f.getName(),
messageResolver, factory );
+ }
+
+ private MetaConstraint(Type t, Method m, Field f, ElementType elementType,
ConstraintDescriptor constraintDescriptor, String property, MessageResolver
messageResolver, ConstraintFactory factory) {
+ this.type = t;
+ this.method = m;
this.field = f;
- this.method = null;
- this.type = null;
- this.descriptor = constraintDescriptor;
- this.elementType = ElementType.FIELD;
- this.propertyName = f.getName();
+ this.elementType = elementType;
+ this.propertyName = property;
+ constraintTree = new ConstraintTree( constraintDescriptor, factory, messageResolver );
}
/**
@@ -140,7 +144,7 @@
}
public ConstraintDescriptor getDescriptor() {
- return descriptor;
+ return constraintTree.getDescriptor();
}
public Method getMethod() {
@@ -163,6 +167,20 @@
return elementType;
}
+ public ConstraintTree getConstraintTree() {
+ return constraintTree;
+ }
+
+ public <T> void validateConstraint(Class beanClass, ValidationContext<T>
validationContext) {
+ final Object leafBeanInstance = validationContext.peekValidatedObject();
+ Object value = getValue( leafBeanInstance );
+ constraintTree.validateConstraints( value, beanClass, validationContext );
+ }
+
+ public <T> void validateConstraint(Class beanClass, Object value,
ValidationContext<T> validationContext) {
+ constraintTree.validateConstraints( value, beanClass, validationContext );
+ }
+
private Type typeOfAnnoatedElement() {
Type t;
switch ( elementType ) {
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidationContext.java
===================================================================
---
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidationContext.java 2009-01-12
22:07:51 UTC (rev 15772)
+++
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidationContext.java 2009-01-13
14:46:34 UTC (rev 15773)
@@ -143,6 +143,10 @@
return failingConstraintViolations;
}
+ public void clearFailingConstraints() {
+ failingConstraintViolations.clear();
+ }
+
/**
* Adds a new level to the current property path of this context.
*
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidatorImpl.java
===================================================================
---
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidatorImpl.java 2009-01-12
22:07:51 UTC (rev 15772)
+++
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidatorImpl.java 2009-01-13
14:46:34 UTC (rev 15773)
@@ -27,24 +27,15 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.ListIterator;
import javax.validation.BeanDescriptor;
-import javax.validation.Constraint;
import javax.validation.ConstraintDescriptor;
-import javax.validation.ConstraintFactory;
import javax.validation.ConstraintViolation;
-import javax.validation.MessageResolver;
-import javax.validation.TraversableResolver;
-import javax.validation.ValidationException;
import javax.validation.Validator;
import javax.validation.groups.Default;
-import org.slf4j.Logger;
-
import org.hibernate.validation.impl.ConstraintViolationImpl;
import org.hibernate.validation.util.PropertyIterator;
import org.hibernate.validation.util.ReflectionHelper;
-import org.hibernate.validation.util.LoggerFactory;
/**
* The main Bean Validation class.
@@ -54,7 +45,6 @@
* @todo Make all properties transient for serializability.
*/
public class ValidatorImpl implements Validator {
- private static final Logger log = LoggerFactory.make();
private static final Set<Class<?>> INDEXABLE_CLASS = new
HashSet<Class<?>>();
private static final Class<?>[] DEFAULT_GROUP = new Class<?>[] {
Default.class };
@@ -64,22 +54,10 @@
INDEXABLE_CLASS.add( String.class );
}
- /**
- * Message resolver used for interpolating error messages.
- */
- private final MessageResolver messageResolver;
-
private final ValidatorFactoryImplementor factory;
- private final ConstraintFactory constraintFactory;
- private final TraversableResolver traversableResolver;
-
- public ValidatorImpl(ValidatorFactoryImplementor factory, MessageResolver
messageResolver,
- TraversableResolver traversableResolver, ConstraintFactory constraintFactory) {
+ public ValidatorImpl(ValidatorFactoryImplementor factory) {
this.factory = factory;
- this.messageResolver = messageResolver;
- this.traversableResolver = traversableResolver;
- this.constraintFactory = constraintFactory;
}
/**
@@ -149,6 +127,7 @@
( BeanMetaData<T> ) factory.getBeanMetaData(
validationContext.peekValidatedObjectType() );
for ( MetaConstraint metaConstraint : beanMetaData.geMetaConstraintList() ) {
ConstraintDescriptor mainConstraintDescriptor = metaConstraint.getDescriptor();
+
validationContext.pushProperty( metaConstraint.getPropertyName() );
if ( !validationContext.needsValidation( mainConstraintDescriptor.getGroups() ) ) {
@@ -156,48 +135,7 @@
continue;
}
- final Object leafBeanInstance = validationContext.peekValidatedObject();
- Object value = metaConstraint.getValue( leafBeanInstance );
-
- // we have to check the main constraint and all composing constraints
- List<ConstraintDescriptor> descriptors = new
ArrayList<ConstraintDescriptor>();
- descriptors.add( mainConstraintDescriptor );
- // use a list iterator so that we can keep modifying the underlying list
- ListIterator<ConstraintDescriptor> listIter = descriptors.listIterator();
- while ( listIter.hasNext() ) {
- ConstraintDescriptor descriptor = listIter.next();
- ConstraintContextImpl constraintContext = new ConstraintContextImpl( descriptor );
- if ( log.isTraceEnabled() ) {
- log.trace( "Validating value {} against constraint defined by {}", value,
descriptor );
- }
- if ( !getConstraint( descriptor ).isValid( value, constraintContext ) ) {
- for ( ConstraintContextImpl.ErrorMessage error :
constraintContext.getErrorMessages() ) {
- final String message = error.getMessage();
- String interpolatedMessage = messageResolver.interpolate(
- message,
- descriptor,
- leafBeanInstance
- );
- ConstraintViolationImpl<T> failingConstraintViolation = new
ConstraintViolationImpl<T>(
- message,
- interpolatedMessage,
- validationContext.getRootBean(),
- beanMetaData.getBeanClass(),
- leafBeanInstance,
- value,
- validationContext.peekPropertyPath(), //FIXME use error.getProperty()
- validationContext.getCurrentGroup(),
- descriptor
- );
- validationContext.addConstraintFailure( failingConstraintViolation );
- }
- }
- // check for composing constraints and add them to the list. The list iterator needs
to set back each time!
- for ( ConstraintDescriptor composingDescriptor : descriptor.getComposingConstraints()
) {
- listIter.add( composingDescriptor );
- listIter = descriptors.listIterator( listIter.previousIndex() );
- }
- }
+ metaConstraint.validateConstraint( beanMetaData.getBeanClass(), validationContext );
validationContext.popProperty();
}
validationContext.markProcessedForCurrentGroup();
@@ -281,7 +219,6 @@
}
}
-
/**
* {@inheritDoc}
*/
@@ -291,7 +228,6 @@
return new HashSet<ConstraintViolation<T>>( failingConstraintViolations );
}
-
private <T> void validateProperty(T object, PropertyIterator propertyIter,
List<ConstraintViolationImpl<T>> failingConstraintViolations,
Class<?>... groups) {
if ( object == null ) {
throw new IllegalArgumentException( "Validated object cannot be null" );
@@ -299,9 +235,10 @@
@SuppressWarnings("unchecked")
final Class<T> beanType = ( Class<T> ) object.getClass();
- DesrciptorValueWrapper wrapper = getConstraintDescriptorAndValueForPath( beanType,
propertyIter, object );
+ Set<MetaConstraint> metaConstraints = new HashSet<MetaConstraint>();
+ getMetaConstraintsForPath( beanType, propertyIter, metaConstraints );
- if ( wrapper == null ) {
+ if ( metaConstraints.size() == 0 ) {
return;
}
@@ -318,33 +255,14 @@
for ( Class<?> expandedGroup : expandedGroups ) {
- if ( !wrapper.descriptor.getGroups().contains( expandedGroup ) ) {
- continue;
- }
-
- ConstraintContextImpl contextImpl = new ConstraintContextImpl( wrapper.descriptor );
- if ( !getConstraint( wrapper.descriptor ).isValid( wrapper.value, contextImpl ) ) {
-
- for ( ConstraintContextImpl.ErrorMessage error : contextImpl.getErrorMessages() ) {
- final String message = error.getMessage();
- String interpolatedMessage = messageResolver.interpolate(
- message,
- wrapper.descriptor,
- wrapper.value
- );
- ConstraintViolationImpl<T> failingConstraintViolation = new
ConstraintViolationImpl<T>(
- message,
- interpolatedMessage,
- object,
- beanType,
- object,
- wrapper.value,
- propertyIter.getOriginalProperty(), //FIXME use error.getProperty()
- group,
- wrapper.descriptor
- );
- addFailingConstraint( failingConstraintViolations, failingConstraintViolation );
+ for ( MetaConstraint metaConstraint : metaConstraints ) {
+ if ( !metaConstraint.getDescriptor().getGroups().contains( expandedGroup ) ) {
+ continue;
}
+
+ ValidationContext<T> context = new ValidationContext<T>( object );
+ metaConstraint.validateConstraint( object.getClass(), context );
+ failingConstraintViolations.addAll( context.getFailingConstraints() );
}
if ( isGroupSequence && failingConstraintViolations.size() > 0 ) {
@@ -367,13 +285,11 @@
return factory.getBeanMetaData( clazz ).getBeanDescriptor();
}
- /**
- * @todo Implement composing constraints.
- */
- private <T> void validateValue(Class<T> beanType, Object object,
PropertyIterator propertyIter, List<ConstraintViolationImpl<T>>
failingConstraintViolations, Class<?>... groups) {
- ConstraintDescriptor constraintDescriptor = getConstraintDescriptorForPath( beanType,
propertyIter );
+ private <T> void validateValue(Class<T> beanType, Object value,
PropertyIterator propertyIter, List<ConstraintViolationImpl<T>>
failingConstraintViolations, Class<?>... groups) {
+ Set<MetaConstraint> metaConstraints = new HashSet<MetaConstraint>();
+ getMetaConstraintsForPath( beanType, propertyIter, metaConstraints );
- if ( constraintDescriptor == null ) {
+ if ( metaConstraints.size() == 0 ) {
return;
}
@@ -390,33 +306,15 @@
for ( Class<?> expandedGroup : expandedGroups ) {
- if ( !constraintDescriptor.getGroups().contains( expandedGroup ) ) {
- continue;
- }
-
- ConstraintContextImpl contextImpl = new ConstraintContextImpl( constraintDescriptor
);
- if ( !getConstraint( constraintDescriptor ).isValid( object, contextImpl ) ) {
- for ( ConstraintContextImpl.ErrorMessage error : contextImpl.getErrorMessages() ) {
- final String message = error.getMessage();
- String interpolatedMessage = messageResolver.interpolate(
- message,
- constraintDescriptor,
- object
- );
- ConstraintViolationImpl<T> failingConstraintViolation = new
ConstraintViolationImpl<T>(
- message,
- interpolatedMessage,
- null,
- null,
- null,
- object,
- propertyIter.getOriginalProperty(), //FIXME use error.getProperty()
- null,
- //FIXME why is this a null group!! Used to be "" string should it be
Default. Looks weird
- constraintDescriptor
- );
- addFailingConstraint( failingConstraintViolations, failingConstraintViolation );
+ for ( MetaConstraint metaConstraint : metaConstraints ) {
+ if ( !metaConstraint.getDescriptor().getGroups().contains( expandedGroup ) ) {
+ continue;
}
+
+ ValidationContext<T> context = new ValidationContext<T>( ( T ) value );
+ context.pushProperty( propertyIter.getOriginalProperty() );
+ metaConstraint.validateConstraint( beanType, value, context );
+ failingConstraintViolations.addAll( context.getFailingConstraints() );
}
if ( isGroupSequence && failingConstraintViolations.size() > 0 ) {
@@ -427,7 +325,7 @@
}
/**
- * Returns the constraint descriptor for the given path relative to the specified
validator.
+ * Collects all <code>MetaConstraint</code>s which match the given path
relative to the specified root class.
* <p>
* This method does not traverse an actual object, but rather tries to resolve the
porperty generically.
* </p>
@@ -438,20 +336,16 @@
*
* @param clazz the class type to check for constraints.
* @param propertyIter an instance of <code>PropertyIterator</code>
- *
- * @return The constraint descriptor matching the given path.
+ * @param metaConstraints Set of <code>MetaConstraint</code>s to collect all
matching constraints.
*/
- private ConstraintDescriptor getConstraintDescriptorForPath(Class<?> clazz,
PropertyIterator propertyIter) {
-
- ConstraintDescriptor matchingConstraintDescriptor = null;
+ private void getMetaConstraintsForPath(Class<?> clazz, PropertyIterator
propertyIter, Set<MetaConstraint> metaConstraints) {
propertyIter.split();
if ( !propertyIter.hasNext() ) {
List<MetaConstraint> metaConstraintList = factory.getBeanMetaData( clazz
).geMetaConstraintList();
for ( MetaConstraint metaConstraint : metaConstraintList ) {
- ConstraintDescriptor constraintDescriptor = metaConstraint.getDescriptor();
if ( metaConstraint.getPropertyName().equals( propertyIter.getHead() ) ) {
- matchingConstraintDescriptor = constraintDescriptor;
+ metaConstraints.add( metaConstraint );
}
}
}
@@ -467,67 +361,12 @@
continue;
}
}
-
- matchingConstraintDescriptor = getConstraintDescriptorForPath( ( Class<?> )
type, propertyIter );
+ getMetaConstraintsForPath( ( Class<?> ) type, propertyIter, metaConstraints
);
}
}
}
-
- return matchingConstraintDescriptor;
}
-
- private DesrciptorValueWrapper getConstraintDescriptorAndValueForPath(Class<?>
clazz, PropertyIterator propertyIter, Object value) {
-
- DesrciptorValueWrapper wrapper = null;
- propertyIter.split();
-
-
- // bottom out - there is only one token left
- if ( !propertyIter.hasNext() ) {
- List<MetaConstraint> metaConstraintList = factory.getBeanMetaData( clazz
).geMetaConstraintList();
- for ( MetaConstraint metaConstraint : metaConstraintList ) {
- ConstraintDescriptor constraintDescriptor = metaConstraint.getDescriptor();
- if ( metaConstraint.getPropertyName().equals( propertyIter.getHead() ) ) {
- return new DesrciptorValueWrapper(
- constraintDescriptor, metaConstraint.getValue( value )
- );
- }
- }
- }
- else {
- List<Member> cascadedMembers = factory.getBeanMetaData( clazz
).getCascadedMembers();
- for ( Member m : cascadedMembers ) {
- if ( ReflectionHelper.getPropertyName( m ).equals( propertyIter.getHead() ) ) {
- Object newValue;
- if ( propertyIter.isIndexed() ) {
- newValue = ReflectionHelper.getValue( m, value );
- }
- else {
- newValue = ReflectionHelper.getIndexedValue( value, propertyIter.getIndex() );
- }
- wrapper = getConstraintDescriptorAndValueForPath(
- newValue.getClass(), propertyIter, newValue
- );
- }
- }
- }
-
- return wrapper;
- }
-
-
- private <T> void addFailingConstraint(List<ConstraintViolationImpl<T>>
failingConstraintViolations, ConstraintViolationImpl<T> failingConstraintViolation)
{
- int i = failingConstraintViolations.indexOf( failingConstraintViolation );
- if ( i == -1 ) {
- failingConstraintViolations.add( failingConstraintViolation );
- }
- else {
- failingConstraintViolations.get( i ).addGroups( failingConstraintViolation.getGroups()
);
- }
- }
-
-
/**
* Checks whether the provided group name is a group sequence and if so expands the
group name and add the expanded
* groups names to <code>expandedGroupName</code>.
@@ -556,33 +395,4 @@
}
return isGroupSequence;
}
-
- private Constraint getConstraint(ConstraintDescriptor descriptor) {
- Constraint constraint;
- try {
- //unchecked
- constraint = constraintFactory.getInstance( descriptor.getConstraintClass() );
- }
- catch ( RuntimeException e ) {
- throw new ValidationException( "Unable to instantiate " +
descriptor.getConstraintClass(), e );
- }
-
- try {
- constraint.initialize( descriptor.getAnnotation() );
- }
- catch ( RuntimeException e ) {
- throw new ValidationException( "Unable to intialize " +
constraint.getClass().getName(), e );
- }
- return constraint;
- }
-
- private class DesrciptorValueWrapper {
- final ConstraintDescriptor descriptor;
- final Object value;
-
- DesrciptorValueWrapper(ConstraintDescriptor descriptor, Object value) {
- this.descriptor = descriptor;
- this.value = value;
- }
- }
}
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ValidatorBuilderImpl.java
===================================================================
---
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ValidatorBuilderImpl.java 2009-01-12
22:07:51 UTC (rev 15772)
+++
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ValidatorBuilderImpl.java 2009-01-13
14:46:34 UTC (rev 15773)
@@ -1,10 +1,9 @@
package org.hibernate.validation.impl;
-import javax.validation.ValidatorBuilder;
import javax.validation.MessageResolver;
import javax.validation.TraversableResolver;
import javax.validation.Validator;
-import javax.validation.ConstraintFactory;
+import javax.validation.ValidatorBuilder;
import org.hibernate.validation.engine.ValidatorImpl;
@@ -17,16 +16,13 @@
private final MessageResolver factoryMessageResolver;
private final TraversableResolver factoryTraversableResolver;
private final ValidatorFactoryImpl validatorFactory;
- private final ConstraintFactory constraintFactory;
public ValidatorBuilderImpl(ValidatorFactoryImpl validatorFactory,
MessageResolver factoryMessageResolver,
- TraversableResolver factoryTraversableResolver,
- ConstraintFactory constraintFactory) {
+ TraversableResolver factoryTraversableResolver) {
this.validatorFactory = validatorFactory;
this.factoryMessageResolver = factoryMessageResolver;
this.factoryTraversableResolver = factoryTraversableResolver;
- this.constraintFactory = constraintFactory;
messageResolver(factoryMessageResolver);
traversableResolver(factoryTraversableResolver);
}
@@ -52,6 +48,6 @@
}
public Validator getValidator() {
- return new ValidatorImpl( validatorFactory, messageResolver, traversableResolver,
constraintFactory );
+ return new ValidatorImpl( validatorFactory );
}
}
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ValidatorFactoryImpl.java
===================================================================
---
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ValidatorFactoryImpl.java 2009-01-12
22:07:51 UTC (rev 15772)
+++
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ValidatorFactoryImpl.java 2009-01-13
14:46:34 UTC (rev 15773)
@@ -63,7 +63,7 @@
}
public ValidatorBuilder defineValidatorState() {
- return new ValidatorBuilderImpl(this, messageResolver, traversableResolver,
constraintFactory);
+ return new ValidatorBuilderImpl(this, messageResolver, traversableResolver);
}
public <T> BeanMetaDataImpl<T> getBeanMetaData(Class<T> beanClass) {
@@ -72,7 +72,7 @@
@SuppressWarnings( "unchecked")
BeanMetaDataImpl<T> metadata = ( BeanMetaDataImpl<T> )
metadataProviders.get(beanClass);
if (metadata == null) {
- metadata = new BeanMetaDataImpl<T>(beanClass);
+ metadata = new BeanMetaDataImpl<T>(beanClass, messageResolver,
constraintFactory);
metadataProviders.put( beanClass, metadata );
}
return metadata;
Modified:
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/constraints/composition/GermanZipcode.java
===================================================================
---
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/constraints/composition/GermanZipcode.java 2009-01-12
22:07:51 UTC (rev 15772)
+++
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/constraints/composition/GermanZipcode.java 2009-01-13
14:46:34 UTC (rev 15773)
@@ -25,6 +25,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;
import javax.validation.ConstraintValidator;
+import javax.validation.ReportAsViolationFromCompositeConstraint;
/**
* Constraint used to test nested composing constraints.
@@ -36,6 +37,7 @@
@Documented
@Target({ METHOD, FIELD, TYPE })
@Retention(RUNTIME)
+@ReportAsViolationFromCompositeConstraint
public @interface GermanZipcode {
public abstract String message() default "Falsche Postnummer.";
Modified:
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/ConstraintCompositionTest.java
===================================================================
---
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/ConstraintCompositionTest.java 2009-01-12
22:07:51 UTC (rev 15772)
+++
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/ConstraintCompositionTest.java 2009-01-13
14:46:34 UTC (rev 15773)
@@ -24,15 +24,15 @@
import static org.junit.Assert.fail;
import org.junit.Test;
-import static org.hibernate.validation.util.TestUtil.getValidator;
-import static org.hibernate.validation.util.TestUtil.assertNumberOfViolations;
-import static org.hibernate.validation.util.TestUtil.assertConstraintViolation;
-
import org.hibernate.validation.constraints.NotNullConstraint;
+import org.hibernate.validation.constraints.PatternConstraint;
import org.hibernate.validation.constraints.SizeConstraint;
-import org.hibernate.validation.constraints.PatternConstraint;
+import org.hibernate.validation.constraints.composition.GermanZipcodeConstraint;
import org.hibernate.validation.eg.FrenchAddress;
import org.hibernate.validation.eg.GermanAddress;
+import static org.hibernate.validation.util.TestUtil.assertConstraintViolation;
+import static org.hibernate.validation.util.TestUtil.assertNumberOfViolations;
+import static org.hibernate.validation.util.TestUtil.getValidator;
/**
* Tests for composing constraints.
@@ -147,11 +147,33 @@
assertNumberOfViolations( constraintViolations, 1 );
assertConstraintViolation(
constraintViolations.iterator().next(),
- "may not be null",
- NotNullConstraint.class,
+ "Falsche Postnummer.",
+ GermanZipcodeConstraint.class,
GermanAddress.class,
null,
"zipCode"
);
}
+
+ @Test
+ public void testOnlySingleConstraintViolation() {
+ Validator validator = getValidator();
+
+ GermanAddress address = new GermanAddress();
+ address.setAddressline1( "Rathausstrasse 5" );
+ address.setAddressline2( "3ter Stock" );
+ address.setCity( "Karlsruhe" );
+ address.setZipCode( "abc" );
+ // actually three composing constraints fail, but due to
@ReportAsViolationFromCompositeConstraint only one will be reported.
+ Set<ConstraintViolation<GermanAddress>> constraintViolations =
validator.validate( address );
+ assertNumberOfViolations( constraintViolations, 1 );
+ assertConstraintViolation(
+ constraintViolations.iterator().next(),
+ "Falsche Postnummer.",
+ GermanZipcodeConstraint.class,
+ GermanAddress.class,
+ "abc",
+ "zipCode"
+ );
+ }
}
\ No newline at end of file
Modified: validator/trunk/hibernate-validator/src/test/resources/log4j.properties
===================================================================
--- validator/trunk/hibernate-validator/src/test/resources/log4j.properties 2009-01-12
22:07:51 UTC (rev 15772)
+++ validator/trunk/hibernate-validator/src/test/resources/log4j.properties 2009-01-13
14:46:34 UTC (rev 15773)
@@ -20,6 +20,7 @@
### set log levels - for more verbose logging change 'info' to 'debug'
###
log4j.rootLogger=debug, stdout
-log4j.logger.org.hibernate.validation.engine.ValidatorImpl=trace
+log4j.logger.org.hibernate.validation.engine.ValidatorImpl=debug
+log4j.logger.org.hibernate.validation.engine.ConstraintTree=trace
org.hibernate.validation.impl.ResourceBundleMessageResolver=info
Modified: validator/trunk/pom.xml
===================================================================
--- validator/trunk/pom.xml 2009-01-12 22:07:51 UTC (rev 15772)
+++ validator/trunk/pom.xml 2009-01-13 14:46:34 UTC (rev 15773)
@@ -59,6 +59,11 @@
<artifactId>validation-api</artifactId>
<version>${version}</version>
</dependency>
+ <!--dependency>
+ <groupId>com.google.code.guice</groupId>
+ <artifactId>guice</artifactId>
+ <version>1.0</version>
+ </dependency-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
Modified: validator/trunk/validation-api/src/main/java/javax/validation/Validator.java
===================================================================
---
validator/trunk/validation-api/src/main/java/javax/validation/Validator.java 2009-01-12
22:07:51 UTC (rev 15772)
+++
validator/trunk/validation-api/src/main/java/javax/validation/Validator.java 2009-01-13
14:46:34 UTC (rev 15773)
@@ -17,7 +17,6 @@
*/
package javax.validation;
-import java.io.Serializable;
import java.util.Set;
/**
@@ -30,7 +29,7 @@
*/
public interface Validator {
/**
- * validate all constraints on object
+ * Validates all constraints on object.
*
* @param object object to validate
* @param groups groups targeted for validation
@@ -43,7 +42,7 @@
<T> Set<ConstraintViolation<T>> validate(T object, Class<?>...
groups);
/**
- * validate all constraints on <code>propertyName</code>
property of object
+ * Validates all constraints on <code>propertyName</code>
property of object
*
* @param object object to validate
* @param propertyName property to validate (ie field and getter constraints)
@@ -59,11 +58,12 @@
Class<?>... groups);
/**
- * validate all constraints on <code>propertyName</code> property
+ * Validates all constraints on <code>propertyName</code> property
* if the property value is <code>value</code>
* <p/>
* TODO express limitations of ConstraintViolation in this case
*
+ * @param beanType the bean type
* @param propertyName property to validate
* @param value property value to validate
* @param groups groups targeted for validation
@@ -83,6 +83,7 @@
* are immutable.
*
* @param clazz class type evaluated
+ * @return the bean descriptor for the specified class.
*/
BeanDescriptor getConstraintsForClass(Class<?> clazz);
}