bval-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mben...@apache.org
Subject [14/15] bval git commit: wip
Date Wed, 15 Nov 2017 22:54:19 GMT
http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintDefaults.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintDefaults.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintDefaults.java
index 3e3771e..07af5fe 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintDefaults.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintDefaults.java
@@ -80,28 +80,20 @@ public class ConstraintDefaults {
     private Map<String, Class<? extends ConstraintValidator<?, ?>>[]> loadDefaultConstraints(String resource) {
         final Properties constraintProperties = new Properties();
         final ClassLoader classloader = getClassLoader();
-        final InputStream stream = classloader.getResourceAsStream(resource);
-        if (stream == null) {
-            log.log(Level.WARNING, String.format("Cannot find %s", resource));
-        } else {
-            try {
+        try (final InputStream stream = classloader.getResourceAsStream(resource)) {
+            if (stream == null) {
+                log.log(Level.WARNING, String.format("Cannot find %s", resource));
+            } else {
                 constraintProperties.load(stream);
-            } catch (IOException e) {
-                log.log(Level.SEVERE, String.format("Cannot load %s", resource), e);
-            } finally {
-                try {
-                    stream.close();
-                } catch (final IOException e) {
-                    // no-op
-                }
             }
+        } catch (IOException e) {
+            log.log(Level.SEVERE, String.format("Cannot load %s", resource), e);
         }
 
-        final Map<String, Class<? extends ConstraintValidator<?, ?>>[]> loadedConstraints =
-            new HashMap<String, Class<? extends ConstraintValidator<?, ?>>[]>();
+        final Map<String, Class<? extends ConstraintValidator<?, ?>>[]> loadedConstraints = new HashMap<>();
 
         for (final Map.Entry<Object, Object> entry : constraintProperties.entrySet()) {
-            final List<Class<?>> classes = new LinkedList<Class<?>>();
+            final List<Class<?>> classes = new LinkedList<>();
             for (String className : StringUtils.split((String) entry.getValue(), ',')) {
                 try {
                     classes.add(Reflection.toClass(className.trim(), classloader));

http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintDescriptorImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintDescriptorImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintDescriptorImpl.java
index a56e1e1..c4c9d99 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintDescriptorImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintDescriptorImpl.java
@@ -21,6 +21,7 @@ package org.apache.bval.jsr;
 import javax.validation.ConstraintTarget;
 import javax.validation.Payload;
 import javax.validation.metadata.ConstraintDescriptor;
+import javax.validation.metadata.ValidateUnwrappedValue;
 
 import java.io.Serializable;
 import java.lang.annotation.Annotation;
@@ -220,4 +221,16 @@ public class ConstraintDescriptorImpl<T extends Annotation> implements Constrain
         result = 31 * result + (template != null ? template.hashCode() : 0);
         return result;
     }
+
+    @Override
+    public ValidateUnwrappedValue getValueUnwrapping() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public <U> U unwrap(Class<U> arg0) {
+        // TODO Auto-generated method stub
+        return null;
+    }
 }

http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidation.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidation.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidation.java
index 5b51141..5ba14ca 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidation.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidation.java
@@ -39,6 +39,8 @@ import javax.validation.ValidationException;
 import javax.validation.constraintvalidation.SupportedValidationTarget;
 import javax.validation.constraintvalidation.ValidationTarget;
 import javax.validation.metadata.ConstraintDescriptor;
+import javax.validation.metadata.ValidateUnwrappedValue;
+
 import java.io.Serializable;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Array;
@@ -54,6 +56,7 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * Description: Adapter between Constraint (JSR303) and Validation (Core)<br/>
@@ -328,10 +331,12 @@ public class ConstraintValidation<T extends Annotation> implements Validation, C
             throw new UnexpectedTypeException(message);
         }
         if (types.size() > 1) {
-            throw new UnexpectedTypeException(
-                String.format("Ambiguous validators for type %s. See: @%s at %s. Validators are: %s",
-                    stringForType(targetType), anno.annotationType().getSimpleName(), stringForLocation(owner, access),
-                    StringUtils.join(types, ", ")));
+            throw new UnexpectedTypeException(String.format(
+                "Ambiguous validators for type %s. See: @%s at %s. Validators are: %s",
+                stringForType(targetType),
+                anno.annotationType().getSimpleName(),
+                stringForLocation(owner, access), types.stream()
+                    .map(Object::toString).collect(Collectors.joining(", "))));
         }
     }
 
@@ -524,9 +529,13 @@ public class ConstraintValidation<T extends Annotation> implements Validation, C
      * {@inheritDoc}
      */
     @Override
-    @SuppressWarnings("unchecked")
+    @SuppressWarnings({ "unchecked", "rawtypes" })
     public Set<ConstraintDescriptor<?>> getComposingConstraints() {
-        return composedConstraints == null ? Collections.EMPTY_SET : composedConstraints;
+        if (composedConstraints == null) {
+            return Collections.emptySet();
+        }
+        final Set result = composedConstraints;
+        return result;
     }
 
     /**
@@ -581,4 +590,16 @@ public class ConstraintValidation<T extends Annotation> implements Validation, C
     public void setValidated(final boolean validated) {
         this.validated = validated;
     }
+
+    @Override
+    public ValidateUnwrappedValue getValueUnwrapping() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public <U> U unwrap(Class<U> arg0) {
+        // TODO Auto-generated method stub
+        return null;
+    }
 }

http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidatorContextImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidatorContextImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidatorContextImpl.java
index 3599603..930170d 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidatorContextImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidatorContextImpl.java
@@ -25,6 +25,7 @@ import org.apache.bval.jsr.util.NodeImpl;
 import org.apache.bval.jsr.util.PathImpl;
 import org.apache.bval.model.ValidationListener;
 
+import javax.validation.ClockProvider;
 import javax.validation.ConstraintValidator;
 import javax.validation.ConstraintValidatorContext;
 import javax.validation.Path;
@@ -38,7 +39,10 @@ import java.util.List;
  * Description: Short-lived {@link ConstraintValidatorContext} implementation passed by
  * a {@link ConstraintValidation} to its adapted {@link ConstraintValidator}. <br/>
  */
-public class ConstraintValidatorContextImpl implements ConstraintValidatorContext {
+@Deprecated
+public class ConstraintValidatorContextImpl
+    extends org.apache.bval.jsr.job.ConstraintValidatorContextImpl<Object>
+    implements ConstraintValidatorContext {
     private final List<ValidationListener.Error> errorMessages = new LinkedList<ValidationListener.Error>();
 
     private final ConstraintValidation<?> constraintDescriptor;
@@ -53,6 +57,7 @@ public class ConstraintValidatorContextImpl implements ConstraintValidatorContex
      */
     public ConstraintValidatorContextImpl(GroupValidationContext<?> validationContext,
         ConstraintValidation<?> aConstraintValidation) {
+        super();
         this.validationContext = validationContext;
         this.constraintDescriptor = aConstraintValidation;
     }
@@ -154,6 +159,13 @@ public class ConstraintValidatorContextImpl implements ConstraintValidatorContex
             parent.addError(messageTemplate, propertyPath);
             return parent;
         }
+
+        @Override
+        public ContainerElementNodeBuilderCustomizableContext addContainerElementNode(
+            String arg0, Class<?> arg1, Integer arg2) {
+            // TODO Auto-generated method stub
+            return null;
+        }
     }
 
     /**
@@ -190,4 +202,10 @@ public class ConstraintValidatorContextImpl implements ConstraintValidatorContex
     public void addError(String messageTemplate, Path propertyPath) {
         errorMessages.add(new ValidationListener.Error(messageTemplate, propertyPath, null));
     }
+
+    @Override
+    public ClockProvider getClockProvider() {
+        // TODO Auto-generated method stub
+        return null;
+    }
 }

http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintViolationImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintViolationImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintViolationImpl.java
index c367b8e..d510341 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintViolationImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintViolationImpl.java
@@ -20,15 +20,19 @@ import javax.validation.ConstraintViolation;
 import javax.validation.Path;
 import javax.validation.ValidationException;
 import javax.validation.metadata.ConstraintDescriptor;
+
+import org.apache.bval.jsr.util.Exceptions;
+
 import java.io.Serializable;
 import java.lang.annotation.ElementType;
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * Description: Describe a constraint validation defect.<br/>
  * From rootBean and propertyPath, it is possible to rebuild the context of the failure
  */
-class ConstraintViolationImpl<T> implements ConstraintViolation<T>, Serializable {
+public class ConstraintViolationImpl<T> implements ConstraintViolation<T>, Serializable {
     /** Serialization version */
     private static final long serialVersionUID = 1L;
 
@@ -163,7 +167,7 @@ class ConstraintViolationImpl<T> implements ConstraintViolation<T>, Serializable
         if (type.isInstance(this)) {
             return type.cast(this);
         }
-        throw new ValidationException("Type " + type + " is not supported");
+        throw Exceptions.create(ValidationException::new, "Type %s is not supported", type);
     }
 
     /**
@@ -171,45 +175,28 @@ class ConstraintViolationImpl<T> implements ConstraintViolation<T>, Serializable
      */
     @Override
     public String toString() {
-        return "ConstraintViolationImpl{" + "rootBean=" + rootBean + ", propertyPath='" + propertyPath + '\''
-            + ", message='" + message + '\'' + ", leafBean=" + leafBean + ", value=" + value + '}';
+        return String.format("%s{rootBean=%s, propertyPath='%s', message='%s', leafBean=%s, value=%s}",
+            ConstraintViolationImpl.class.getSimpleName(), rootBean, propertyPath, message, leafBean, value);
     }
 
     @Override
     public boolean equals(Object o) {
-        if (this == o)
+        if (this == o) {
             return true;
-        if (o == null || getClass() != o.getClass())
+        }
+        if (o == null || !getClass().equals(o.getClass())) {
             return false;
+        }
 
-        ConstraintViolationImpl that = (ConstraintViolationImpl) o;
-
-        if (constraintDescriptor != null ? !constraintDescriptor.equals(that.constraintDescriptor)
-            : that.constraintDescriptor != null)
-            return false;
-        if (elementType != that.elementType)
-            return false;
-        if (leafBean != null ? !leafBean.equals(that.leafBean) : that.leafBean != null)
-            return false;
-        if (message != null ? !message.equals(that.message) : that.message != null)
-            return false;
-        if (messageTemplate != null ? !messageTemplate.equals(that.messageTemplate) : that.messageTemplate != null)
-            return false;
-        // Probably incorrect - comparing Object[] arrays with Arrays.equals
-        if (!Arrays.equals(parameters, that.parameters))
-            return false;
-        if (propertyPath != null ? !propertyPath.equals(that.propertyPath) : that.propertyPath != null)
-            return false;
-        if (returnValue != null ? !returnValue.equals(that.returnValue) : that.returnValue != null)
-            return false;
-        if (rootBean != null ? !rootBean.equals(that.rootBean) : that.rootBean != null)
-            return false;
-        if (rootBeanClass != null ? !rootBeanClass.equals(that.rootBeanClass) : that.rootBeanClass != null)
-            return false;
-        if (value != null ? !value.equals(that.value) : that.value != null)
-            return false;
+        @SuppressWarnings("rawtypes")
+        final ConstraintViolationImpl that = (ConstraintViolationImpl) o;
 
-        return true;
+        return Objects.equals(constraintDescriptor, that.constraintDescriptor) && elementType == that.elementType
+            && Objects.equals(leafBean, that.leafBean) && Objects.equals(message, that.message)
+            && Objects.equals(messageTemplate, that.messageTemplate) && Arrays.equals(parameters, that.parameters)
+            && Objects.equals(propertyPath, that.propertyPath) && Objects.equals(returnValue, that.returnValue)
+            && Objects.equals(rootBean, that.rootBean) && Objects.equals(rootBeanClass, that.rootBeanClass)
+            && Objects.equals(value, that.value);
     }
 
     @Override
@@ -217,18 +204,10 @@ class ConstraintViolationImpl<T> implements ConstraintViolation<T>, Serializable
         return hashCode;
     }
 
-    public int computeHashCode() {
-        int result = messageTemplate != null ? messageTemplate.hashCode() : 0;
-        result = 31 * result + (message != null ? message.hashCode() : 0);
-        result = 31 * result + (rootBean != null ? rootBean.hashCode() : 0);
-        result = 31 * result + (rootBeanClass != null ? rootBeanClass.hashCode() : 0);
-        result = 31 * result + (leafBean != null ? leafBean.hashCode() : 0);
-        result = 31 * result + (value != null ? value.hashCode() : 0);
-        result = 31 * result + (propertyPath != null ? propertyPath.hashCode() : 0);
-        result = 31 * result + (elementType != null ? elementType.hashCode() : 0);
-        result = 31 * result + (constraintDescriptor != null ? constraintDescriptor.hashCode() : 0);
-        result = 31 * result + (returnValue != null ? returnValue.hashCode() : 0);
-        result = 31 * result + (parameters != null ? Arrays.hashCode(parameters) : 0);
+    private int computeHashCode() {
+        int result = Objects.hash(messageTemplate, message, rootBean, rootBeanClass, leafBean, value, propertyPath,
+            elementType, constraintDescriptor, returnValue);
+        result = 31 * result + (parameters == null ? 0 : Arrays.hashCode(parameters));
         return result;
     }
 }

http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/GraphContext.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/GraphContext.java b/bval-jsr/src/main/java/org/apache/bval/jsr/GraphContext.java
new file mode 100644
index 0000000..020a950
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/GraphContext.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.bval.jsr;
+
+import org.apache.bval.jsr.util.NodeImpl;
+import org.apache.bval.jsr.util.PathImpl;
+import org.apache.bval.util.Validate;
+
+public class GraphContext {
+
+    private final ApacheFactoryContext validatorContext;
+    private final PathImpl path;
+    private final Object value;
+    private final GraphContext parent;
+
+    public GraphContext(ApacheFactoryContext validatorContext, PathImpl path, Object value) {
+        this(validatorContext, path, value, null);
+    }
+
+    private GraphContext(ApacheFactoryContext validatorContext, PathImpl path, Object value, GraphContext parent) {
+        super();
+        this.validatorContext = Validate.notNull(validatorContext, "validatorContext");
+        this.path = Validate.notNull(path, "path");
+        this.value = value;
+        this.parent = parent;
+    }
+
+    public ApacheFactoryContext getValidatorContext() {
+        return validatorContext;
+    }
+
+    public PathImpl getPath() {
+        return PathImpl.copy(path);
+    }
+
+    public Object getValue() {
+        return value;
+    }
+
+    public GraphContext child(NodeImpl node, Object value) {
+        if (value == null || stackContains(value)) {
+            return null;
+        }
+        final PathImpl p = PathImpl.copy(path);
+        p.addNode(node);
+        return new GraphContext(validatorContext, p, value, this);
+    }
+
+    private boolean stackContains(Object value) {
+        GraphContext c = this;
+        while (c != null) {
+            if (c.value == value) {
+                return true;
+            }
+            c = c.parent;
+        }
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/NodeBuilderCustomizableContextImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/NodeBuilderCustomizableContextImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/NodeBuilderCustomizableContextImpl.java
new file mode 100644
index 0000000..8200bfe
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/NodeBuilderCustomizableContextImpl.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.bval.jsr;
+
+import org.apache.bval.jsr.util.LeafNodeBuilderCustomizableContextImpl;
+import org.apache.bval.jsr.util.NodeImpl;
+import org.apache.bval.jsr.util.PathImpl;
+
+import javax.validation.ConstraintValidatorContext;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.ContainerElementNodeBuilderCustomizableContext;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext;
+import javax.validation.ElementKind;
+
+public class NodeBuilderCustomizableContextImpl
+    implements ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext {
+    private final PathImpl path;
+    private final ConstraintValidatorContextImpl context;
+    private final String template;
+
+    public NodeBuilderCustomizableContextImpl(final ConstraintValidatorContextImpl parent, final String messageTemplate,
+        final PathImpl propertyPath) {
+        context = parent;
+        template = messageTemplate;
+        path = propertyPath;
+    }
+
+    @Override
+    public ConstraintValidatorContext.ConstraintViolationBuilder.NodeContextBuilder inIterable() {
+        path.getLeafNode().setInIterable(true);
+        return new NodeContextBuilderImpl(context, template, path);
+    }
+
+    @Override
+    public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext addNode(String name) {
+        path.addNode(new NodeImpl(name));
+        return this;
+    }
+
+    @Override
+    public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext addPropertyNode(
+        String name) {
+        final NodeImpl node = new NodeImpl.PropertyNodeImpl(name);
+        path.addNode(node);
+        return this;
+    }
+
+    @Override
+    public ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeBuilderCustomizableContext addBeanNode() {
+        final NodeImpl node = new NodeImpl.BeanNodeImpl();
+        path.addNode(node);
+        return null;
+//        return new LeafNodeBuilderCustomizableContextImpl(context, template, path);
+    }
+
+    @Override
+    public ConstraintValidatorContext addConstraintViolation() {
+        context.addError(template, path);
+        return context;
+    }
+
+    @Override
+    public NodeBuilderCustomizableContext inContainer(Class<?> containerClass, Integer typeArgumentIndex) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public ContainerElementNodeBuilderCustomizableContext addContainerElementNode(String name, Class<?> containerType,
+        Integer typeArgumentIndex) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/NodeContextBuilderImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/NodeContextBuilderImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/NodeContextBuilderImpl.java
new file mode 100644
index 0000000..d1f191e
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/NodeContextBuilderImpl.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.bval.jsr;
+
+import org.apache.bval.jsr.util.LeafNodeBuilderCustomizableContextImpl;
+import org.apache.bval.jsr.util.NodeBuilderDefinedContextImpl;
+import org.apache.bval.jsr.util.NodeImpl;
+import org.apache.bval.jsr.util.PathImpl;
+
+import javax.validation.ConstraintValidatorContext;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.ContainerElementNodeBuilderCustomizableContext;
+import javax.validation.ElementKind;
+
+public class NodeContextBuilderImpl
+    implements ConstraintValidatorContext.ConstraintViolationBuilder.NodeContextBuilder {
+    private final PathImpl path;
+    private final String template;
+    private final ConstraintValidatorContextImpl context;
+
+    public NodeContextBuilderImpl(final ConstraintValidatorContextImpl context, final String template,
+        final PathImpl path) {
+        this.context = context;
+        this.template = template;
+        this.path = path;
+    }
+
+    @Override
+    public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderDefinedContext atKey(Object key) {
+        path.getLeafNode().setKey(key);
+        return null;
+//        return new NodeBuilderDefinedContextImpl(context, template, path);
+    }
+
+    @Override
+    public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderDefinedContext atIndex(Integer index) {
+        path.getLeafNode().setIndex(index);
+        return null;
+//        return new NodeBuilderDefinedContextImpl(context, template, path);
+    }
+
+    @Override
+    public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext addNode(String name) {
+        return new NodeBuilderCustomizableContextImpl(context, template, path).addNode(name);
+    }
+
+    @Override
+    public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext addPropertyNode(
+        String name) {
+        return new NodeBuilderCustomizableContextImpl(context, template, path).addPropertyNode(name);
+    }
+
+    @Override
+    public ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeBuilderCustomizableContext addBeanNode() {
+        final NodeImpl node = new NodeImpl.BeanNodeImpl();
+        path.addNode(node);
+        return null;
+//        return new LeafNodeBuilderCustomizableContextImpl(context, template, path);
+    }
+
+    @Override
+    public ConstraintValidatorContext addConstraintViolation() {
+        context.addError(template, path);
+        return context;
+    }
+
+    @Override
+    public ContainerElementNodeBuilderCustomizableContext addContainerElementNode(String name, Class<?> containerType,
+        Integer typeArgumentIndex) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/ParameterDescriptorImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ParameterDescriptorImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ParameterDescriptorImpl.java
index 187fd7e..65f3ecc 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ParameterDescriptorImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ParameterDescriptorImpl.java
@@ -21,6 +21,7 @@ import org.apache.bval.jsr.groups.GroupConversionDescriptorImpl;
 import org.apache.bval.model.MetaBean;
 import org.apache.bval.model.Validation;
 
+import javax.validation.metadata.ContainerElementTypeDescriptor;
 import javax.validation.metadata.GroupConversionDescriptor;
 import javax.validation.metadata.ParameterDescriptor;
 import java.util.Set;
@@ -86,4 +87,10 @@ public class ParameterDescriptorImpl extends ElementDescriptorImpl implements Pa
         groupConversions.add(new GroupConversionDescriptorImpl(from, to));
         super.addGroupMapping(from, to);
     }
+
+    @Override
+    public Set<ContainerElementTypeDescriptor> getConstrainedContainerElementTypes() {
+        // TODO Auto-generated method stub
+        return null;
+    }
 }

http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/PropertyDescriptorImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/PropertyDescriptorImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/PropertyDescriptorImpl.java
index 7f7c56d..03cf5de 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/PropertyDescriptorImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/PropertyDescriptorImpl.java
@@ -21,6 +21,9 @@ package org.apache.bval.jsr;
 import org.apache.bval.model.Features;
 import org.apache.bval.model.MetaProperty;
 
+import java.util.Set;
+
+import javax.validation.metadata.ContainerElementTypeDescriptor;
 import javax.validation.metadata.PropertyDescriptor;
 
 /**
@@ -67,4 +70,10 @@ class PropertyDescriptorImpl extends ElementDescriptorImpl implements PropertyDe
         return "PropertyDescriptorImpl{" + "returnType=" + elementClass + ", propertyPath='" + propertyPath + '\''
             + '}';
     }
+
+    @Override
+    public Set<ContainerElementTypeDescriptor> getConstrainedContainerElementTypes() {
+        // TODO Auto-generated method stub
+        return null;
+    }
 }

http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/ReturnValueDescriptorImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ReturnValueDescriptorImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ReturnValueDescriptorImpl.java
index b1fc72d..a6faa9b 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ReturnValueDescriptorImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ReturnValueDescriptorImpl.java
@@ -18,8 +18,10 @@ package org.apache.bval.jsr;
 
 import org.apache.bval.model.MetaBean;
 
+import javax.validation.metadata.ContainerElementTypeDescriptor;
 import javax.validation.metadata.ReturnValueDescriptor;
 import java.util.Collection;
+import java.util.Set;
 
 public class ReturnValueDescriptorImpl extends ElementDescriptorImpl implements ReturnValueDescriptor {
     public ReturnValueDescriptorImpl(final MetaBean metaBean, Class<?> returnType,
@@ -32,4 +34,10 @@ public class ReturnValueDescriptorImpl extends ElementDescriptorImpl implements
     public boolean hasConstraints() {
         return false;
     }
+
+    @Override
+    public Set<ContainerElementTypeDescriptor> getConstrainedContainerElementTypes() {
+        // TODO Auto-generated method stub
+        return null;
+    }
 }

http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/ValidatorImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ValidatorImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ValidatorImpl.java
new file mode 100644
index 0000000..606e191
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ValidatorImpl.java
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.bval.jsr;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Set;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.ValidationException;
+import javax.validation.executable.ExecutableValidator;
+import javax.validation.metadata.BeanDescriptor;
+
+import org.apache.bval.jsr.job.ValidationJobFactory;
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.Reflection;
+
+public class ValidatorImpl implements CascadingPropertyValidator, ExecutableValidator {
+
+    private final ApacheFactoryContext validatorContext;
+    private final ValidationJobFactory validationJobFactory;
+
+    ValidatorImpl(ApacheFactoryContext validatorContext) {
+        super();
+        this.validatorContext = Validate.notNull(validatorContext, "validatorContext");
+        this.validationJobFactory = new ValidationJobFactory(validatorContext);
+    }
+
+    @Override
+    public BeanDescriptor getConstraintsForClass(Class<?> clazz) {
+        return validatorContext.getDescriptorManager().getBeanDescriptor(clazz);
+    }
+
+    @Override
+    public <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) {
+        return validationJobFactory.validateBean(object, groups).getResults();
+    }
+
+    @Override
+    public <T> Set<ConstraintViolation<T>> validateProperty(T object, String propertyName, boolean cascade,
+        Class<?>... groups) {
+        return validationJobFactory.validateProperty(object, propertyName, groups).cascade(cascade).getResults();
+    }
+
+    @Override
+    public <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value,
+        boolean cascade, Class<?>... groups) {
+        return validationJobFactory.validateValue(beanType, propertyName, value, groups).cascade(cascade).getResults();
+    }
+
+    @Override
+    public ExecutableValidator forExecutables() {
+        return this;
+    }
+
+    @Override
+    public <T> Set<ConstraintViolation<T>> validateParameters(T object, Method method, Object[] parameterValues,
+        Class<?>... groups) {
+        return validationJobFactory.validateParameters(object, method, parameterValues, groups).getResults();
+    }
+
+    @Override
+    public <T> Set<ConstraintViolation<T>> validateReturnValue(T object, Method method, Object returnValue,
+        Class<?>... groups) {
+        return validationJobFactory.validateReturnValue(object, method, returnValue, groups).getResults();
+    }
+
+    @Override
+    public <T> Set<ConstraintViolation<T>> validateConstructorParameters(Constructor<? extends T> constructor,
+        Object[] parameterValues, Class<?>... groups) {
+        return validationJobFactory.<T> validateConstructorParameters(constructor, parameterValues, groups)
+            .getResults();
+    }
+
+    @Override
+    public <T> Set<ConstraintViolation<T>> validateConstructorReturnValue(Constructor<? extends T> constructor,
+        T createdObject, Class<?>... groups) {
+        return validationJobFactory.<T> validateConstructorReturnValue(constructor, createdObject, groups).getResults();
+    }
+
+    @Override
+    public <T> T unwrap(Class<T> type) {
+        // FIXME 2011-03-27 jw:
+        // This code is unsecure.
+        // It should allow only a fixed set of classes.
+        // Can't fix this because don't know which classes this method should support.
+
+        if (type.isAssignableFrom(getClass())) {
+            @SuppressWarnings("unchecked")
+            final T result = (T) this;
+            return result;
+        }
+        if (!(type.isInterface() || Modifier.isAbstract(type.getModifiers()))) {
+            return newInstance(type);
+        }
+        try {
+            final Class<?> cls = Reflection.toClass(type.getName() + "Impl");
+            if (type.isAssignableFrom(cls)) {
+                @SuppressWarnings("unchecked")
+                final Class<? extends T> implClass = (Class<? extends T>) cls;
+                return newInstance(implClass);
+            }
+        } catch (ClassNotFoundException e) {
+        }
+        throw new ValidationException("Type " + type + " not supported");
+    }
+
+    private <T> T newInstance(final Class<T> cls) {
+        final Constructor<T> cons = Reflection.getDeclaredConstructor(cls, ApacheFactoryContext.class);
+        if (cons == null) {
+            throw new ValidationException("Cannot instantiate " + cls);
+        }
+        final boolean mustUnset = Reflection.setAccessible(cons, true);
+        try {
+            return cons.newInstance(validatorContext);
+        } catch (final Exception ex) {
+            throw new ValidationException("Cannot instantiate " + cls, ex);
+        } finally {
+            if (mustUnset) {
+                Reflection.setAccessible(cons, false);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/BeanD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/BeanD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/BeanD.java
new file mode 100644
index 0000000..570352b
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/BeanD.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.bval.jsr.descriptor;
+
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+
+import javax.validation.metadata.BeanDescriptor;
+import javax.validation.metadata.ConstructorDescriptor;
+import javax.validation.metadata.MethodDescriptor;
+import javax.validation.metadata.MethodType;
+import javax.validation.metadata.PropertyDescriptor;
+
+import org.apache.bval.jsr.metadata.Signature;
+import org.apache.bval.jsr.util.ToUnmodifiable;
+import org.apache.bval.util.Lazy;
+
+public class BeanD extends ElementD<Class<?>, MetadataReader.ForBean> implements BeanDescriptor {
+
+    private static <K, V> Map<K, V> toMap(Set<V> set, Function<? super V, ? extends K> toKey) {
+        return set.stream().collect(ToUnmodifiable.map(toKey, Function.identity()));
+    }
+
+    private final Class<?> beanClass;
+
+    private final Lazy<List<Class<?>>> groupSequence;
+    private Lazy<Set<PropertyDescriptor>> properties;
+    private Lazy<Map<String, PropertyDescriptor>> propertiesMap;
+    private Lazy<Map<Signature, ConstructorD>> constructors;
+    private Lazy<Map<Signature, MethodD>> methods;
+
+    BeanD(MetadataReader.ForBean reader) {
+        super(reader);
+        this.beanClass = reader.meta.getHost();
+
+        groupSequence = new Lazy<>(reader::getGroupSequence);
+        properties = new Lazy<>(() -> reader.getProperties(this));
+        propertiesMap = new Lazy<>(() -> toMap(properties.get(), PropertyDescriptor::getPropertyName));
+        constructors = new Lazy<>(() -> reader.getConstructors(this));
+        methods = new Lazy<>(() -> reader.getMethods(this));
+    }
+
+    @Override
+    public Class<?> getElementClass() {
+        return beanClass;
+    }
+
+    @Override
+    public boolean isBeanConstrained() {
+        return hasConstraints() || properties.get().stream().anyMatch(pd -> pd.isCascaded() || pd.hasConstraints());
+    }
+
+    @Override
+    public PropertyDescriptor getConstraintsForProperty(String propertyName) {
+        return propertiesMap.get().get(propertyName);
+    }
+
+    @Override
+    public Set<PropertyDescriptor> getConstrainedProperties() {
+        return properties.get();
+    }
+
+    @Override
+    public MethodDescriptor getConstraintsForMethod(String methodName, Class<?>... parameterTypes) {
+        return methods.get().get(new Signature(methodName, parameterTypes));
+    }
+
+    @Override
+    public Set<MethodDescriptor> getConstrainedMethods(MethodType methodType, MethodType... methodTypes) {
+        return methods.get().values().stream().filter(EnumSet.of(methodType, methodTypes)::contains)
+            .collect(ToUnmodifiable.set());
+    }
+
+    @Override
+    public ConstructorDescriptor getConstraintsForConstructor(Class<?>... parameterTypes) {
+        return constructors.get().get(new Signature(beanClass.getSimpleName(), parameterTypes));
+    }
+
+    @Override
+    public Set<ConstructorDescriptor> getConstrainedConstructors() {
+        return constructors.get().values().stream().collect(ToUnmodifiable.set());
+    }
+
+    @Override
+    protected BeanD getBean() {
+        return this;
+    }
+
+    @Override
+    List<Class<?>> getGroupSequence() {
+        return groupSequence.get();
+    }
+}

http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CascadableContainerD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CascadableContainerD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CascadableContainerD.java
new file mode 100644
index 0000000..163b6ca
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CascadableContainerD.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.bval.jsr.descriptor;
+
+import java.lang.reflect.AnnotatedElement;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import javax.validation.ValidationException;
+import javax.validation.metadata.CascadableDescriptor;
+import javax.validation.metadata.ContainerDescriptor;
+import javax.validation.metadata.ContainerElementTypeDescriptor;
+import javax.validation.metadata.GroupConversionDescriptor;
+
+import org.apache.bval.jsr.GraphContext;
+import org.apache.bval.util.Lazy;
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.TypeUtils;
+
+public abstract class CascadableContainerD<P extends ElementD<?,?>, E extends AnnotatedElement>
+    extends ElementD.NonRoot<P, E, MetadataReader.ForContainer<E>> implements CascadableDescriptor, ContainerDescriptor {
+
+    private final Class<?> type;
+
+    private final boolean cascaded;
+    private final Set<GroupConversion> groupConversions;
+    private final Lazy<Set<ContainerElementTypeD>> containerElementTypes;
+
+    protected CascadableContainerD(MetadataReader.ForContainer<E> reader, P parent) {
+        super(reader, parent);
+
+        type = TypeUtils.getRawType(reader.meta.getType(), parent.getElementClass());
+
+        cascaded = reader.isCascaded();
+        groupConversions = reader.getGroupConversions();
+        containerElementTypes = new Lazy<>(() -> reader.getContainerElementTypes(this));
+    }
+
+    @Override
+    public Class<?> getElementClass() {
+        return type;
+    }
+
+    @Override
+    public boolean isCascaded() {
+        return cascaded;
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Override
+    public Set<GroupConversionDescriptor> getGroupConversions() {
+        return (Set) groupConversions;
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Override
+    public Set<ContainerElementTypeDescriptor> getConstrainedContainerElementTypes() {
+        return (Set) containerElementTypes.get();
+    }
+
+    public final Stream<GraphContext> read(GraphContext context) {
+        Validate.notNull(context);
+        if (context.getValue() == null) {
+            return Stream.empty();
+        }
+        try {
+            return readImpl(context);
+        } catch (Exception e) {
+            throw new ValidationException(e);
+        }
+    }
+
+    protected Stream<GraphContext> readImpl(GraphContext context) throws Exception {
+        throw new UnsupportedOperationException();
+    }
+}

http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComposedD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComposedD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComposedD.java
new file mode 100644
index 0000000..14fb9a8
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComposedD.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.bval.jsr.descriptor;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import javax.validation.metadata.CascadableDescriptor;
+import javax.validation.metadata.ConstraintDescriptor;
+import javax.validation.metadata.ContainerDescriptor;
+import javax.validation.metadata.ContainerElementTypeDescriptor;
+import javax.validation.metadata.ElementDescriptor;
+import javax.validation.metadata.GroupConversionDescriptor;
+import javax.validation.metadata.PropertyDescriptor;
+
+import org.apache.bval.jsr.util.ToUnmodifiable;
+import org.apache.bval.util.Validate;
+
+public abstract class ComposedD<D extends ElementD<?, ?>> implements ElementDescriptor {
+
+    static abstract class ForCascadableContainer<D extends CascadableContainerD<?, ?>> extends ComposedD<D>
+        implements CascadableDescriptor, ContainerDescriptor {
+
+        ForCascadableContainer(List<D> delegates) {
+            super(delegates);
+        }
+
+        @Override
+        public Set<ContainerElementTypeDescriptor> getConstrainedContainerElementTypes() {
+            return delegates.stream().map(ContainerDescriptor::getConstrainedContainerElementTypes)
+                .flatMap(Collection::stream).collect(ToUnmodifiable.set());
+        }
+
+        @Override
+        public boolean isCascaded() {
+            return delegates.stream().anyMatch(CascadableDescriptor::isCascaded);
+        }
+
+        @Override
+        public Set<GroupConversionDescriptor> getGroupConversions() {
+            return delegates.stream().map(CascadableDescriptor::getGroupConversions).flatMap(Collection::stream)
+                .collect(ToUnmodifiable.set());
+        }
+    }
+
+    static class ForProperty extends ComposedD.ForCascadableContainer<PropertyD<?>> implements PropertyDescriptor {
+
+        ForProperty(List<PropertyD<?>> delegates) {
+            super(delegates);
+        }
+
+        @Override
+        public String getPropertyName() {
+            return delegates.stream().map(PropertyDescriptor::getPropertyName).findFirst()
+                .orElseThrow(IllegalStateException::new);
+        }
+    }
+
+    public static <T extends ElementD<?, ?>> Stream<T> unwrap(ElementDescriptor descriptor, Class<? super T> delegateType) {
+        final Stream<?> s;
+
+        if (descriptor instanceof ComposedD<?>) {
+            s = ((ComposedD<?>) descriptor).delegates.stream()
+                // unwrap recursively:
+                .flatMap(d -> unwrap(d, delegateType));
+        } else {
+            s = Stream.of(descriptor);
+        }
+        @SuppressWarnings("unchecked")
+        final Stream<T> result = (Stream<T>) s.map(delegateType::cast);
+        return result;
+    }
+
+    protected final List<D> delegates;
+
+    ComposedD(List<D> delegates) {
+        super();
+        this.delegates = delegates;
+
+        Validate.notNull(delegates, "delegates");
+        Validate.isTrue(!delegates.isEmpty(), "At least one delegate is required");
+        Validate.isTrue(delegates.stream().noneMatch(Objects::isNull), "null delegates not permitted");
+    }
+
+    @Override
+    public boolean hasConstraints() {
+        return delegates.stream().anyMatch(ElementDescriptor::hasConstraints);
+    }
+
+    @Override
+    public Class<?> getElementClass() {
+        return delegates.stream().map(ElementDescriptor::getElementClass).findFirst()
+            .orElseThrow(IllegalStateException::new);
+    }
+
+    @Override
+    public Set<ConstraintDescriptor<?>> getConstraintDescriptors() {
+        return delegates.stream().map(ElementDescriptor::getConstraintDescriptors).flatMap(Collection::stream)
+            .collect(ToUnmodifiable.set());
+    }
+
+    @Override
+    public ConstraintFinder findConstraints() {
+        return new Finder(this, delegates.stream().map(ElementD::getGroupSequence).findFirst().orElse(null));
+    }
+}

http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComputeConstraintValidatorClass.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComputeConstraintValidatorClass.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComputeConstraintValidatorClass.java
new file mode 100644
index 0000000..4410726
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComputeConstraintValidatorClass.java
@@ -0,0 +1,147 @@
+package org.apache.bval.jsr.descriptor;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.WildcardType;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import javax.validation.ConstraintDefinitionException;
+import javax.validation.ConstraintValidator;
+import javax.validation.UnexpectedTypeException;
+import javax.validation.constraintvalidation.ValidationTarget;
+
+import org.apache.bval.jsr.ApacheValidatorFactory;
+import org.apache.bval.jsr.ConstraintCached.ConstraintValidatorInfo;
+import org.apache.bval.jsr.util.Exceptions;
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.Reflection;
+import org.apache.bval.util.reflection.Reflection.Interfaces;
+import org.apache.bval.util.reflection.TypeUtils;
+import org.apache.commons.weaver.privilizer.Privilizing;
+import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
+
+@Privilizing(@CallTo(Reflection.class))
+class ComputeConstraintValidatorClass<A extends Annotation>
+    implements Supplier<Class<? extends ConstraintValidator<A, ?>>> {
+
+    private static final String CV = ConstraintValidator.class.getSimpleName();
+    private static final WildcardType UNBOUNDED = TypeUtils.wildcardType().build();
+
+    private static Type getValidatedType(Class<? extends ConstraintValidator<?, ?>> validatorType) {
+        final Type result = TypeUtils.getTypeArguments(validatorType, ConstraintValidator.class)
+            .get(ConstraintValidator.class.getTypeParameters()[1]);
+        Exceptions.raiseUnless(isSupported(result), ConstraintDefinitionException::new,
+            "Validated type %s declared by %s %s is unsupported", result, CV, validatorType.getName());
+        return result;
+    }
+
+    private static boolean isSupported(Type validatedType) {
+        if (validatedType instanceof Class<?>) {
+            return true;
+        }
+        if (validatedType instanceof ParameterizedType) {
+            return Stream.of(((ParameterizedType) validatedType).getActualTypeArguments())
+                .allMatch(arg -> TypeUtils.equals(arg, UNBOUNDED));
+        }
+        return false;
+    }
+
+    private final ApacheValidatorFactory validatorFactory;
+    private final Class<A> constraintType;
+    private final Class<?> validatedType;
+    private final ValidationTarget validationTarget;
+
+    ComputeConstraintValidatorClass(ApacheValidatorFactory validatorFactory, ValidationTarget validationTarget,
+        Class<A> constraintType, Class<?> validatedType) {
+        super();
+        this.validatorFactory = Validate.notNull(validatorFactory, "validatorFactory");
+        this.validationTarget = Validate.notNull(validationTarget, "validationTarget");
+        this.constraintType = Validate.notNull(constraintType, "constraintType");
+        this.validatedType = Validate.notNull(validatedType, "validatedType");
+    }
+
+    @Override
+    public Class<? extends ConstraintValidator<A, ?>> get() {
+        final Optional<Class<? extends ConstraintValidator<A, ?>>> result =
+            validatorFactory.getConstraintsCache().getConstraintValidatorInfo(constraintType).map(this::findValidator);
+
+        Exceptions.raiseUnless(result.isPresent(), UnexpectedTypeException::new,
+            "No %s found for %s constraint %s/type %s", CV, validationTarget, constraintType, validatedType);
+
+        return result.get();
+    }
+
+    private Class<? extends ConstraintValidator<A, ?>> findValidator(Set<ConstraintValidatorInfo<A>> infos) {
+        switch (validationTarget) {
+            case PARAMETERS:
+                return findCrossParameterValidator(infos);
+            case ANNOTATED_ELEMENT:
+                return findAnnotatedElementValidator(infos);
+            default:
+                return null;
+        }
+    }
+
+    private Class<? extends ConstraintValidator<A, ?>> findCrossParameterValidator(
+        Set<ConstraintValidatorInfo<A>> infos) {
+
+        final Set<ConstraintValidatorInfo<A>> set =
+            infos.stream().filter(info -> info.getSupportedTargets().contains(ValidationTarget.PARAMETERS))
+                .collect(Collectors.toSet());
+
+        Exceptions.raiseIf(set.isEmpty(), UnexpectedTypeException::new,
+            "No cross-parameter %s found for constraint type %s", CV, constraintType);
+
+        Exceptions.raiseUnless(set.size() == 1, UnexpectedTypeException::new,
+            "%d cross-parameter %ss found for constraint type %s", set.size(), CV, constraintType);
+
+        final Class<? extends ConstraintValidator<A, ?>> result = set.iterator().next().getType();
+        Exceptions.raiseUnless(TypeUtils.isAssignable(Object[].class, getValidatedType(result)),
+            ConstraintDefinitionException::new,
+            "Cross-parameter %s %s does not support the validation of an object array", CV, result.getName());
+
+        return result;
+    }
+
+    private Class<? extends ConstraintValidator<A, ?>> findAnnotatedElementValidator(
+        Set<ConstraintValidatorInfo<A>> infos) {
+
+        final Class<?> effectiveValidatedType = Reflection.primitiveToWrapper(validatedType);
+
+        final Map<Type, Class<? extends ConstraintValidator<?, ?>>> validators =
+            infos.stream().filter(info -> info.getSupportedTargets().contains(ValidationTarget.ANNOTATED_ELEMENT))
+                .map(ConstraintValidatorInfo::getType)
+                .collect(Collectors.toMap(ComputeConstraintValidatorClass::getValidatedType, Function.identity()));
+
+        final Map<Type, Class<? extends ConstraintValidator<?, ?>>> candidates = new HashMap<>();
+
+        for (Class<?> type : Reflection.hierarchy(effectiveValidatedType, Interfaces.INCLUDE)) {
+            if (validators.containsKey(type)) {
+                // if we already have a candidate whose validated type is a subtype of the current evaluated type, skip:
+                if (candidates.keySet().stream().anyMatch(k -> TypeUtils.isAssignable(k, type))) {
+                    continue;
+                }
+                candidates.put(type, validators.get(type));
+            }
+        }
+
+        Exceptions.raiseIf(candidates.isEmpty(), UnexpectedTypeException::new,
+            "No compliant %s found for annotated element of type %s", CV, TypeUtils.toString(validatedType));
+
+        Exceptions.raiseIf(candidates.size() > 1, UnexpectedTypeException::new,
+            "> 1 maximally specific %s found for annotated element of type %s", CV, TypeUtils.toString(validatedType));
+
+        @SuppressWarnings("unchecked")
+        final Class<? extends ConstraintValidator<A, ?>> result =
+            (Class<? extends ConstraintValidator<A, ?>>) candidates.values().iterator().next();
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstraintD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstraintD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstraintD.java
new file mode 100644
index 0000000..d8d9bd7
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstraintD.java
@@ -0,0 +1,206 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.bval.jsr.descriptor;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+import javax.validation.ConstraintTarget;
+import javax.validation.ConstraintValidator;
+import javax.validation.Payload;
+import javax.validation.ReportAsSingleViolation;
+import javax.validation.UnexpectedTypeException;
+import javax.validation.ValidationException;
+import javax.validation.metadata.ConstraintDescriptor;
+import javax.validation.metadata.Scope;
+import javax.validation.metadata.ValidateUnwrappedValue;
+import javax.validation.valueextraction.Unwrapping.Skip;
+import javax.validation.valueextraction.Unwrapping.Unwrap;
+
+import org.apache.bval.jsr.ApacheValidatorFactory;
+import org.apache.bval.jsr.ConstraintAnnotationAttributes;
+import org.apache.bval.jsr.ConstraintAnnotationAttributes.Worker;
+import org.apache.bval.jsr.metadata.Metas;
+import org.apache.bval.jsr.util.AnnotationsManager;
+import org.apache.bval.jsr.util.Exceptions;
+import org.apache.bval.jsr.util.ToUnmodifiable;
+import org.apache.bval.util.Lazy;
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.TypeUtils;
+
+public class ConstraintD<A extends Annotation> implements ConstraintDescriptor<A> {
+    private static <T> Set<T> set(Supplier<T[]> array) {
+        return Stream.of(array.get()).collect(ToUnmodifiable.set());
+    }
+
+    private final A annotation;
+    private final Scope scope;
+    private final Metas<?> meta;
+    private final Class<?> validatedType;
+
+    private final Lazy<Set<Class<?>>> groups = new Lazy<>(() -> set(() -> read(ConstraintAnnotationAttributes.GROUPS)));
+
+    private final Lazy<Set<Class<? extends Payload>>> payload =
+        new Lazy<>(() -> set(() -> read(ConstraintAnnotationAttributes.PAYLOAD)));
+
+    private final Lazy<Boolean> reportAsSingle =
+        new Lazy<>(() -> getAnnotation().annotationType().isAnnotationPresent(ReportAsSingleViolation.class));
+
+    private final Lazy<ValidateUnwrappedValue> valueUnwrapping = new Lazy<>(this::computeValidateUnwrappedValue);
+
+    private final Lazy<Map<String, Object>> attributes;
+    private final Lazy<Set<ConstraintDescriptor<?>>> composingConstraints;
+    private final Lazy<List<Class<? extends ConstraintValidator<A, ?>>>> constraintValidatorClasses;
+    private final Lazy<Class<? extends ConstraintValidator<A, ?>>> constraintValidatorClass;
+
+    public ConstraintD(A annotation, Scope scope, Metas<?> meta, ApacheValidatorFactory validatorFactory) {
+        this.annotation = Validate.notNull(annotation, "annotation");
+        this.scope = Validate.notNull(scope, "scope");
+
+        this.meta = Validate.notNull(meta, "meta");
+        validatedType = TypeUtils.getRawType(meta.getType(), null);
+        Exceptions.raiseIf(validatedType == null, UnexpectedTypeException::new,
+            "Could not calculate validated type from %s", meta.getType());
+
+        attributes = new Lazy<>(() -> AnnotationsManager.readAttributes(annotation));
+
+        // retain no references to the validatorFactory; only wrap it in lazy suppliers
+        Validate.notNull(validatorFactory, "validatorFactory");
+        composingConstraints = new Lazy<>(computeComposingConstraints(validatorFactory));
+        constraintValidatorClasses = new Lazy<>(computeConstraintValidatorClasses(validatorFactory));
+
+        @SuppressWarnings("unchecked")
+        final Supplier<Class<? extends ConstraintValidator<A, ?>>> computeConstraintValidatorClass =
+            new ComputeConstraintValidatorClass<>(validatorFactory, meta.getValidationTarget(),
+                (Class<A>) annotation.annotationType(), validatedType);
+
+        constraintValidatorClass = new Lazy<>(computeConstraintValidatorClass);
+    }
+
+    @Override
+    public A getAnnotation() {
+        return annotation;
+    }
+
+    @Override
+    public Set<Class<?>> getGroups() {
+        return groups.get();
+    }
+
+    @Override
+    public Set<Class<? extends Payload>> getPayload() {
+        return payload.get();
+    }
+
+    @Override
+    public List<Class<? extends ConstraintValidator<A, ?>>> getConstraintValidatorClasses() {
+        return constraintValidatorClasses.get();
+    }
+
+    @Override
+    public Map<String, Object> getAttributes() {
+        return attributes.get();
+    }
+
+    @Override
+    public Set<ConstraintDescriptor<?>> getComposingConstraints() {
+        return composingConstraints.get();
+    }
+
+    @Override
+    public boolean isReportAsSingleViolation() {
+        return reportAsSingle.get().booleanValue();
+    }
+
+    @Override
+    public String getMessageTemplate() {
+        return read(ConstraintAnnotationAttributes.MESSAGE);
+    }
+
+    @Override
+    public ConstraintTarget getValidationAppliesTo() {
+        return read(ConstraintAnnotationAttributes.VALIDATION_APPLIES_TO);
+    }
+
+    @Override
+    public ValidateUnwrappedValue getValueUnwrapping() {
+        return valueUnwrapping.get();
+    }
+
+    @Override
+    public <U> U unwrap(Class<U> type) throws ValidationException {
+        try {
+            return type.cast(this);
+        } catch (ClassCastException e) {
+            throw new ValidationException(e);
+        }
+    }
+
+    public Scope getScope() {
+        return scope;
+    }
+
+    public ElementType getDeclaredOn() {
+        return meta.getElementType();
+    }
+
+    public Class<?> getValidatedType() {
+        return validatedType;
+    }
+
+    public Class<? extends ConstraintValidator<A, ?>> getConstraintValidatorClass() {
+        return constraintValidatorClass.get();
+    }
+
+    private <T> T read(ConstraintAnnotationAttributes attr) {
+        return Optional.of(annotation.annotationType()).map(attr::analyze).filter(Worker::isValid)
+            .map(w -> w.<T> read(annotation)).orElse(null);
+    }
+
+    private Supplier<Set<ConstraintDescriptor<?>>> computeComposingConstraints(
+        ApacheValidatorFactory validatorFactory) {
+        return () -> Stream.of(validatorFactory.getAnnotationsManager().getComposingConstraints(annotation))
+            .map(c -> new ConstraintD<>(c, scope, meta, validatorFactory)).collect(ToUnmodifiable.set());
+    }
+
+    @SuppressWarnings("unchecked")
+    private Supplier<List<Class<? extends ConstraintValidator<A, ?>>>> computeConstraintValidatorClasses(
+        ApacheValidatorFactory validatorFactory) {
+        return () -> validatorFactory.getConstraintsCache()
+            .getConstraintValidatorClasses((Class<A>) annotation.annotationType());
+    }
+
+    private ValidateUnwrappedValue computeValidateUnwrappedValue() {
+        final Set<Class<? extends Payload>> p = getPayload();
+        final boolean unwrap = p.contains(Unwrap.class);
+        final boolean skip = p.contains(Skip.class);
+        if (unwrap) {
+            Validate.validState(!skip, "Cannot specify both %s and %s", Unwrap.class.getSimpleName(),
+                Skip.class.getSimpleName());
+            return ValidateUnwrappedValue.UNWRAP;
+        }
+        return skip ? ValidateUnwrappedValue.SKIP : ValidateUnwrappedValue.DEFAULT;
+    }
+}

http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstructorD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstructorD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstructorD.java
new file mode 100644
index 0000000..9e457b5
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstructorD.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.bval.jsr.descriptor;
+
+import java.lang.reflect.Constructor;
+
+import javax.validation.metadata.ConstructorDescriptor;
+
+public class ConstructorD extends ExecutableD<Constructor<?>, MetadataReader.ForConstructor, ConstructorD>
+    implements ConstructorDescriptor {
+
+    ConstructorD(MetadataReader.ForConstructor reader, BeanD parent) {
+        super(reader, parent);
+    }
+
+    @Override
+    protected String nameOf(Constructor<?> e) {
+        return e.getDeclaringClass().getSimpleName();
+    }
+}

http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ContainerElementTypeD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ContainerElementTypeD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ContainerElementTypeD.java
new file mode 100644
index 0000000..54b2c3e
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ContainerElementTypeD.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.bval.jsr.descriptor;
+
+import java.lang.reflect.AnnotatedType;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+import javax.validation.ValidationException;
+import javax.validation.metadata.ContainerElementTypeDescriptor;
+import javax.validation.valueextraction.ValueExtractor;
+
+import org.apache.bval.jsr.GraphContext;
+import org.apache.bval.jsr.metadata.ContainerElementKey;
+import org.apache.bval.jsr.util.Exceptions;
+import org.apache.bval.jsr.util.NodeImpl;
+import org.apache.bval.util.Lazy;
+import org.apache.bval.util.Validate;
+
+public class ContainerElementTypeD extends CascadableContainerD<CascadableContainerD<?, ?>, AnnotatedType>
+    implements ContainerElementTypeDescriptor {
+
+    private static class Receiver implements ValueExtractor.ValueReceiver {
+        private final GraphContext context;
+        private Lazy<List<GraphContext>> result = new Lazy<>(ArrayList::new);
+
+        Receiver(GraphContext context) {
+            super();
+            this.context = context;
+        }
+
+        @Override
+        public void value(String nodeName, Object object) {
+            addChild(new NodeImpl.PropertyNodeImpl(nodeName), object);
+        }
+
+        @Override
+        public void iterableValue(String nodeName, Object object) {
+            final NodeImpl.PropertyNodeImpl node = new NodeImpl.PropertyNodeImpl(nodeName);
+            node.setInIterable(true);
+            addChild(node, object);
+        }
+
+        @Override
+        public void indexedValue(String nodeName, int i, Object object) {
+            final NodeImpl.PropertyNodeImpl node = new NodeImpl.PropertyNodeImpl(nodeName);
+            node.setIndex(Integer.valueOf(i));
+            addChild(node, object);
+        }
+
+        @Override
+        public void keyedValue(String nodeName, Object key, Object object) {
+            final NodeImpl.PropertyNodeImpl node = new NodeImpl.PropertyNodeImpl(nodeName);
+            node.setKey(key);
+            addChild(node, object);
+        }
+
+        private void addChild(NodeImpl node, Object value) {
+            result.get().add(context.child(node, value));
+        }
+    }
+
+    private final ContainerElementKey key;
+
+    ContainerElementTypeD(ContainerElementKey key, MetadataReader.ForContainer<AnnotatedType> reader,
+        CascadableContainerD<?, ?> parent) {
+        super(reader, parent);
+        this.key = Validate.notNull(key, "key");
+    }
+
+    @Override
+    public Class<?> getContainerClass() {
+        return key.getContainerClass();
+    }
+
+    @Override
+    public Integer getTypeArgumentIndex() {
+        return Integer.valueOf(key.getTypeArgumentIndex());
+    }
+
+    ContainerElementKey getKey() {
+        return key;
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Override
+    protected Stream<GraphContext> readImpl(GraphContext context) throws Exception {
+        final ValueExtractor valueExtractor = context.getValidatorContext().getValueExtractors().find(key);
+        Exceptions.raiseIf(valueExtractor == null, ValidationException::new, "No %s found for %s",
+            ValueExtractor.class.getSimpleName(), key);
+
+        final Receiver receiver = new Receiver(context);
+        try {
+            valueExtractor.extractValues(context.getValue(), receiver);
+        } catch (ValidationException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new ValidationException(e);
+        }
+        return receiver.result.get().stream();
+    }
+}

http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CrossParameterD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CrossParameterD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CrossParameterD.java
new file mode 100644
index 0000000..0d51800
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CrossParameterD.java
@@ -0,0 +1,18 @@
+package org.apache.bval.jsr.descriptor;
+
+import java.lang.reflect.Executable;
+
+import javax.validation.metadata.CrossParameterDescriptor;
+
+public class CrossParameterD<P extends ExecutableD<?, ?, P>, E extends Executable>
+    extends ElementD.NonRoot<P, E, MetadataReader.ForElement<E, ?>> implements CrossParameterDescriptor {
+
+    protected CrossParameterD(MetadataReader.ForElement<E, ?> reader, P parent) {
+        super(reader, parent);
+    }
+
+    @Override
+    public Class<?> getElementClass() {
+        return Object[].class;
+    }
+}

http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java
new file mode 100644
index 0000000..747e242
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You 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.apache.bval.jsr.descriptor;
+
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.validation.metadata.BeanDescriptor;
+
+import org.apache.bval.jsr.ApacheValidatorFactory;
+import org.apache.bval.jsr.metadata.AnnotationBehaviorMergeStrategy;
+import org.apache.bval.jsr.metadata.CompositeBuilder;
+import org.apache.bval.jsr.metadata.HierarchyBuilder;
+import org.apache.bval.jsr.metadata.MetadataBuilder;
+import org.apache.bval.jsr.metadata.ParallelBuilder;
+import org.apache.bval.jsr.metadata.ReflectionBuilder;
+import org.apache.bval.util.Validate;
+
+public class DescriptorManager {
+    private final ApacheValidatorFactory validatorFactory;
+    private final ConcurrentMap<Class<?>, BeanD> beanDescriptors = new ConcurrentHashMap<>();
+    private final ReflectionBuilder reflectionBuilder;
+    private final MetadataReader metadataReader;
+
+    public DescriptorManager(ApacheValidatorFactory validatorFactory) {
+        super();
+        this.validatorFactory = Validate.notNull(validatorFactory, "validatorFactory");
+        this.reflectionBuilder = new ReflectionBuilder(validatorFactory);
+        this.metadataReader = new MetadataReader(validatorFactory);
+    }
+
+    public BeanDescriptor getBeanDescriptor(Class<?> beanClass) {
+        Validate.notNull(beanClass, "beanClass");
+        return beanDescriptors.computeIfAbsent(beanClass, k -> new BeanD(metadataReader.forBean(k, builder(k))));
+    }
+
+    private MetadataBuilder.ForBean builder(Class<?> beanClass) {
+        final MetadataBuilder.ForBean primaryBuilder =
+            new HierarchyBuilder(reflectionBuilder::forBean).forBean(beanClass);
+
+        final MetadataBuilder.ForBean customBuilder = new HierarchyBuilder(this::customBuilder).forBean(beanClass);
+
+        return customBuilder.isEmpty() ? primaryBuilder : ParallelBuilder.forBean(primaryBuilder, customBuilder);
+    }
+
+    private MetadataBuilder.ForBean customBuilder(Class<?> beanClass) {
+        final List<MetadataBuilder.ForBean> customBuilders =
+            validatorFactory.getMetadataBuilders().getCustomBuilders(beanClass);
+
+        return customBuilders.isEmpty() ? null : customBuilders.stream()
+            .collect(CompositeBuilder.with(AnnotationBehaviorMergeStrategy.consensus()).compose());
+    }
+}

http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ElementD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ElementD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ElementD.java
new file mode 100644
index 0000000..c64a19a
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ElementD.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.bval.jsr.descriptor;
+
+import java.lang.annotation.ElementType;
+import java.lang.reflect.AnnotatedElement;
+import java.util.List;
+import java.util.Set;
+
+import javax.validation.metadata.ConstraintDescriptor;
+import javax.validation.metadata.ElementDescriptor;
+
+import org.apache.bval.util.Validate;
+
+public abstract class ElementD<E extends AnnotatedElement, R extends MetadataReader.ForElement<E, ?>>
+    implements ElementDescriptor {
+
+    public static abstract class NonRoot<P extends ElementD<?, ?>, E extends AnnotatedElement, R extends MetadataReader.ForElement<E, ?>>
+        extends ElementD<E, R> {
+
+        protected final P parent;
+
+        protected NonRoot(R reader, P parent) {
+            super(reader);
+            this.parent = Validate.notNull(parent, "parent");
+        }
+        
+        public P getParent() {
+            return parent;
+        }
+
+        @Override
+        final protected BeanD getBean() {
+            return parent.getBean();
+        }
+
+        @Override
+        final List<Class<?>> getGroupSequence() {
+            return getBean().getGroupSequence();
+        }
+    }
+
+    private final E target;
+    private final Set<ConstraintD<?>> constraints;
+    private final ElementType elementType;
+
+    protected ElementD(R reader) {
+        super();
+        Validate.notNull(reader, "reader");
+        target = reader.meta.getHost();
+        constraints = reader.getConstraints();
+        elementType = reader.meta.getElementType();
+    }
+
+    @Override
+    public final boolean hasConstraints() {
+        return !constraints.isEmpty();
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Override
+    public final Set<ConstraintDescriptor<?>> getConstraintDescriptors() {
+        return (Set) constraints;
+    }
+
+    @Override
+    public final ConstraintFinder findConstraints() {
+        return new Finder(this, getGroupSequence());
+    }
+
+    public final ElementType getElementType() {
+        return elementType;
+    }
+
+    public final E getTarget() {
+        return target;
+    }
+
+    @Deprecated
+    final Set<ConstraintD<?>> getConstraints() {
+        return constraints;
+    }
+
+    abstract List<Class<?>> getGroupSequence();
+
+    protected abstract BeanD getBean();
+}

http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ExecutableD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ExecutableD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ExecutableD.java
new file mode 100644
index 0000000..fe2a80e
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ExecutableD.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.bval.jsr.descriptor;
+
+import java.lang.reflect.Executable;
+import java.util.List;
+
+import javax.validation.metadata.CrossParameterDescriptor;
+import javax.validation.metadata.ExecutableDescriptor;
+import javax.validation.metadata.ParameterDescriptor;
+import javax.validation.metadata.ReturnValueDescriptor;
+
+public abstract class ExecutableD<E extends Executable, R extends MetadataReader.ForExecutable<E,R>, SELF extends ExecutableD<E, R, SELF>>
+    extends ElementD.NonRoot<BeanD, E, R> implements ExecutableDescriptor {
+
+    private final String name;
+    private final ReturnValueD<SELF, E> returnValue;
+    private final List<ParameterD<SELF>> parameters;
+    private final CrossParameterD<SELF, E> crossParameter;
+
+    @SuppressWarnings("unchecked")
+    protected ExecutableD(R reader, BeanD parent) {
+        super(reader, parent);
+
+        name = reader.meta.getName();
+
+        returnValue = reader.getReturnValueDescriptor((SELF) this);
+        parameters = reader.getParameterDescriptors((SELF) this);
+        crossParameter = reader.getCrossParameterDescriptor((SELF) this);
+    }
+
+    @Override
+    public final String getName() {
+        return name;
+    }
+
+    @Override
+    public final Class<?> getElementClass() {
+        return returnValue.getElementClass();
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Override
+    public final List<ParameterDescriptor> getParameterDescriptors() {
+        return (List) parameters;
+    }
+
+    @Override
+    public final CrossParameterDescriptor getCrossParameterDescriptor() {
+        return crossParameter;
+    }
+
+    @Override
+    public final ReturnValueDescriptor getReturnValueDescriptor() {
+        return returnValue;
+    }
+
+    @Override
+    public final boolean hasConstrainedParameters() {
+        return parameters.stream().anyMatch(this::isConstrained);
+    }
+
+    @Override
+    public final boolean hasConstrainedReturnValue() {
+        return isConstrained(returnValue);
+    }
+
+    protected abstract String nameOf(E e);
+
+    private boolean isConstrained(CascadableContainerD<?, ?> child) {
+        return child.isCascaded() || child.hasConstraints();
+    }
+}


Mime
View raw message