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 2018/04/03 20:30:30 UTC

[2/2] bval git commit: revamp custom constraint building code for TCK progress/spec compliance

revamp custom constraint building code for TCK progress/spec compliance


Project: http://git-wip-us.apache.org/repos/asf/bval/repo
Commit: http://git-wip-us.apache.org/repos/asf/bval/commit/283c4e8c
Tree: http://git-wip-us.apache.org/repos/asf/bval/tree/283c4e8c
Diff: http://git-wip-us.apache.org/repos/asf/bval/diff/283c4e8c

Branch: refs/heads/bv2
Commit: 283c4e8c35eb9f49be56165c96df2e5e125f2ec1
Parents: 9884b56
Author: Matt Benson <mb...@apache.org>
Authored: Tue Apr 3 15:30:21 2018 -0500
Committer: Matt Benson <mb...@apache.org>
Committed: Tue Apr 3 15:30:21 2018 -0500

----------------------------------------------------------------------
 .../jsr/job/ConstraintValidatorContextImpl.java | 72 +++++++++++++-------
 .../apache/bval/jsr/job/ValidateParameters.java |  5 +-
 .../bval/jsr/job/ValidateReturnValue.java       |  7 +-
 .../org/apache/bval/jsr/job/ValidationJob.java  |  9 ++-
 ...ementNodeBuilderCustomizableContextImpl.java | 30 +++-----
 ...nerElementNodeBuilderDefinedContextImpl.java | 22 +++---
 .../ContainerElementNodeContextBuilderImpl.java | 38 ++++-------
 .../LeafNodeBuilderCustomizableContextImpl.java | 32 ++++-----
 .../NodeBuilderCustomizableContextImpl.java     | 52 +++++---------
 .../jsr/util/NodeBuilderDefinedContextImpl.java | 24 +++----
 .../bval/jsr/util/NodeContextBuilderImpl.java   | 51 ++++++--------
 .../java/org/apache/bval/jsr/util/NodeImpl.java |  5 ++
 .../java/org/apache/bval/jsr/util/PathImpl.java | 33 ++++-----
 13 files changed, 173 insertions(+), 207 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/bval/blob/283c4e8c/bval-jsr/src/main/java/org/apache/bval/jsr/job/ConstraintValidatorContextImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ConstraintValidatorContextImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ConstraintValidatorContextImpl.java
index d536e89..156fa79 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ConstraintValidatorContextImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ConstraintValidatorContextImpl.java
@@ -24,6 +24,7 @@ import java.util.Set;
 import javax.validation.ClockProvider;
 import javax.validation.ConstraintValidatorContext;
 import javax.validation.ConstraintViolation;
+import javax.validation.ElementKind;
 import javax.validation.MessageInterpolator;
 import javax.validation.ValidationException;
 import javax.validation.metadata.ConstraintDescriptor;
@@ -43,10 +44,12 @@ import org.apache.bval.util.Lazy;
 import org.apache.bval.util.Validate;
 
 public class ConstraintValidatorContextImpl<T> implements ConstraintValidatorContext, MessageInterpolator.Context {
-    private class ConstraintViolationBuilderImpl implements ConstraintValidatorContext.ConstraintViolationBuilder {
+    public class ConstraintViolationBuilderImpl implements ConstraintValidatorContext.ConstraintViolationBuilder {
         private final String template;
         private final PathImpl path;
 
+        private boolean complete;
+
         ConstraintViolationBuilderImpl(String template, PathImpl path) {
             this.template = template;
             this.path = path;
@@ -57,29 +60,22 @@ public class ConstraintValidatorContextImpl<T> implements ConstraintValidatorCon
          */
         @Override
         public NodeBuilderDefinedContext addNode(String name) {
-            PathImpl p;
-            if (path.isRootPath()) {
-                p = PathImpl.create();
-                p.getLeafNode().setName(name);
-            } else {
-                p = PathImpl.copy(path);
-                p.addNode(new NodeImpl.PropertyNodeImpl(name));
-            }
-            return new NodeBuilderDefinedContextImpl(ConstraintValidatorContextImpl.this, template, p);
+            return new NodeBuilderDefinedContextImpl(extensiblePath().addProperty(name), this);
         }
 
         @Override
         public NodeBuilderCustomizableContext addPropertyNode(String name) {
-            return new NodeBuilderCustomizableContextImpl(ConstraintValidatorContextImpl.this, template, path, name);
+            return new NodeBuilderCustomizableContextImpl(extensiblePath(), name, this);
         }
 
         @Override
         public LeafNodeBuilderCustomizableContext addBeanNode() {
-            return new LeafNodeBuilderCustomizableContextImpl(ConstraintValidatorContextImpl.this, template, path);
+            return new LeafNodeBuilderCustomizableContextImpl(extensiblePath(), this);
         }
 
         @Override
         public NodeBuilderDefinedContext addParameterNode(int index) {
+            ofLegalState();
             Exceptions.raiseUnless(frame.descriptor instanceof CrossParameterDescriptor, ValidationException::new,
                 "Cannot add parameter node for %s", f -> f.args(frame.descriptor.getClass().getName()));
 
@@ -88,12 +84,9 @@ public class ConstraintValidatorContextImpl<T> implements ConstraintValidatorCon
 
             final String parameterName = crossParameter.getParent().getParameterDescriptors().get(index).getName();
 
-            final NodeImpl node = new NodeImpl.ParameterNodeImpl(parameterName, index);
-            if (!path.isRootPath()) {
-                path.removeLeafNode();
-            }
-            path.addNode(node);
-            return new NodeBuilderDefinedContextImpl(ConstraintValidatorContextImpl.this, template, path);
+            path.removeLeafNode();
+            return new NodeBuilderDefinedContextImpl(path.addNode(new NodeImpl.ParameterNodeImpl(parameterName, index)),
+                this);
         }
 
         /**
@@ -101,15 +94,42 @@ public class ConstraintValidatorContextImpl<T> implements ConstraintValidatorCon
          */
         @Override
         public ConstraintValidatorContext addConstraintViolation() {
-            addError(template, path);
+            return addConstraintViolation(path);
+        }
+
+        public synchronized ConstraintViolationBuilderImpl ofLegalState() {
+            Validate.validState(!complete, "#addConstraintViolation() already called");
+            return this;
+        }
+
+        public ConstraintValidatorContext addConstraintViolation(PathImpl p) {
+            synchronized (this) {
+                ofLegalState();
+                complete = true;
+            }
+            addError(template, p);
             return ConstraintValidatorContextImpl.this;
         }
 
         @Override
         public ContainerElementNodeBuilderCustomizableContext addContainerElementNode(String name,
             Class<?> containerType, Integer typeArgumentIndex) {
-            return new ContainerElementNodeBuilderCustomizableContextImpl(ConstraintValidatorContextImpl.this, template,
-                path, name, containerType, typeArgumentIndex);
+            ofLegalState();
+            return new ContainerElementNodeBuilderCustomizableContextImpl(extensiblePath(), name,
+                containerType, typeArgumentIndex, this);
+        }
+
+        private PathImpl extensiblePath() {
+            if (path.isRootPath()) {
+                return PathImpl.create();
+            }
+            final PathImpl result = PathImpl.copy(path);
+            final NodeImpl leafNode = result.getLeafNode();
+            if (leafNode.getKind() == ElementKind.BEAN
+                && !(leafNode.isInIterable() || leafNode.getContainerClass() != null)) {
+                result.removeLeafNode();
+            }
+            return result;
         }
     }
 
@@ -153,11 +173,6 @@ public class ConstraintValidatorContextImpl<T> implements ConstraintValidatorCon
         }
     }
 
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public void addError(String messageTemplate, PathImpl propertyPath) {
-        violations.get().add(((ValidationJob) frame.getJob()).createViolation(messageTemplate, this, propertyPath));
-    }
-
     ValidationJob<T>.Frame<?> getFrame() {
         return frame;
     }
@@ -181,4 +196,9 @@ public class ConstraintValidatorContextImpl<T> implements ConstraintValidatorCon
     public Object getValidatedValue() {
         return frame.context.getValue();
     }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    private void addError(String messageTemplate, PathImpl propertyPath) {
+        violations.get().add(((ValidationJob) frame.getJob()).createViolation(messageTemplate, this, propertyPath));
+    }
 }

http://git-wip-us.apache.org/repos/asf/bval/blob/283c4e8c/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateParameters.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateParameters.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateParameters.java
index 777ff1a..4adc4a9 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateParameters.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateParameters.java
@@ -162,9 +162,8 @@ public abstract class ValidateParameters<E extends Executable, T> extends Valida
 
     @Override
     protected Frame<?> computeBaseFrame() {
-        final PathImpl cp = createBasePath();
-        cp.addNode(new NodeImpl.CrossParameterNodeImpl());
-        return new ParametersFrame(describe(), new GraphContext(validatorContext, cp, parameterValues));
+        return new ParametersFrame(describe(), new GraphContext(validatorContext,
+            createBasePath().addNode(new NodeImpl.CrossParameterNodeImpl()), parameterValues));
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/bval/blob/283c4e8c/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java
index 4b469bb..774566a 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java
@@ -130,11 +130,8 @@ public abstract class ValidateReturnValue<E extends Executable, T> extends Valid
 
     @Override
     protected Frame<?> computeBaseFrame() {
-        final PathImpl path = createBasePath();
-        path.addNode(new NodeImpl.ReturnValueNodeImpl());
-
-        return createBaseFrame((ReturnValueD<?, ?>) describe().getReturnValueDescriptor(),
-            new GraphContext(validatorContext, path, returnValue));
+        return createBaseFrame((ReturnValueD<?, ?>) describe().getReturnValueDescriptor(), new GraphContext(
+            validatorContext, createBasePath().addNode(new NodeImpl.ReturnValueNodeImpl()), returnValue));
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/bval/blob/283c4e8c/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java
index 46246b4..0bbf17d 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java
@@ -252,13 +252,16 @@ public abstract class ValidationJob<T> {
     }
 
     public class BeanFrame<B> extends Frame<BeanD<B>> {
+        private final GraphContext realContext;
 
         BeanFrame(GraphContext context) {
             this(null, context);
         }
 
         BeanFrame(Frame<?> parent, GraphContext context) {
-            super(parent, getBeanDescriptor(context.getValue()), context);
+            super(parent, getBeanDescriptor(context.getValue()),
+                context.child(context.getPath().addBean(), context.getValue()));
+            this.realContext = context;
         }
 
         @Override
@@ -282,7 +285,7 @@ public abstract class ValidationJob<T> {
             final TraversableResolver traversableResolver = validatorContext.getTraversableResolver();
 
             final Stream<PropertyD<?>> reachableProperties = properties.filter(d -> {
-                final PathImpl p = context.getPath();
+                final PathImpl p = realContext.getPath();
                 p.addProperty(d.getPropertyName());
                 try {
                     return traversableResolver.isReachable(context.getValue(), p.removeLeafNode(), getRootBeanClass(),
@@ -294,7 +297,7 @@ public abstract class ValidationJob<T> {
                 }
             });
             return reachableProperties.flatMap(
-                d -> d.read(context).filter(context -> !context.isRecursive()).map(child -> propertyFrame(d, child)));
+                d -> d.read(realContext).filter(context -> !context.isRecursive()).map(child -> propertyFrame(d, child)));
         }
     }
 

http://git-wip-us.apache.org/repos/asf/bval/blob/283c4e8c/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeBuilderCustomizableContextImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeBuilderCustomizableContextImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeBuilderCustomizableContextImpl.java
index 7459fdc..f60d1e4 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeBuilderCustomizableContextImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeBuilderCustomizableContextImpl.java
@@ -28,50 +28,40 @@ import org.apache.bval.jsr.job.ConstraintValidatorContextImpl;
 
 public class ContainerElementNodeBuilderCustomizableContextImpl
     implements ContainerElementNodeBuilderCustomizableContext {
-    private final ConstraintValidatorContextImpl<?> context;
-    private final String template;
     private final PathImpl path;
-    private NodeImpl node;
+    private final ConstraintValidatorContextImpl<?>.ConstraintViolationBuilderImpl builder;
 
-    public ContainerElementNodeBuilderCustomizableContextImpl(ConstraintValidatorContextImpl<?> context, String template,
-        PathImpl path, String name, Class<?> containerType, Integer typeArgumentIndex) {
+    public ContainerElementNodeBuilderCustomizableContextImpl(PathImpl path, String name, Class<?> containerType,
+        Integer typeArgumentIndex, ConstraintValidatorContextImpl<?>.ConstraintViolationBuilderImpl builder) {
         super();
-        this.context = context;
-        this.path = path;
-        this.template = template;
-        this.node = new NodeImpl.ContainerElementNodeImpl(name, containerType, typeArgumentIndex);
+        this.builder = builder.ofLegalState();
+        this.path = path.addNode(new NodeImpl.ContainerElementNodeImpl(name, containerType, typeArgumentIndex));
     }
 
     @Override
     public ContainerElementNodeContextBuilder inIterable() {
-        node.setInIterable(true);
-        return new ContainerElementNodeContextBuilderImpl(context, template, path, node);
+        return new ContainerElementNodeContextBuilderImpl(path, builder);
     }
 
     @Override
     public NodeBuilderCustomizableContext addPropertyNode(String name) {
-        path.addNode(node);
-        return new NodeBuilderCustomizableContextImpl(context, template, path, name);
+        return new NodeBuilderCustomizableContextImpl(path, name, builder);
     }
 
     @Override
     public LeafNodeBuilderCustomizableContext addBeanNode() {
-        path.addNode(node);
-        return new LeafNodeBuilderCustomizableContextImpl(context, template, path);
+        return new LeafNodeBuilderCustomizableContextImpl(path, builder);
     }
 
     @Override
     public ContainerElementNodeBuilderCustomizableContext addContainerElementNode(String name, Class<?> containerType,
         Integer typeArgumentIndex) {
-        path.addNode(node);
-        node = new NodeImpl.ContainerElementNodeImpl(name, containerType, typeArgumentIndex);
+        path.addNode(new NodeImpl.ContainerElementNodeImpl(name, containerType, typeArgumentIndex));
         return this;
     }
 
     @Override
     public ConstraintValidatorContext addConstraintViolation() {
-        path.addNode(node);
-        context.addError(template, path);
-        return context;
+        return builder.addConstraintViolation(path);
     }
 }

http://git-wip-us.apache.org/repos/asf/bval/blob/283c4e8c/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeBuilderDefinedContextImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeBuilderDefinedContextImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeBuilderDefinedContextImpl.java
index 6077d87..013b86d 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeBuilderDefinedContextImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeBuilderDefinedContextImpl.java
@@ -27,39 +27,35 @@ import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.No
 import org.apache.bval.jsr.job.ConstraintValidatorContextImpl;
 
 public class ContainerElementNodeBuilderDefinedContextImpl implements ContainerElementNodeBuilderDefinedContext {
-    private final ConstraintValidatorContextImpl<?> context;
-    private final String template;
+    private final ConstraintValidatorContextImpl<?>.ConstraintViolationBuilderImpl builder;
     private final PathImpl path;
 
-    ContainerElementNodeBuilderDefinedContextImpl(ConstraintValidatorContextImpl<?> context, String template,
-        PathImpl path) {
+    ContainerElementNodeBuilderDefinedContextImpl(PathImpl path,
+        ConstraintValidatorContextImpl<?>.ConstraintViolationBuilderImpl builder) {
         super();
-        this.context = context;
-        this.template = template;
         this.path = path;
+        this.builder = builder.ofLegalState();
     }
 
     @Override
     public NodeBuilderCustomizableContext addPropertyNode(String name) {
-        return new NodeBuilderCustomizableContextImpl(context, template, path, name);
+        return new NodeBuilderCustomizableContextImpl(path, name, builder);
     }
 
     @Override
     public LeafNodeBuilderCustomizableContext addBeanNode() {
-        return new LeafNodeBuilderCustomizableContextImpl(context, template, path);
+        return new LeafNodeBuilderCustomizableContextImpl(path, builder);
     }
 
     @Override
     public ContainerElementNodeBuilderCustomizableContext addContainerElementNode(String name, Class<?> containerType,
         Integer typeArgumentIndex) {
-        return new ContainerElementNodeBuilderCustomizableContextImpl(context, name, path, name, containerType,
-            typeArgumentIndex);
+        return new ContainerElementNodeBuilderCustomizableContextImpl(path, name, containerType, typeArgumentIndex,
+            builder);
     }
 
     @Override
     public ConstraintValidatorContext addConstraintViolation() {
-        context.addError(template, path);
-        return context;
+        return builder.addConstraintViolation(path);
     }
-
 }

http://git-wip-us.apache.org/repos/asf/bval/blob/283c4e8c/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeContextBuilderImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeContextBuilderImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeContextBuilderImpl.java
index f05ef76..aeff169 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeContextBuilderImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeContextBuilderImpl.java
@@ -28,58 +28,48 @@ import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.No
 import org.apache.bval.jsr.job.ConstraintValidatorContextImpl;
 
 public class ContainerElementNodeContextBuilderImpl implements ContainerElementNodeContextBuilder {
-    private final ConstraintValidatorContextImpl<?> context;
-    private final String template;
     private final PathImpl path;
-    private final NodeImpl node;
+    private ConstraintValidatorContextImpl<?>.ConstraintViolationBuilderImpl builder;
 
-    ContainerElementNodeContextBuilderImpl(ConstraintValidatorContextImpl<?> context, String template,
-        PathImpl path, NodeImpl node) {
+    ContainerElementNodeContextBuilderImpl(PathImpl path,
+        ConstraintValidatorContextImpl<?>.ConstraintViolationBuilderImpl builder) {
         super();
-        this.context = context;
-        this.template = template;
+        this.builder = builder.ofLegalState();
         this.path = path;
-        this.node = node;
+        path.getLeafNode().inIterable();
     }
 
     @Override
     public ContainerElementNodeBuilderDefinedContext atKey(Object key) {
-        node.setKey(key);
-        path.addNode(node);
-        return new ContainerElementNodeBuilderDefinedContextImpl(context, template, path);
+        path.getLeafNode().setKey(key);
+        return new ContainerElementNodeBuilderDefinedContextImpl(path, builder);
     }
 
     @Override
     public ContainerElementNodeBuilderDefinedContext atIndex(Integer index) {
-        node.setIndex(index);
-        path.addNode(node);
-        return new ContainerElementNodeBuilderDefinedContextImpl(context, template, path);
+        path.getLeafNode().setIndex(index);
+        return new ContainerElementNodeBuilderDefinedContextImpl(path, builder);
     }
 
     @Override
     public NodeBuilderCustomizableContext addPropertyNode(String name) {
-        path.addNode(node);
-        return new NodeBuilderCustomizableContextImpl(context, name, path, name);
+        return new NodeBuilderCustomizableContextImpl(path, name, builder);
     }
 
     @Override
     public LeafNodeBuilderCustomizableContext addBeanNode() {
-        path.addNode(node);
-        return new LeafNodeBuilderCustomizableContextImpl(context, template, path);
+        return new LeafNodeBuilderCustomizableContextImpl(path, builder);
     }
 
     @Override
     public ContainerElementNodeBuilderCustomizableContext addContainerElementNode(String name, Class<?> containerType,
         Integer typeArgumentIndex) {
-        path.addNode(node);
-        return new ContainerElementNodeBuilderCustomizableContextImpl(context, template, path, name, containerType,
-            typeArgumentIndex);
+        return new ContainerElementNodeBuilderCustomizableContextImpl(path, name, containerType, typeArgumentIndex,
+            builder);
     }
 
     @Override
     public ConstraintValidatorContext addConstraintViolation() {
-        context.addError(template, path);
-        return context;
+        return builder.addConstraintViolation(path);
     }
-
 }

http://git-wip-us.apache.org/repos/asf/bval/blob/283c4e8c/bval-jsr/src/main/java/org/apache/bval/jsr/util/LeafNodeBuilderCustomizableContextImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/LeafNodeBuilderCustomizableContextImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/LeafNodeBuilderCustomizableContextImpl.java
index 99305be..527b56c 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/util/LeafNodeBuilderCustomizableContextImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/LeafNodeBuilderCustomizableContextImpl.java
@@ -18,13 +18,13 @@
  */
 package org.apache.bval.jsr.util;
 
-import org.apache.bval.jsr.job.ConstraintValidatorContextImpl;
-
 import javax.validation.ConstraintValidatorContext;
 import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeBuilderCustomizableContext;
 import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeBuilderDefinedContext;
 import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeContextBuilder;
 
+import org.apache.bval.jsr.job.ConstraintValidatorContextImpl;
+
 public class LeafNodeBuilderCustomizableContextImpl
     implements ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeBuilderCustomizableContext {
 
@@ -39,13 +39,13 @@ public class LeafNodeBuilderCustomizableContextImpl
 
         @Override
         public LeafNodeBuilderDefinedContext atKey(Object key) {
-            node.setKey(key);
+            path.getLeafNode().setKey(key);
             return definedContext;
         }
 
         @Override
         public LeafNodeBuilderDefinedContext atIndex(Integer index) {
-            node.setIndex(index);
+            path.getLeafNode().setIndex(index);
             return definedContext;
         }
 
@@ -55,35 +55,31 @@ public class LeafNodeBuilderCustomizableContextImpl
         }
     }
 
-    private final ConstraintValidatorContextImpl<?> context;
+    private final ConstraintValidatorContextImpl<?>.ConstraintViolationBuilderImpl builder;
     private final PathImpl path;
-    private final String template;
-    private final NodeImpl node;
 
-    public LeafNodeBuilderCustomizableContextImpl(final ConstraintValidatorContextImpl<?> context, String template,
-        PathImpl path) {
-        this.context = context;
-        this.template = template;
-        this.path = path;
-        node = new NodeImpl.BeanNodeImpl();
+    public LeafNodeBuilderCustomizableContextImpl(
+        PathImpl path, ConstraintValidatorContextImpl<?>.ConstraintViolationBuilderImpl builder) {
+        this.builder = builder.ofLegalState();
+        this.path = path.addBean();
     }
 
     @Override
     public LeafNodeContextBuilder inIterable() {
-        node.setInIterable(true);
+        builder.ofLegalState();
+        path.getLeafNode().setInIterable(true);
         return new LeafNodeContextBuilderImpl();
     }
 
     @Override
     public ConstraintValidatorContext addConstraintViolation() {
-        path.addNode(node);
-        context.addError(template, path);
-        return context;
+        return builder.addConstraintViolation(path);
     }
 
     @Override
     public LeafNodeBuilderCustomizableContext inContainer(Class<?> containerType, Integer typeArgumentIndex) {
-        node.inContainer(containerType, typeArgumentIndex);
+        builder.ofLegalState();
+        path.getLeafNode().inContainer(containerType, typeArgumentIndex);
         return this;
     }
 }

http://git-wip-us.apache.org/repos/asf/bval/blob/283c4e8c/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeBuilderCustomizableContextImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeBuilderCustomizableContextImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeBuilderCustomizableContextImpl.java
index d349cb5..3f1f288 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeBuilderCustomizableContextImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeBuilderCustomizableContextImpl.java
@@ -25,34 +25,25 @@ import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.No
 import org.apache.bval.jsr.job.ConstraintValidatorContextImpl;
 
 /**
- * Description: implementation of {@link javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext}.<br/>
+ * Description: implementation of
+ * {@link javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext}.<br/>
  */
 public final class NodeBuilderCustomizableContextImpl
     implements ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext {
-    private final ConstraintValidatorContextImpl<?> context;
-    private final String template;
     private final PathImpl path;
-    private NodeImpl node;
+    private final ConstraintValidatorContextImpl<?>.ConstraintViolationBuilderImpl builder;
 
     /**
      * Create a new NodeBuilderCustomizableContextImpl instance.
-     * @param context
-     * @param template
+     * 
      * @param path
      * @param name
+     * @param builder
      */
-    public NodeBuilderCustomizableContextImpl(ConstraintValidatorContextImpl<?> context, String template, PathImpl path,
-        String name) {
-        this.context = context;
-        this.template = template;
-        this.path = path;
-
-        if (path.isRootPath() || path.getLeafNode().getName() != null) {
-            node = new NodeImpl.PropertyNodeImpl(name);
-        } else {
-            node = new NodeImpl.PropertyNodeImpl(path.removeLeafNode());
-            node.setName(name);
-        }
+    public NodeBuilderCustomizableContextImpl(PathImpl path, String name,
+        ConstraintValidatorContextImpl<?>.ConstraintViolationBuilderImpl builder) {
+        this.builder = builder.ofLegalState();
+        this.path = path.addProperty(name);
     }
 
     /**
@@ -60,8 +51,7 @@ public final class NodeBuilderCustomizableContextImpl
      */
     @Override
     public ConstraintValidatorContext.ConstraintViolationBuilder.NodeContextBuilder inIterable() {
-        node.setInIterable(true);
-        return new NodeContextBuilderImpl(context, template, path, node);
+        return new NodeContextBuilderImpl(path, builder);
     }
 
     /**
@@ -75,15 +65,14 @@ public final class NodeBuilderCustomizableContextImpl
     @Override
     public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext addPropertyNode(
         String name) {
-        path.addNode(node);
-        node = new NodeImpl.PropertyNodeImpl(name);
+        builder.ofLegalState();
+        path.addProperty(name);
         return this;
     }
 
     @Override
     public ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeBuilderCustomizableContext addBeanNode() {
-        path.addNode(node);
-        return new LeafNodeBuilderCustomizableContextImpl(context, template, path);
+        return new LeafNodeBuilderCustomizableContextImpl(path, builder);
     }
 
     /**
@@ -91,25 +80,20 @@ public final class NodeBuilderCustomizableContextImpl
      */
     @Override
     public ConstraintValidatorContext addConstraintViolation() {
-        path.addNode(node);
-        node = null;
-        context.addError(template, path);
-        return context;
+        return builder.addConstraintViolation(path);
     }
 
     @Override
     public NodeBuilderCustomizableContext inContainer(Class<?> containerClass, Integer typeArgumentIndex) {
-        node.inContainer(containerClass, typeArgumentIndex);
+        builder.ofLegalState();
+        path.getLeafNode().inContainer(containerClass, typeArgumentIndex);
         return this;
     }
 
     @Override
     public ContainerElementNodeBuilderCustomizableContext addContainerElementNode(String name, Class<?> containerType,
         Integer typeArgumentIndex) {
-        path.addNode(node);
-        node = new NodeImpl.ContainerElementNodeImpl(name, containerType, typeArgumentIndex);
-        return new ContainerElementNodeBuilderCustomizableContextImpl(context, template, path, name, containerType,
-            typeArgumentIndex);
+        return new ContainerElementNodeBuilderCustomizableContextImpl(path, name, containerType, typeArgumentIndex,
+            builder);
     }
-
 }

http://git-wip-us.apache.org/repos/asf/bval/blob/283c4e8c/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeBuilderDefinedContextImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeBuilderDefinedContextImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeBuilderDefinedContextImpl.java
index 5a20e08..4d6ba24 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeBuilderDefinedContextImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeBuilderDefinedContextImpl.java
@@ -28,20 +28,19 @@ import org.apache.bval.jsr.job.ConstraintValidatorContextImpl;
  */
 public final class NodeBuilderDefinedContextImpl
     implements ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderDefinedContext {
-    private final ConstraintValidatorContextImpl<?> context;
-    private final String template;
     private final PathImpl path;
+    private final ConstraintValidatorContextImpl<?>.ConstraintViolationBuilderImpl builder;
 
     /**
      * Create a new NodeBuilderDefinedContextImpl instance.
-     * @param contextImpl
-     * @param template
+     * 
      * @param path
+     * @param builder
      */
-    public NodeBuilderDefinedContextImpl(ConstraintValidatorContextImpl<?> contextImpl, String template, PathImpl path) {
-        this.context = contextImpl;
-        this.template = template;
+    public NodeBuilderDefinedContextImpl(PathImpl path,
+        ConstraintValidatorContextImpl<?>.ConstraintViolationBuilderImpl builder) {
         this.path = path;
+        this.builder = builder.ofLegalState();
     }
 
     /**
@@ -55,12 +54,12 @@ public final class NodeBuilderDefinedContextImpl
     @Override
     public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext addPropertyNode(
         String name) {
-        return new NodeBuilderCustomizableContextImpl(context, template, path, name);
+        return new NodeBuilderCustomizableContextImpl(path, name, builder);
     }
 
     @Override
     public ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeBuilderCustomizableContext addBeanNode() {
-        return new LeafNodeBuilderCustomizableContextImpl(context, template, path);
+        return new LeafNodeBuilderCustomizableContextImpl(path, builder);
     }
 
     /**
@@ -68,14 +67,13 @@ public final class NodeBuilderDefinedContextImpl
      */
     @Override
     public ConstraintValidatorContext addConstraintViolation() {
-        context.addError(template, path);
-        return context;
+        return builder.addConstraintViolation(path);
     }
 
     @Override
     public ContainerElementNodeBuilderCustomizableContext addContainerElementNode(String name, Class<?> containerType,
         Integer typeArgumentIndex) {
-        return new ContainerElementNodeBuilderCustomizableContextImpl(context, template, path, name, containerType,
-            typeArgumentIndex);
+        return new ContainerElementNodeBuilderCustomizableContextImpl(path, name, containerType, typeArgumentIndex,
+            builder);
     }
 }

http://git-wip-us.apache.org/repos/asf/bval/blob/283c4e8c/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeContextBuilderImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeContextBuilderImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeContextBuilderImpl.java
index f32db9f..40c3c60 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeContextBuilderImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeContextBuilderImpl.java
@@ -18,34 +18,30 @@
  */
 package org.apache.bval.jsr.util;
 
-import org.apache.bval.jsr.job.ConstraintValidatorContextImpl;
-
 import javax.validation.ConstraintValidatorContext;
 import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.ContainerElementNodeBuilderCustomizableContext;
 import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.NodeContextBuilder;
 
+import org.apache.bval.jsr.job.ConstraintValidatorContextImpl;
+
 /**
  * Description: Implementation of {@link NodeContextBuilder}.<br/>
  */
-public final class NodeContextBuilderImpl implements ConstraintValidatorContext.ConstraintViolationBuilder.NodeContextBuilder {
-    private final ConstraintValidatorContextImpl<?> context;
-    private final String template;
+public final class NodeContextBuilderImpl
+    implements ConstraintValidatorContext.ConstraintViolationBuilder.NodeContextBuilder {
+    private final ConstraintValidatorContextImpl<?>.ConstraintViolationBuilderImpl builder;
     private final PathImpl path;
-    // The name of the last "added" node, it will only be added if it has a non-null name
-    // The actual incorporation in the path will take place when the definition of the current leaf node is complete
-    private final NodeImpl node;
 
     /**
      * Create a new NodeContextBuilderImpl instance.
-     * @param contextImpl
-     * @param template
+     * 
      * @param path
+     * @param builder
      */
-    NodeContextBuilderImpl(ConstraintValidatorContextImpl<?> contextImpl, String template, PathImpl path, NodeImpl node) {
-        this.context = contextImpl;
-        this.template = template;
+    NodeContextBuilderImpl(PathImpl path, ConstraintValidatorContextImpl<?>.ConstraintViolationBuilderImpl builder) {
+        this.builder = builder.ofLegalState();
         this.path = path;
-        this.node = node;
+        path.getLeafNode().inIterable();
     }
 
     /**
@@ -53,9 +49,8 @@ public final class NodeContextBuilderImpl implements ConstraintValidatorContext.
      */
     @Override
     public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderDefinedContext atKey(Object key) {
-        node.setKey(key);
-        path.addNode(node);
-        return new NodeBuilderDefinedContextImpl(context, template, path);
+        path.getLeafNode().setKey(key);
+        return new NodeBuilderDefinedContextImpl(path, builder);
     }
 
     /**
@@ -63,9 +58,8 @@ public final class NodeContextBuilderImpl implements ConstraintValidatorContext.
      */
     @Override
     public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderDefinedContext atIndex(Integer index) {
-        node.setIndex(index);
-        path.addNode(node);
-        return new NodeBuilderDefinedContextImpl(context, template, path);
+        path.getLeafNode().setIndex(index);
+        return new NodeBuilderDefinedContextImpl(path, builder);
     }
 
     /**
@@ -79,14 +73,12 @@ public final class NodeContextBuilderImpl implements ConstraintValidatorContext.
     @Override
     public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext addPropertyNode(
         String name) {
-        path.addNode(node);
-        return new NodeBuilderCustomizableContextImpl(context, template, path, name);
+        return new NodeBuilderCustomizableContextImpl(path, name, builder);
     }
 
     @Override
     public ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeBuilderCustomizableContext addBeanNode() {
-        path.addNode(node);
-        return new LeafNodeBuilderCustomizableContextImpl(context, template, path);
+        return new LeafNodeBuilderCustomizableContextImpl(path, builder);
     }
 
     /**
@@ -94,18 +86,13 @@ public final class NodeContextBuilderImpl implements ConstraintValidatorContext.
      */
     @Override
     public ConstraintValidatorContext addConstraintViolation() {
-        path.addNode(node);
-        context.addError(template, path);
-        return context;
+        return builder.addConstraintViolation(path);
     }
 
     @Override
     public ContainerElementNodeBuilderCustomizableContext addContainerElementNode(String name, Class<?> containerType,
         Integer typeArgumentIndex) {
-        final NodeImpl node = new NodeImpl.ContainerElementNodeImpl(name, containerType, typeArgumentIndex);
-        path.addNode(node);
-        return new ContainerElementNodeBuilderCustomizableContextImpl(context, template, path, name, containerType,
-            typeArgumentIndex);
+        return new ContainerElementNodeBuilderCustomizableContextImpl(path, name, containerType, typeArgumentIndex,
+            builder);
     }
-
 }

http://git-wip-us.apache.org/repos/asf/bval/blob/283c4e8c/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeImpl.java
index 9f7b0c3..57bf7c0 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeImpl.java
@@ -384,6 +384,11 @@ public abstract class NodeImpl implements Path.Node, Serializable {
         return typeArgumentIndex;
     }
 
+    public NodeImpl inIterable() {
+        setInIterable(true);
+        return this;
+    }
+
     public NodeImpl inContainer(Class<?> containerType, Integer typeArgumentIndex) {
         this.containerType = containerType;
         this.typeArgumentIndex = typeArgumentIndex;

http://git-wip-us.apache.org/repos/asf/bval/blob/283c4e8c/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathImpl.java
index 54ad138..841d1e0 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathImpl.java
@@ -188,37 +188,28 @@ public class PathImpl implements Path, Serializable {
     }
 
     /**
-     * Return a new {@link PathImpl} that represents <code>this</code> minus its leaf node (if present).
-     * 
-     * @return PathImpl
-     */
-    public PathImpl getPathWithoutLeafNode() {
-        if (nodeList.size() < 2) {
-            return null;
-        }
-        return new PathImpl(nodeList.subList(0, nodeList.size() - 1));
-    }
-
-    /**
      * Add a node to this {@link PathImpl}.
      * 
      * @param node
      *            to add
+     * @return {@code this}, fluently
      */
-    public void addNode(Node node) {
+    public PathImpl addNode(Node node) {
         final NodeImpl impl = node instanceof NodeImpl ? (NodeImpl) node : newNode(node);
         if (isRootPath()) {
             nodeList.pop();
         }
         nodeList.add(impl);
+        return this;
     }
 
     /**
      * Encapsulate the node manipulations needed to add a named property to this path.
      * 
      * @param name
+     * @return {@code this}, fluently
      */
-    public void addProperty(String name) {
+    public PathImpl addProperty(String name) {
         if (!nodeList.isEmpty()) {
             NodeImpl leaf = getLeafNode();
             if (isAwaitingPropertyName(leaf)) {
@@ -229,10 +220,20 @@ public class PathImpl implements Path, Serializable {
                     leaf = tmp;
                 }
                 leaf.setName(name);
-                return;
+                return this;
             }
         }
-        addNode(new NodeImpl.PropertyNodeImpl(name));
+        return addNode(new NodeImpl.PropertyNodeImpl(name));
+    }
+
+    public PathImpl addBean() {
+        final NodeImpl.BeanNodeImpl node;
+        if (!nodeList.isEmpty() && isAwaitingPropertyName(getLeafNode())) {
+            node = new NodeImpl.BeanNodeImpl(removeLeafNode());
+        } else {
+            node = new NodeImpl.BeanNodeImpl();
+        }
+        return addNode(node);
     }
 
     /**