Author: hardy.ferentschik
Date: 2009-06-23 08:59:27 -0400 (Tue, 23 Jun 2009)
New Revision: 16902
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ConstraintValidatorContextImpl.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ExecutionContext.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/NodeImpl.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/PathImpl.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidatorImpl.java
Log:
HV-177
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ConstraintValidatorContextImpl.java
===================================================================
---
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ConstraintValidatorContextImpl.java 2009-06-23
12:57:02 UTC (rev 16901)
+++
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ConstraintValidatorContextImpl.java 2009-06-23
12:59:27 UTC (rev 16902)
@@ -48,7 +48,7 @@
}
public ErrorBuilder buildErrorWithMessageTemplate(String messageTemplate) {
- return null; //To change body of implemented methods use File | Settings | File
Templates.
+ return new ErrorBuilderImpl( messageTemplate, propertyPath );
}
public ConstraintDescriptor<?> getConstraintDescriptor() {
@@ -86,4 +86,103 @@
return propertyPath;
}
}
+
+ class ErrorBuilderImpl implements ErrorBuilder {
+ String messageTemplate;
+ Path propertyPath;
+
+ ErrorBuilderImpl(String template, Path path) {
+ messageTemplate = template;
+ propertyPath = path;
+ }
+
+ public NodeBuilder inSubNode(String name) {
+ PathImpl path = new PathImpl();
+ path.addNode( new NodeImpl( name ) );
+ return new NodeBuilderImpl( messageTemplate, path );
+ }
+
+ public ConstraintValidatorContext addError() {
+ errorMessages.add( new ErrorMessage( messageTemplate, propertyPath ) );
+ return ConstraintValidatorContextImpl.this;
+ }
+ }
+
+ class NodeBuilderImpl implements ErrorBuilder.NodeBuilder {
+ String messageTemplate;
+ PathImpl propertyPath;
+
+ NodeBuilderImpl(String template, PathImpl path) {
+ messageTemplate = template;
+ propertyPath = path;
+ }
+
+ public ErrorBuilder.InIterableNodeBuilder inSubNode(String name) {
+ NodeImpl node = new NodeImpl( name );
+ propertyPath.addNode( node );
+ return new InIterableNodeBuilderImpl( messageTemplate, propertyPath );
+ }
+
+ public ConstraintValidatorContext addError() {
+ errorMessages.add( new ErrorMessage( messageTemplate, propertyPath ) );
+ return ConstraintValidatorContextImpl.this;
+ }
+ }
+
+ class InIterableNodeBuilderImpl implements ErrorBuilder.InIterableNodeBuilder {
+ String messageTemplate;
+ PathImpl propertyPath;
+
+ InIterableNodeBuilderImpl(String template, PathImpl path) {
+ messageTemplate = template;
+ propertyPath = path;
+ }
+
+ public ErrorBuilder.InIterablePropertiesBuilder inIterable() {
+ return new InIterablePropertiesBuilderImpl(messageTemplate, propertyPath);
+ }
+
+ public ErrorBuilder.InIterableNodeBuilder inSubNode(String name) {
+ Path.Node node = new NodeImpl( name );
+ propertyPath.addNode( node );
+ return this;
+ }
+
+ public ConstraintValidatorContext addError() {
+ errorMessages.add( new ErrorMessage( messageTemplate, propertyPath ) );
+ return ConstraintValidatorContextImpl.this;
+ }
+ }
+
+ class InIterablePropertiesBuilderImpl implements
ErrorBuilder.InIterablePropertiesBuilder {
+ String messageTemplate;
+ PathImpl propertyPath;
+
+ InIterablePropertiesBuilderImpl(String template, PathImpl path) {
+ messageTemplate = template;
+ propertyPath = path;
+ propertyPath.getLeafNode().setInIterable( true );
+ }
+
+ public ErrorBuilder.NodeBuilder atKey(Object key) {
+ propertyPath.getLeafNode().setKey( key );
+ return new NodeBuilderImpl( messageTemplate, propertyPath );
+ }
+
+ public ErrorBuilder.NodeBuilder atIndex(Integer index) {
+ propertyPath.getLeafNode().setIndex( index );
+ return new NodeBuilderImpl( messageTemplate, propertyPath );
+ }
+
+ public ErrorBuilder.InIterableNodeBuilder inSubNode(String name) {
+ Path.Node node = new NodeImpl( name );
+ propertyPath.addNode( node );
+ return new InIterableNodeBuilderImpl( messageTemplate, propertyPath );
+ }
+
+ public ConstraintValidatorContext addError() {
+ errorMessages.add( new ErrorMessage( messageTemplate, propertyPath ) );
+ return ConstraintValidatorContextImpl.this;
+ }
+ }
}
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ExecutionContext.java
===================================================================
---
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ExecutionContext.java 2009-06-23
12:57:02 UTC (rev 16901)
+++
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ExecutionContext.java 2009-06-23
12:59:27 UTC (rev 16902)
@@ -22,16 +22,15 @@
import java.lang.reflect.Member;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
-import java.util.HashSet;
import javax.validation.ConstraintValidatorFactory;
import javax.validation.ConstraintViolation;
import javax.validation.MessageInterpolator;
-import javax.validation.Path;
import javax.validation.TraversableResolver;
import javax.validation.metadata.ConstraintDescriptor;
@@ -68,7 +67,7 @@
/**
* Maps an object to a list of paths in which it has been invalidated.
*/
- private final Map<Object, Set<Path>> processedPaths;
+ private final Map<Object, Set<PathImpl>> processedPaths;
/**
* A list of all failing constraints so far.
@@ -95,7 +94,7 @@
*
* @todo Make this boolean a configurable item.
*/
- private boolean allowOneValidationPerPath = false;
+ private boolean allowOneValidationPerPath = true;
/**
* The message resolver which should be used in this context.
@@ -148,7 +147,7 @@
beanStack.push( object );
processedObjects = new HashMap<Class<?>, IdentitySet>();
- processedPaths = new IdentityHashMap<Object, Set<Path>>();
+ processedPaths = new IdentityHashMap<Object, Set<PathImpl>>();
propertyPath = new PathImpl();
failingConstraintViolations = new ArrayList<ConstraintViolation<T>>();
}
@@ -232,29 +231,21 @@
* Drops the last level of the current property path of this context.
*/
public void popProperty() {
- propertyPath.removeLast();
+ propertyPath.removeLeafNode();
}
public void markCurrentPropertyAsIterable() {
- ((NodeImpl)propertyPath.getLast()).setInIterable( true );
+ ( ( NodeImpl ) propertyPath.getLeafNode() ).setInIterable( true );
}
public void setPropertyIndex(String index) {
- ((NodeImpl)propertyPath.getLast()).setIndex( Integer.getInteger( index ) );
+ ( ( NodeImpl ) propertyPath.getLeafNode() ).setIndex( new Integer( index ) );
}
- public Path peekPropertyPath() {
- return new PathImpl(propertyPath);
+ public PathImpl peekPropertyPath() {
+ return new PathImpl( propertyPath );
}
- public Path.Node peekProperty() {
- return propertyPath.getLast();
- }
-
- public Path peekParentPath() {
- return propertyPath.getParentPath();
- }
-
@SuppressWarnings("SimplifiableIfStatement")
public boolean isValidationRequired(MetaConstraint metaConstraint) {
if ( !metaConstraint.getGroupList().contains( currentGroup ) ) {
@@ -263,9 +254,9 @@
return traversableResolver.isReachable(
peekCurrentBean(),
- peekProperty(),
+ propertyPath.getLeafNode(),
getRootBeanClass(),
- peekParentPath(),
+ propertyPath.getPathWithoutLeafNode(),
metaConstraint.getElementType()
);
}
@@ -276,16 +267,16 @@
final Object traversableobject = peekCurrentBean();
return traversableResolver.isReachable(
traversableobject,
- peekProperty(),
+ propertyPath.getLeafNode(),
rootBeanType,
- peekParentPath(),
+ propertyPath.getPathWithoutLeafNode(),
type
)
&& traversableResolver.isCascadable(
traversableobject,
- peekProperty(),
+ propertyPath.getLeafNode(),
rootBeanType,
- peekParentPath(),
+ propertyPath.getPathWithoutLeafNode(),
type
);
}
@@ -320,10 +311,17 @@
}
private boolean isAlreadyValidatedForPath(Object value) {
- Set<Path> pathSet = processedPaths.get( value );
- if(pathSet != null && pathSet.contains( peekPropertyPath() )) {
- return true;
+ Set<PathImpl> pathSet = processedPaths.get( value );
+ if ( pathSet == null ) {
+ return false;
}
+
+ for (PathImpl p : pathSet) {
+ if (p.isSubPathOf(peekPropertyPath()) || peekPropertyPath().isSubPathOf(p)) {
+ return true;
+ }
+ }
+
return false;
}
@@ -344,7 +342,7 @@
processedPaths.get( peekCurrentBean() ).add( peekPropertyPath() );
}
else {
- Set<Path> set = new HashSet<Path>();
+ Set<PathImpl> set = new HashSet<PathImpl>();
set.add( peekPropertyPath() );
processedPaths.put( peekCurrentBean(), set );
}
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/NodeImpl.java
===================================================================
---
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/NodeImpl.java 2009-06-23
12:57:02 UTC (rev 16901)
+++
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/NodeImpl.java 2009-06-23
12:59:27 UTC (rev 16902)
@@ -23,6 +23,10 @@
* @author Hardy Ferentschik
*/
public class NodeImpl implements Path.Node {
+
+ private static final String INDEX_OPEN = "[";
+ private static final String INDEX_CLOSE = "]";
+
private final String name;
private boolean isInIterable;
private Integer index;
@@ -33,6 +37,13 @@
this.name = name;
}
+ NodeImpl(Path.Node node) {
+ this.name = node.getName();
+ this.isInIterable = node.isInIterable();
+ this.index = node.getIndex();
+ this.key = node.getKey();
+ }
+
public String getName() {
return name;
}
@@ -50,6 +61,7 @@
}
public void setIndex(Integer index) {
+ isInIterable = true;
this.index = index;
}
@@ -57,14 +69,25 @@
return key;
}
+ public void setKey(Object key) {
+ isInIterable = true;
+ this.key = key;
+ }
+
@Override
public String toString() {
- return "NodeImpl{" +
- "name='" + name + '\'' +
- ", isInIterable=" + isInIterable +
- ", index=" + index +
- ", key=" + key +
- '}';
+ StringBuilder builder = new StringBuilder( name );
+ if ( isInIterable ) {
+ builder.append( INDEX_OPEN );
+ if ( getIndex() != null ) {
+ builder.append( getIndex() );
+ }
+ else if ( getKey() != null ) {
+ builder.append( getKey() );
+ }
+ builder.append( INDEX_CLOSE );
+ }
+ return builder.toString();
}
@Override
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/PathImpl.java
===================================================================
---
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/PathImpl.java 2009-06-23
12:57:02 UTC (rev 16901)
+++
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/PathImpl.java 2009-06-23
12:59:27 UTC (rev 16902)
@@ -27,30 +27,35 @@
*/
public class PathImpl implements Path {
- public static final String PROPERTY_PATH_SEPERATOR = ".";
+ private static final String PROPERTY_PATH_SEPERATOR = ".";
+ private static final String INDEX_OPEN = "[";
+ private static final String INDEX_CLOSE = "]";
+ private static final Node ROOT_NODE = new NodeImpl( ( String ) null );
+
private final List<Node> nodeList;
public PathImpl() {
nodeList = new ArrayList<Node>();
- Node root = new NodeImpl( null );
- nodeList.add( root );
+ nodeList.add( ROOT_NODE );
}
public PathImpl(PathImpl path) {
- this();
+ this.nodeList = new ArrayList<Node>();
Iterator<Node> iter = path.iterator();
- while(iter.hasNext()) {
- Node node = iter.next();
- nodeList.add(node);
+ while ( iter.hasNext() ) {
+ nodeList.add( new NodeImpl( iter.next() ) );
}
}
- public PathImpl(List<Node> nodeList) {
- this.nodeList = nodeList;
+ private PathImpl(List<Node> nodeList) {
+ this.nodeList = new ArrayList<Node>();
+ for ( Node node : nodeList ) {
+ this.nodeList.add( new NodeImpl( node ) );
+ }
}
- public Path getParentPath() {
+ public Path getPathWithoutLeafNode() {
List<Node> nodes = new ArrayList<Node>( nodeList );
if ( nodes.size() > 1 ) {
nodes.remove( nodes.size() - 1 );
@@ -62,48 +67,56 @@
nodeList.add( node );
}
- public Node removeLast() {
- if ( nodeList.size() < 1 ) {
- throw new IllegalStateException();
+ public Node removeLeafNode() {
+ if ( nodeList.size() == 0 ) {
+ throw new IllegalStateException( "No nodes in path!" );
}
+ if ( nodeList.size() == 1 ) {
+ throw new IllegalStateException( "Root node cannot be removed!" );
+ }
return nodeList.remove( nodeList.size() - 1 );
}
- public Node getLast() {
- if ( nodeList.size() < 1 ) {
- throw new IllegalStateException();
+ public NodeImpl getLeafNode() {
+ if ( nodeList.size() == 0 ) {
+ throw new IllegalStateException( "No nodes in path!" );
}
- return nodeList.get( nodeList.size() - 1 );
+ return ( NodeImpl ) nodeList.get( nodeList.size() - 1 );
}
public Iterator<Path.Node> iterator() {
return nodeList.iterator();
}
+ public boolean isSubPathOf(Path path) {
+ Iterator<Node> pathIter = path.iterator();
+ Iterator<Node> thisIter = iterator();
+ while ( pathIter.hasNext() ) {
+ Node pathNode = pathIter.next();
+ if ( !thisIter.hasNext() ) {
+ return false;
+ }
+ Node thisNode = thisIter.next();
+ if ( !thisNode.equals( pathNode ) ) {
+ return false;
+ }
+ }
+ return true;
+ }
+
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
Iterator<Path.Node> iter = iterator();
while ( iter.hasNext() ) {
Node node = iter.next();
- if ( node.getName() != null ) {
- builder.append( node.getName() );
-
- if ( node.isInIterable() ) {
- builder.append( "[" );
- if ( node.getIndex() != null ) {
- builder.append( node.getIndex() );
- }
- else if ( node.getKey() != null ) {
- builder.append( node.getKey() );
- }
- builder.append( "]" );
- }
- if ( iter.hasNext() ) {
- builder.append( PROPERTY_PATH_SEPERATOR );
-
- }
+ if ( ROOT_NODE.equals( node ) ) {
+ continue;
}
+ builder.append( node.toString() );
+ if ( iter.hasNext() ) {
+ builder.append( PROPERTY_PATH_SEPERATOR );
+ }
}
return builder.toString();
}
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-06-23
12:57:02 UTC (rev 16901)
+++
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidatorImpl.java 2009-06-23
12:59:27 UTC (rev 16902)
@@ -234,7 +234,7 @@
*/
private <T> void validateConstraints(ExecutionContext<T> executionContext)
{
//casting rely on the fact that root object is at the top of the stack
- @SuppressWarnings(" unchecked")
+ @SuppressWarnings("unchecked")
BeanMetaData<T> beanMetaData = getBeanMetaData( ( Class<T> )
executionContext.peekCurrentBeanType() );
if ( executionContext.getCurrentGroup().getName().equals( Default.class.getName() ) )
{
List<Class<?>> defaultGroupSequence =
beanMetaData.getDefaultGroupSequence();