You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by ra...@apache.org on 2018/10/12 15:00:51 UTC

svn commit: r1843674 [9/22] - in /tomee/deps/branches/bval-2: ./ bundle/ bundle/src/ bundle/src/main/ bundle/src/main/appended-resources/ bundle/src/main/appended-resources/META-INF/ bval-extras/ bval-extras/src/ bval-extras/src/main/ bval-extras/src/m...

Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateProperty.java
URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateProperty.java?rev=1843674&view=auto
==============================================================================
--- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateProperty.java (added)
+++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateProperty.java Fri Oct 12 15:00:48 2018
@@ -0,0 +1,565 @@
+/*
+ * 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.job;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.ValidationException;
+import javax.validation.metadata.BeanDescriptor;
+import javax.validation.metadata.CascadableDescriptor;
+import javax.validation.metadata.ContainerDescriptor;
+import javax.validation.metadata.ContainerElementTypeDescriptor;
+import javax.validation.metadata.ElementDescriptor;
+import javax.validation.metadata.PropertyDescriptor;
+import javax.validation.valueextraction.ValueExtractor;
+import javax.validation.valueextraction.ValueExtractor.ValueReceiver;
+
+import org.apache.bval.jsr.ApacheFactoryContext;
+import org.apache.bval.jsr.ConstraintViolationImpl;
+import org.apache.bval.jsr.GraphContext;
+import org.apache.bval.jsr.descriptor.BeanD;
+import org.apache.bval.jsr.descriptor.CascadableContainerD;
+import org.apache.bval.jsr.descriptor.ComposedD;
+import org.apache.bval.jsr.descriptor.ConstraintD;
+import org.apache.bval.jsr.descriptor.ContainerElementTypeD;
+import org.apache.bval.jsr.descriptor.DescriptorManager;
+import org.apache.bval.jsr.descriptor.ElementD;
+import org.apache.bval.jsr.descriptor.PropertyD;
+import org.apache.bval.jsr.groups.GroupStrategy;
+import org.apache.bval.jsr.metadata.ContainerElementKey;
+import org.apache.bval.jsr.util.PathImpl;
+import org.apache.bval.jsr.util.PathNavigation;
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.ObjectWrapper;
+import org.apache.bval.util.StringUtils;
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.TypeUtils;
+
+public final class ValidateProperty<T> extends ValidationJob<T> {
+
+    interface Strategy<T> {
+        T getRootBean();
+
+        PathNavigation.Callback<?> callback(PathImpl.Builder pathBuilder, FindDescriptor findDescriptor,
+            ObjectWrapper<Boolean> reachable);
+
+        ValidateProperty<T>.Frame<?> frame(ValidateProperty<T> job, PathImpl path);
+    }
+
+    static class ForBeanProperty<T> implements Strategy<T> {
+        final ApacheFactoryContext validatorContext;
+        final T rootBean;
+        final GraphContext rootContext;
+        final ObjectWrapper<GraphContext> leafContext;
+        final ObjectWrapper<Object> value;
+
+        ForBeanProperty(ApacheFactoryContext validatorContext, T bean) {
+            super();
+            this.validatorContext = validatorContext;
+            this.rootBean = bean;
+            this.rootContext = new GraphContext(validatorContext, PathImpl.create(), bean);
+            this.leafContext = new ObjectWrapper<>(rootContext);
+            this.value = new ObjectWrapper<>(bean);
+        }
+
+        @Override
+        public T getRootBean() {
+            return rootBean;
+        }
+
+        @Override
+        public PathNavigation.Callback<?> callback(PathImpl.Builder pathBuilder, FindDescriptor findDescriptor,
+            ObjectWrapper<Boolean> reachable) {
+            return new WalkGraph(validatorContext, rootBean.getClass(), pathBuilder, findDescriptor, value, reachable,
+                (p, v) -> leafContext.accept(p.isRootPath() ? rootContext : rootContext.child(p, v)));
+        }
+
+        @Override
+        public ValidateProperty<T>.Frame<?> frame(ValidateProperty<T> job, PathImpl path) {
+            if (job.descriptor instanceof BeanDescriptor) {
+                return job.new LeafFrame<>(leafContext.get());
+            }
+            return job.new PropertyFrame<PropertyD<?>>(job.new BeanFrame<>(leafContext.get()),
+                (PropertyD<?>) job.descriptor, leafContext.get().child(path, value.get()));
+        }
+    }
+
+    static class ForPropertyValue<T> implements Strategy<T> {
+        final ApacheFactoryContext validatorContext;
+        final Class<?> rootBeanClass;
+        final Object value;
+
+        ForPropertyValue(ApacheFactoryContext validatorContext, Class<?> rootBeanClass, Object value) {
+            super();
+            this.validatorContext = validatorContext;
+            this.rootBeanClass = rootBeanClass;
+            this.value = value;
+        }
+
+        @Override
+        public T getRootBean() {
+            return null;
+        }
+
+        @Override
+        public PathNavigation.Callback<?> callback(PathImpl.Builder pathBuilder, FindDescriptor findDescriptor,
+            ObjectWrapper<Boolean> reachable) {
+            return new WalkGraph(validatorContext, rootBeanClass, pathBuilder, findDescriptor, new ObjectWrapper<>(),
+                reachable, null);
+        }
+
+        @Override
+        public ValidateProperty<T>.Frame<?> frame(ValidateProperty<T> job, PathImpl path) {
+            final GraphContext context = new GraphContext(job.validatorContext, path, value);
+            if (job.descriptor instanceof BeanDescriptor) {
+                return job.new LeafFrame<>(context);
+            }
+            return job.new PropertyFrame<PropertyD<?>>(null, (PropertyD<?>) job.descriptor, context);
+        }
+    }
+
+    private interface Step {
+        Type type();
+
+        ElementD<?, ?> element();
+    }
+
+    private static class DescriptorWrapper implements Step {
+        final ElementD<?, ?> wrapped;
+
+        DescriptorWrapper(ElementDescriptor wrapped) {
+            super();
+            this.wrapped = (ElementD<?, ?>) wrapped;
+        }
+
+        @Override
+        public Type type() {
+            return wrapped.getGenericType();
+        }
+
+        @Override
+        public ElementD<?, ?> element() {
+            return wrapped;
+        }
+    }
+
+    private static class TypeWrapper implements Step {
+        final ApacheFactoryContext validatorContext;
+        final Type type;
+
+        TypeWrapper(ApacheFactoryContext validatorContext, Type type) {
+            super();
+            this.validatorContext = validatorContext;
+            this.type = type;
+        }
+
+        @Override
+        public Type type() {
+            return type;
+        }
+
+        @Override
+        public ElementD<?, ?> element() {
+            final Class<?> beanClass = TypeUtils.getRawType(type, null);
+            return beanClass == null ? null
+                : (BeanD<?>) validatorContext.getDescriptorManager().getBeanDescriptor(beanClass);
+        }
+    }
+
+    private static class FindDescriptor implements PathNavigation.Callback<ElementD<?, ?>> {
+        private final ApacheFactoryContext validatorContext;
+        Step current;
+
+        FindDescriptor(ApacheFactoryContext validatorContext, Class<?> beanClass) {
+            this.validatorContext = validatorContext;
+            this.current = new DescriptorWrapper(validatorContext.getDescriptorManager().getBeanDescriptor(beanClass));
+        }
+
+        @Override
+        public void handleProperty(String name) {
+            final ElementDescriptor element = current.element();
+            final BeanD<?> bean;
+            if (element instanceof BeanD<?>) {
+                bean = (BeanD<?>) element;
+            } else {
+                bean = (BeanD<?>) validatorContext.getDescriptorManager().getBeanDescriptor(element.getElementClass());
+            }
+            final PropertyDescriptor property = bean.getProperty(name);
+            if (property == null) {
+                Exceptions.raise(IllegalArgumentException::new, "Unknown property %s of %s", name,
+                    bean.getElementClass());
+            }
+            current = new DescriptorWrapper(property);
+        }
+
+        @Override
+        public void handleIndexOrKey(String value) {
+            handleGenericInIterable();
+        }
+
+        @Override
+        public void handleGenericInIterable() {
+            final ElementDescriptor desc = current.element();
+            if (desc instanceof CascadableContainerD<?, ?>) {
+                final Step containerElement = handleContainerElement((CascadableContainerD<?, ?>) desc);
+                if (containerElement != null) {
+                    current = containerElement;
+                    return;
+                }
+            }
+            current = handleElementByType(current.type());
+        }
+
+        private Step handleContainerElement(CascadableContainerD<?, ?> desc) {
+            final Set<ContainerElementTypeDescriptor> containerElements = desc.getConstrainedContainerElementTypes();
+            if (containerElements.isEmpty()) {
+                return null;
+            }
+            final ContainerElementTypeDescriptor element;
+            if (containerElements.size() == 1) {
+                element = containerElements.iterator().next();
+            } else {
+                final Collection<TypeVariable<?>> wellKnown = Arrays.asList(MAP_VALUE, ITERABLE_ELEMENT);
+
+                final Optional<ContainerElementTypeD> found =
+                    containerElements.stream().<ContainerElementTypeD> map(ContainerElementTypeD.class::cast)
+                        .filter(d -> wellKnown.stream().anyMatch(d.getKey()::represents)).findFirst();
+
+                if (!found.isPresent()) {
+                    return null;
+                }
+                element = found.get();
+            }
+            return new DescriptorWrapper(element);
+        }
+
+        private Step handleElementByType(Type type) {
+            Type elementType;
+
+            if (TypeUtils.isArrayType(type)) {
+                elementType = TypeUtils.getArrayComponentType(type);
+            } else if (TypeUtils.isAssignable(type, Map.class)) {
+                elementType =
+                    Optional.ofNullable(TypeUtils.getTypeArguments(type, Map.class).get(MAP_VALUE)).orElse(MAP_VALUE);
+            } else if (TypeUtils.isAssignable(type, Iterable.class)) {
+                elementType =
+                    Optional.ofNullable(TypeUtils.getTypeArguments(type, Iterable.class).get(ITERABLE_ELEMENT))
+                        .orElse(ITERABLE_ELEMENT);
+            } else {
+                throw Exceptions.create(IllegalArgumentException::new, "Unable to resolve element type of %s", type);
+            }
+            return new TypeWrapper(validatorContext, elementType);
+        }
+
+        @Override
+        public ElementD<?, ?> result() {
+            return current.element();
+        }
+    }
+
+    private static class WalkGraph extends PathNavigation.CallbackProcedure {
+        final ApacheFactoryContext validatorContext;
+        final Class<?> rootBeanClass;
+        final PathImpl.Builder pathBuilder;
+        final FindDescriptor findDescriptor;
+        final ObjectWrapper<Object> value;
+        final ObjectWrapper<Boolean> reachable;
+        final BiConsumer<PathImpl, Object> recordLeaf;
+
+        WalkGraph(ApacheFactoryContext validatorContext, Class<?> rootBeanClass, PathImpl.Builder pathBuilder,
+            FindDescriptor findDescriptor, ObjectWrapper<Object> value, ObjectWrapper<Boolean> reachable,
+            BiConsumer<PathImpl, Object> recordLeaf) {
+            this.validatorContext = validatorContext;
+            this.rootBeanClass = rootBeanClass;
+            this.pathBuilder = pathBuilder;
+            this.findDescriptor = findDescriptor;
+            this.value = value;
+            this.reachable = reachable;
+            this.recordLeaf = recordLeaf;
+        }
+
+        @Override
+        public void handleProperty(String name) {
+            final PathImpl p = PathImpl.copy(pathBuilder.result());
+            pathBuilder.handleProperty(name);
+            findDescriptor.handleProperty(name);
+
+            if (reachable.get().booleanValue()) {
+                try {
+                    reachable.accept(validatorContext.getTraversableResolver().isReachable(value.get(),
+                        pathBuilder.result().getLeafNode(), rootBeanClass, p,
+                        findDescriptor.result().getElementType()));
+                } catch (ValidationException ve) {
+                    throw ve;
+                } catch (Exception e) {
+                    throw new ValidationException(e);
+                }
+            }
+            if (reachable.get().booleanValue() && value.optional().isPresent() && recordLeaf != null) {
+                recordLeaf.accept(p, value.get());
+
+                final PropertyD<?> propertyD =
+                    ComposedD.unwrap(findDescriptor.current.element(), PropertyD.class).findFirst().get();
+                try {
+                    value.accept(propertyD.getValue(value.get()));
+                } catch (Exception e) {
+                    Exceptions.raise(IllegalStateException::new, e, "Unable to get value of property %s",
+                        propertyD.getPropertyName());
+                }
+            }
+        }
+
+        @Override
+        public void handleIndexOrKey(final String indexOrKey) {
+            pathBuilder.handleIndexOrKey(indexOrKey);
+            findDescriptor.handleIndexOrKey(indexOrKey);
+            if (value.optional().isPresent()) {
+                ElementDescriptor element = findDescriptor.current.element();
+                if (element instanceof ContainerElementTypeD) {
+                    value.accept(handleContainer(value.get(), ((ContainerElementTypeD) element).getKey(), indexOrKey));
+                } else {
+                    value.accept(handleBasic(value.get(), indexOrKey));
+
+                    if (element == null && value.optional().isPresent()) {
+                        // no generic info available at some previous index level; fall back to runtime type of value
+                        // and repair structure of findDescriptor:
+                        findDescriptor.current = new TypeWrapper(validatorContext, value.get().getClass());
+                        element = findDescriptor.current.element();
+                    }
+                    if (element instanceof BeanDescriptor) {
+                        recordLeaf.accept(PathImpl.copy(pathBuilder.result()), value.get());
+                    }
+                }
+            }
+        }
+
+        @SuppressWarnings("unchecked")
+        private Object handleContainer(Object o, ContainerElementKey key, String indexOrKey) {
+            @SuppressWarnings("rawtypes")
+            final ValueExtractor valueExtractor = validatorContext.getValueExtractors().find(key);
+
+            final ObjectWrapper<Object> result = new ObjectWrapper<>();
+            valueExtractor.extractValues(o, new ValueReceiver() {
+
+                @Override
+                public void indexedValue(String nodeName, int index, Object object) {
+                    if (Integer.toString(index).equals(indexOrKey)) {
+                        result.accept(object);
+                    }
+                }
+
+                @Override
+                public void iterableValue(String nodeName, Object object) {
+                    // ?
+                    result.accept(object);
+                }
+
+                @Override
+                public void keyedValue(String nodeName, Object key, Object object) {
+                    if (String.valueOf(key).equals(indexOrKey)) {
+                        result.accept(object);
+                    }
+                }
+
+                @Override
+                public void value(String nodeName, Object object) {
+                    // ?
+                    result.accept(object);
+                }
+            });
+            return result.get();
+        }
+
+        private Object handleBasic(Object o, String indexOrKey) {
+            if (Map.class.isInstance(o)) {
+                for (Map.Entry<?, ?> e : ((Map<?, ?>) o).entrySet()) {
+                    if (String.valueOf(e.getKey()).equals(indexOrKey)) {
+                        return e.getValue();
+                    }
+                }
+            } else {
+                try {
+                    final int index = Integer.parseInt(indexOrKey);
+                    if (index < 0) {
+                        Exceptions.raise(IllegalArgumentException::new, "Invalid index %d", index);
+                    }
+                    if (o != null && TypeUtils.isArrayType(o.getClass())) {
+                        if (Array.getLength(o) > index) {
+                            return Array.get(o, index);
+                        }
+                    } else if (List.class.isInstance(o)) {
+                        final List<?> l = (List<?>) o;
+                        if (l.size() > index) {
+                            return l.get(index);
+                        }
+                    } else if (Iterable.class.isInstance(o)) {
+                        int i = -1;
+                        for (Object e : (Iterable<?>) o) {
+                            if (++i == index) {
+                                return e;
+                            }
+                        }
+                    }
+                } catch (NumberFormatException e) {
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public void handleGenericInIterable() {
+            throw new UnsupportedOperationException("Cannot resolve generic inIterable against actual object graph");
+        }
+    }
+
+    class LeafFrame<L> extends BeanFrame<L> {
+
+        LeafFrame(GraphContext context) {
+            super(context);
+        }
+
+        @Override
+        protected ValidationJob<T>.Frame<?> propertyFrame(PropertyD<?> d, GraphContext context) {
+            return new PropertyFrame<>(this, d, context);
+        }
+    }
+
+    class PropertyFrame<D extends ElementD<?, ?> & CascadableDescriptor & ContainerDescriptor> extends SproutFrame<D> {
+
+        PropertyFrame(ValidationJob<T>.Frame<?> parent, D descriptor, GraphContext context) {
+            super(parent, descriptor, context);
+        }
+
+        @Override
+        void recurse(GroupStrategy groups, Consumer<ConstraintViolation<T>> sink) {
+            if (cascade) {
+                super.recurse(groups, sink);
+            }
+        }
+    }
+
+    private final Strategy<T> strategy;
+    private final Class<T> rootBeanClass;
+    private final PathImpl propertyPath;
+    private final T rootBean;
+    private final boolean reachable;
+    private ElementD<?, ?> descriptor;
+    private boolean cascade;
+
+    private ValidateProperty(Strategy<T> strategy, ApacheFactoryContext validatorContext, Class<T> rootBeanClass,
+        String property, Class<?>[] groups) {
+        super(validatorContext, groups);
+
+        Exceptions.raiseIf(StringUtils.isBlank(property), IllegalArgumentException::new,
+            "property cannot be null/empty/blank");
+
+        this.strategy = strategy;
+        this.rootBeanClass = Validate.notNull(rootBeanClass, IllegalArgumentException::new, "rootBeanClass");
+
+        final PathImpl.Builder pathBuilder = new PathImpl.Builder();
+        final FindDescriptor findDescriptor = new FindDescriptor(validatorContext, rootBeanClass);
+        final ObjectWrapper<Boolean> reachable = new ObjectWrapper<>(Boolean.TRUE);
+
+        PathNavigation.navigate(property, strategy.callback(pathBuilder, findDescriptor, reachable));
+
+        this.propertyPath = pathBuilder.result();
+        this.descriptor = findDescriptor.result();
+        this.rootBean = strategy.getRootBean();
+        this.reachable = reachable.get().booleanValue();
+    }
+
+    ValidateProperty(ApacheFactoryContext validatorContext, Class<T> rootBeanClass, String property, Object value,
+        Class<?>[] groups) {
+        this(new ForPropertyValue<>(validatorContext, rootBeanClass, value), validatorContext, rootBeanClass, property,
+            groups);
+        if (descriptor == null) {
+            // should only occur when the root class is raw
+
+            final Class<?> t;
+            if (value == null) {
+                t = Object.class;
+            } else {
+                t = value.getClass();
+            }
+            descriptor = (ElementD<?, ?>) validatorContext.getDescriptorManager().getBeanDescriptor(t);
+        } else if (hasWork()) {
+            final Class<?> propertyType = descriptor.getElementClass();
+            if (!TypeUtils.isInstance(value, propertyType)) {
+                Exceptions.raise(IllegalArgumentException::new, "%s is not an instance of %s", value, propertyType);
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    ValidateProperty(ApacheFactoryContext validatorContext, T bean, String property, Class<?>[] groups)
+        throws Exception {
+        this(new ForBeanProperty<>(validatorContext, Validate.notNull(bean, IllegalArgumentException::new, "bean")),
+            validatorContext, (Class<T>) bean.getClass(), property, groups);
+
+        if (descriptor == null) {
+            Exceptions.raise(IllegalArgumentException::new, "Could not resolve property name/path: %s", property);
+        }
+    }
+
+    public ValidateProperty<T> cascade(boolean cascade) {
+        this.cascade = cascade;
+        return this;
+    }
+
+    @Override
+    protected Frame<?> computeBaseFrame() {
+        // TODO assign bean as its own property and figure out what to do
+        return strategy.frame(this, propertyPath);
+    }
+
+    @Override
+    protected Class<T> getRootBeanClass() {
+        return rootBeanClass;
+    }
+
+    @Override
+    protected boolean hasWork() {
+        if (!reachable) {
+            return false;
+        }
+        if (descriptor instanceof BeanDescriptor) {
+            return ((BeanDescriptor) descriptor).isBeanConstrained();
+        }
+        return DescriptorManager.isConstrained((PropertyDescriptor) descriptor);
+    }
+
+    @Override
+    ConstraintViolationImpl<T> createViolation(String messageTemplate, String message,
+        ConstraintValidatorContextImpl<T> context, PathImpl propertyPath) {
+        return new ConstraintViolationImpl<>(messageTemplate, message, rootBean, context.getFrame().getBean(),
+            propertyPath, context.getFrame().context.getValue(), context.getConstraintDescriptor(), rootBeanClass,
+            context.getConstraintDescriptor().unwrap(ConstraintD.class).getDeclaredOn(), null, null);
+    }
+}

Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java
URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java?rev=1843674&view=auto
==============================================================================
--- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java (added)
+++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java Fri Oct 12 15:00:48 2018
@@ -0,0 +1,152 @@
+/*
+ *  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.job;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+
+import javax.validation.metadata.ExecutableDescriptor;
+
+import org.apache.bval.jsr.ApacheFactoryContext;
+import org.apache.bval.jsr.ConstraintViolationImpl;
+import org.apache.bval.jsr.GraphContext;
+import org.apache.bval.jsr.descriptor.ConstraintD;
+import org.apache.bval.jsr.descriptor.ReturnValueD;
+import org.apache.bval.jsr.metadata.Meta;
+import org.apache.bval.jsr.util.NodeImpl;
+import org.apache.bval.jsr.util.PathImpl;
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.TypeUtils;
+
+public abstract class ValidateReturnValue<E extends Executable, T> extends ValidateExecutable<E, T> {
+    public static class ForMethod<T> extends ValidateReturnValue<Method, T> {
+        private final T object;
+
+        ForMethod(ApacheFactoryContext validatorContext, T object, Method method, Object returnValue,
+            Class<?>[] groups) {
+            super(validatorContext,
+                new Meta.ForMethod(Validate.notNull(method, IllegalArgumentException::new, "method")), returnValue,
+                groups);
+            this.object = Validate.notNull(object, IllegalArgumentException::new, "object");
+        }
+
+        @Override
+        protected T getRootBean() {
+            return object;
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        protected Class<T> getRootBeanClass() {
+            return (Class<T>) object.getClass();
+        }
+
+        @Override
+        protected ExecutableDescriptor describe() {
+            return validatorContext.getDescriptorManager().getBeanDescriptor(object.getClass())
+                .getConstraintsForMethod(executable.getName(), executable.getParameterTypes());
+        }
+
+        @Override
+        protected ValidationJob<T>.Frame<?> createBaseFrame(ReturnValueD<?, ?> descriptor, GraphContext context) {
+            return new SproutFrame<ReturnValueD<?, ?>>(descriptor, context) {
+                @Override
+                Object getBean() {
+                    return getRootBean();
+                }
+            };
+        }
+    }
+
+    public static class ForConstructor<T> extends ValidateReturnValue<Constructor<?>, T> {
+
+        ForConstructor(ApacheFactoryContext validatorContext, Constructor<? extends T> ctor, Object returnValue,
+            Class<?>[] groups) {
+            super(validatorContext,
+                new Meta.ForConstructor<>(Validate.notNull(ctor, IllegalArgumentException::new, "ctor")),
+                Validate.notNull(returnValue, IllegalArgumentException::new, "constructor cannot return null"), groups);
+        }
+
+        @Override
+        protected T getRootBean() {
+            return null;
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        protected Class<T> getRootBeanClass() {
+            return (Class<T>) executable.getDeclaringClass();
+        }
+
+        @Override
+        protected ExecutableDescriptor describe() {
+            return validatorContext.getDescriptorManager().getBeanDescriptor(executable.getDeclaringClass())
+                .getConstraintsForConstructor(executable.getParameterTypes());
+        }
+
+        @Override
+        protected ValidationJob<T>.Frame<?> createBaseFrame(ReturnValueD<?, ?> descriptor, GraphContext context) {
+            final Object returnValue = context.getValue();
+            return new SproutFrame<ReturnValueD<?, ?>>(descriptor, context) {
+                @Override
+                Object getBean() {
+                    return returnValue;
+                }
+            };
+        }
+    }
+
+    private final Object returnValue;
+
+    ValidateReturnValue(ApacheFactoryContext validatorContext, Meta<E> meta, Object returnValue, Class<?>[] groups) {
+        super(validatorContext, groups, meta);
+
+        final Type type = Validate.notNull(meta, IllegalArgumentException::new, "meta").getType();
+        if (!TypeUtils.isInstance(returnValue, type)) {
+            Exceptions.raise(IllegalArgumentException::new, "%s is not an instance of %s", returnValue, type);
+        }
+        this.returnValue = returnValue;
+    }
+
+    @Override
+    protected Frame<?> computeBaseFrame() {
+        return createBaseFrame((ReturnValueD<?, ?>) describe().getReturnValueDescriptor(), new GraphContext(
+            validatorContext, createBasePath().addNode(new NodeImpl.ReturnValueNodeImpl()), returnValue));
+    }
+
+    @Override
+    ConstraintViolationImpl<T> createViolation(String messageTemplate, String message,
+        ConstraintValidatorContextImpl<T> context, PathImpl propertyPath) {
+        return new ConstraintViolationImpl<>(messageTemplate, message, getRootBean(), context.getFrame().getBean(),
+            propertyPath, context.getFrame().context.getValue(), context.getConstraintDescriptor(), getRootBeanClass(),
+            context.getConstraintDescriptor().unwrap(ConstraintD.class).getDeclaredOn(), returnValue, null);
+    }
+
+    @Override
+    protected boolean hasWork() {
+        return describe() != null;
+    }
+
+    protected abstract ExecutableDescriptor describe();
+
+    protected abstract T getRootBean();
+
+    protected abstract Frame<?> createBaseFrame(ReturnValueD<?, ?> descriptor, GraphContext context);
+}

Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java
URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java?rev=1843674&view=auto
==============================================================================
--- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java (added)
+++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java Fri Oct 12 15:00:48 2018
@@ -0,0 +1,624 @@
+/*
+ * 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.job;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintViolation;
+import javax.validation.ElementKind;
+import javax.validation.MessageInterpolator;
+import javax.validation.Path;
+import javax.validation.TraversableResolver;
+import javax.validation.UnexpectedTypeException;
+import javax.validation.ValidationException;
+import javax.validation.constraintvalidation.ValidationTarget;
+import javax.validation.groups.Default;
+import javax.validation.metadata.CascadableDescriptor;
+import javax.validation.metadata.ContainerDescriptor;
+import javax.validation.metadata.PropertyDescriptor;
+import javax.validation.metadata.ValidateUnwrappedValue;
+import javax.validation.valueextraction.ValueExtractor;
+
+import org.apache.bval.jsr.ApacheFactoryContext;
+import org.apache.bval.jsr.ConstraintViolationImpl;
+import org.apache.bval.jsr.GraphContext;
+import org.apache.bval.jsr.descriptor.BeanD;
+import org.apache.bval.jsr.descriptor.ComposedD;
+import org.apache.bval.jsr.descriptor.ConstraintD;
+import org.apache.bval.jsr.descriptor.ContainerElementTypeD;
+import org.apache.bval.jsr.descriptor.DescriptorManager;
+import org.apache.bval.jsr.descriptor.ElementD;
+import org.apache.bval.jsr.descriptor.PropertyD;
+import org.apache.bval.jsr.groups.Group;
+import org.apache.bval.jsr.groups.GroupStrategy;
+import org.apache.bval.jsr.groups.Groups;
+import org.apache.bval.jsr.metadata.ContainerElementKey;
+import org.apache.bval.jsr.util.NodeImpl;
+import org.apache.bval.jsr.util.PathImpl;
+import org.apache.bval.jsr.util.Proxies;
+import org.apache.bval.jsr.valueextraction.ExtractValues;
+import org.apache.bval.jsr.valueextraction.ValueExtractors;
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.Lazy;
+import org.apache.bval.util.ObjectUtils;
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.TypeUtils;
+
+public abstract class ValidationJob<T> {
+
+    public abstract class Frame<D extends ElementD<?, ?>> {
+        protected final Frame<?> parent;
+        protected final D descriptor;
+        protected final GraphContext context;
+
+        protected Frame(Frame<?> parent, D descriptor, GraphContext context) {
+            super();
+            this.parent = parent;
+            this.descriptor = Validate.notNull(descriptor, "descriptor");
+            this.context = Validate.notNull(context, "context");
+        }
+
+        protected ValidationTarget getValidationTarget() {
+            return ValidationTarget.ANNOTATED_ELEMENT;
+        }
+
+        final ValidationJob<T> getJob() {
+            return ValidationJob.this;
+        }
+
+        void process(GroupStrategy groups, Consumer<ConstraintViolation<T>> sink) {
+            Validate.notNull(sink, "sink");
+
+            GroupStrategy.redefining(groups, Collections.singletonMap(Group.DEFAULT, descriptor.getGroupStrategy()))
+                .applyTo(noViolations(gs -> validateDescriptorConstraints(gs, sink)));
+
+            recurse(groups, sink);
+        }
+
+        void recurse(GroupStrategy groups, Consumer<ConstraintViolation<T>> sink) {
+            throw new UnsupportedOperationException();
+        }
+
+        abstract Object getBean();
+
+        void validateDescriptorConstraints(GroupStrategy groups, Consumer<ConstraintViolation<T>> sink) {
+            constraintsFor(descriptor, groups)
+                .forEach(c -> unwrap(c.getValueUnwrapping()).forEach(f -> f.validate(c, sink)));
+        }
+
+        private Stream<Frame<D>> unwrap(ValidateUnwrappedValue valueUnwrapping) {
+            if (valueUnwrapping != ValidateUnwrappedValue.SKIP && context.getValue() != null) {
+                final Optional<ValueExtractors.UnwrappingInfo> valueExtractorAndAssociatedContainerElementKey =
+                    validatorContext.getValueExtractors().findUnwrappingInfo(context.getValue().getClass(),
+                        valueUnwrapping);
+
+                if (valueExtractorAndAssociatedContainerElementKey.isPresent()) {
+                    return ExtractValues
+                        .extract(context, valueExtractorAndAssociatedContainerElementKey.get().containerElementKey,
+                            valueExtractorAndAssociatedContainerElementKey.get().valueExtractor)
+                        .stream().map(child -> new UnwrappedElementConstraintValidationPseudoFrame<>(this, child));
+                }
+            }
+            return Stream.of(this);
+        }
+
+        @SuppressWarnings({ "rawtypes", "unchecked" })
+        private boolean validate(ConstraintD<?> constraint, Consumer<ConstraintViolation<T>> sink) {
+            final ConcurrentMap<Path, Set<Object>> pathMap = completedValidations.computeIfAbsent(constraint,
+                k -> new ConcurrentSkipListMap<>(PathImpl.PATH_COMPARATOR));
+            final Set<Object> objectSet =
+                pathMap.computeIfAbsent(context.getPath(), p -> Collections.newSetFromMap(new IdentityHashMap<>()));
+            if (!objectSet.add(context.getValue())) {
+                return true;
+            }
+            final ConstraintValidator constraintValidator = getConstraintValidator(constraint);
+            final ConstraintValidatorContextImpl<T> constraintValidatorContext =
+                new ConstraintValidatorContextImpl<>(this, constraint);
+
+            final boolean valid;
+            if (constraintValidator == null) {
+                // null validator without exception implies composition:
+                valid = true;
+            } else {
+                try {
+                    constraintValidator.initialize(constraint.getAnnotation());
+                    valid = constraintValidator.isValid(context.getValue(), constraintValidatorContext);
+                } catch (ValidationException e) {
+                    throw e;
+                } catch (Exception e) {
+                    throw new ValidationException(e);
+                }
+                if (!valid) {
+                    constraintValidatorContext.getRequiredViolations().forEach(sink);
+                }
+            }
+            if (valid || !constraint.isReportAsSingleViolation()) {
+                final boolean compositionValid = validateComposed(constraint, sink);
+
+                if (!compositionValid) {
+                    if (valid && constraint.isReportAsSingleViolation()) {
+                        constraintValidatorContext.getRequiredViolations().forEach(sink);
+                    }
+                    return false;
+                }
+            }
+            return valid;
+        }
+
+        private boolean validateComposed(ConstraintD<?> constraint, Consumer<ConstraintViolation<T>> sink) {
+            if (constraint.getComposingConstraints().isEmpty()) {
+                return true;
+            }
+            final Consumer<ConstraintViolation<T>> effectiveSink = constraint.isReportAsSingleViolation() ? cv -> {
+            } : sink;
+
+            // collect validation results to set of Boolean, ensuring all are evaluated:
+            final Set<Boolean> validationResults = constraint.getComposingConstraints().stream().map(ConstraintD.class::cast)
+                .map(c -> validate(c, effectiveSink)).collect(Collectors.toSet());
+
+            return Collections.singleton(Boolean.TRUE).equals(validationResults);
+        }
+
+        @SuppressWarnings({ "rawtypes" })
+        private ConstraintValidator getConstraintValidator(ConstraintD<?> constraint) {
+            final Class<? extends ConstraintValidator> constraintValidatorClass =
+                new ComputeConstraintValidatorClass<>(validatorContext.getConstraintsCache(), constraint,
+                    getValidationTarget(), computeValidatedType(constraint)).get();
+
+            if (constraintValidatorClass == null) {
+                if (constraint.getComposingConstraints().isEmpty()) {
+                    Exceptions.raise(UnexpectedTypeException::new, "No %s type located for non-composed constraint %s",
+                        ConstraintValidator.class.getSimpleName(), constraint);
+                }
+                return null;
+            }
+            ConstraintValidator constraintValidator = null;
+            Exception cause = null;
+            try {
+                constraintValidator =
+                    validatorContext.getConstraintValidatorFactory().getInstance(constraintValidatorClass);
+            } catch (Exception e) {
+                cause = e;
+            }
+            if (constraintValidator == null) {
+                Exceptions.raise(ValidationException::new, cause, "Unable to get %s instance from %s",
+                    constraintValidatorClass.getName(), validatorContext.getConstraintValidatorFactory());
+            }
+            return constraintValidator;
+        }
+
+        private Class<?> computeValidatedType(ConstraintD<?> constraint) {
+            if (context.getValue() != null) {
+                return context.getValue().getClass();
+            }
+            final Class<?> elementClass = descriptor.getElementClass();
+
+            final Optional<Class<?>> extractedType =
+                validatorContext.getValueExtractors().findUnwrappingInfo(elementClass, constraint.getValueUnwrapping())
+                    .map(info -> ValueExtractors.getExtractedType(info.valueExtractor, elementClass));
+
+            return extractedType.orElse(elementClass);
+        }
+    }
+
+    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.child(context.getPath().addBean(), context.getValue()));
+            this.realContext = context;
+        }
+
+        void process(GroupStrategy groups, Consumer<ConstraintViolation<T>> sink) {
+            Validate.notNull(sink, "sink");
+            final Lazy<Set<Frame<?>>> propertyFrames = new Lazy<>(this::propertyFrames);
+
+            final GroupStrategy localGroupStrategy = GroupStrategy.redefining(groups,
+                Collections.singletonMap(Group.DEFAULT, descriptor.getGroupStrategy()));
+
+            localGroupStrategy.applyTo(noViolations(gs -> {
+                validateDescriptorConstraints(gs, sink);
+                propertyFrames.get().forEach(p -> {
+                    p.validateDescriptorConstraints(gs, sink);
+                    if (localGroupStrategy == groups) {
+                        p.recurse(gs, sink);
+                    }
+                });
+            }));
+            if (localGroupStrategy != groups) {
+                propertyFrames.get().forEach(p -> p.recurse(groups, sink));
+            }
+        }
+
+        protected Frame<?> propertyFrame(PropertyD<?> d, GraphContext context) {
+            return new SproutFrame<>(this, d, context);
+        }
+
+        @Override
+        Object getBean() {
+            return context.getValue();
+        }
+
+        private Set<Frame<?>> propertyFrames() {
+            final Stream<PropertyD<?>> properties = descriptor.getConstrainedProperties().stream()
+                .flatMap(d -> ComposedD.unwrap(d, PropertyD.class)).map(d -> (PropertyD<?>) d);
+
+            final TraversableResolver traversableResolver = validatorContext.getTraversableResolver();
+
+            final Stream<PropertyD<?>> reachableProperties = properties.filter(d -> {
+                final PathImpl p = realContext.getPath();
+                p.addProperty(d.getPropertyName());
+                try {
+                    return traversableResolver.isReachable(context.getValue(), p.removeLeafNode(), getRootBeanClass(),
+                        p, d.getElementType());
+                } catch (ValidationException ve) {
+                    throw ve;
+                } catch (Exception e) {
+                    throw new ValidationException(e);
+                }
+            });
+            return reachableProperties.flatMap(d -> d.read(realContext).filter(context -> !context.isRecursive())
+                .map(child -> propertyFrame(d, child))).collect(Collectors.toSet());
+        }
+    }
+
+    public class SproutFrame<D extends ElementD<?, ?> & CascadableDescriptor & ContainerDescriptor> extends Frame<D> {
+
+        public SproutFrame(D descriptor, GraphContext context) {
+            this(null, descriptor, context);
+        }
+
+        public SproutFrame(Frame<?> parent, D descriptor, GraphContext context) {
+            super(parent, descriptor, context);
+        }
+
+        @Override
+        void validateDescriptorConstraints(GroupStrategy groups, Consumer<ConstraintViolation<T>> sink) {
+            super.validateDescriptorConstraints(groups, sink);
+            if (context.getValue() != null) {
+                descriptor.getConstrainedContainerElementTypes().stream()
+                    .flatMap(d -> ComposedD.unwrap(d, ContainerElementTypeD.class)).forEach(d -> {
+                        if (constraintsFor(d, groups).findFirst().isPresent()
+                            || !d.getConstrainedContainerElementTypes().isEmpty()) {
+                            final ValueExtractor<?> declaredTypeValueExtractor =
+                                context.getValidatorContext().getValueExtractors().find(d.getKey());
+                            ExtractValues.extract(context, d.getKey(), declaredTypeValueExtractor).stream()
+                                .filter(e -> !e.isRecursive())
+                                .map(e -> new ContainerElementConstraintsFrame(this, d, e))
+                                .forEach(f -> f.validateDescriptorConstraints(groups, sink));
+                        }
+                    });
+            }
+        }
+
+        @Override
+        void recurse(GroupStrategy groups, Consumer<ConstraintViolation<T>> sink) {
+            if (context.getValue() == null || !DescriptorManager.isCascaded(descriptor)) {
+                return;
+            }
+            final Map<Group, GroupStrategy> conversions =
+                descriptor.getGroupConversions().stream().collect(Collectors.toMap(gc -> Group.of(gc.getFrom()),
+                    gc -> validatorContext.getGroupsComputer().computeGroups(gc.getTo()).asStrategy()));
+
+            GroupStrategy.redefining(groups, conversions).applyTo(noViolations(gs -> cascade(gs, sink)));
+        }
+
+        private void cascade(GroupStrategy groups, Consumer<ConstraintViolation<T>> sink) {
+            descriptor.getConstrainedContainerElementTypes().stream()
+                .filter(d -> d.isCascaded() || !d.getConstrainedContainerElementTypes().isEmpty())
+                .flatMap(d -> ComposedD.unwrap(d, ContainerElementTypeD.class)).forEach(d -> {
+                    final ValueExtractor<?> runtimeTypeValueExtractor =
+                        context.getValidatorContext().getValueExtractors().find(context.runtimeKey(d.getKey()));
+                    ExtractValues.extract(context, d.getKey(), runtimeTypeValueExtractor).stream()
+                        .filter(e -> !e.isRecursive()).map(e -> new ContainerElementCascadeFrame(this, d, e))
+                        .forEach(f -> f.recurse(groups, sink));
+                });
+            if (!descriptor.isCascaded()) {
+                return;
+            }
+            if (descriptor instanceof PropertyDescriptor) {
+                final TraversableResolver traversableResolver = validatorContext.getTraversableResolver();
+
+                final Object traversableObject =
+                    Optional.ofNullable(context.getParent()).map(GraphContext::getValue).orElse(null);
+
+                final PathImpl pathToTraversableObject = context.getPath();
+                final NodeImpl traversableProperty = pathToTraversableObject.removeLeafNode();
+
+                try {
+                    if (!traversableResolver.isCascadable(traversableObject, traversableProperty, getRootBeanClass(),
+                        pathToTraversableObject, ((PropertyD<?>) descriptor).getElementType())) {
+                        return;
+                    }
+                } catch (ValidationException ve) {
+                    throw ve;
+                } catch (Exception e) {
+                    throw new ValidationException(e);
+                }
+            }
+            multiplex().filter(context -> context.getValue() != null && !context.isRecursive())
+                .map(context -> new BeanFrame<>(this, context)).forEach(b -> b.process(groups, sink));
+        }
+
+        protected GraphContext getMultiplexContext() {
+            return context;
+        }
+
+        private Stream<GraphContext> multiplex() {
+            final GraphContext multiplexContext = getMultiplexContext();
+            final Object value = multiplexContext.getValue();
+            if (value == null) {
+                return Stream.empty();
+            }
+            if (value.getClass().isArray()) {
+                // inconsistent: use Object[] here but specific type for Iterable? RI compatibility
+                final Class<?> arrayType = value instanceof Object[] ? Object[].class : value.getClass();
+                return IntStream.range(0, Array.getLength(value)).mapToObj(
+                    i -> multiplexContext.child(NodeImpl.atIndex(i).inContainer(arrayType, null), Array.get(value, i)));
+            }
+            if (Map.class.isInstance(value)) {
+                return ((Map<?, ?>) value).entrySet().stream()
+                    .map(e -> multiplexContext.child(
+                        setContainerInformation(NodeImpl.atKey(e.getKey()), MAP_VALUE, descriptor.getElementClass()),
+                        e.getValue()));
+            }
+            if (List.class.isInstance(value)) {
+                final List<?> l = (List<?>) value;
+                return IntStream.range(0, l.size())
+                    .mapToObj(i -> multiplexContext.child(
+                        setContainerInformation(NodeImpl.atIndex(i), ITERABLE_ELEMENT, descriptor.getElementClass()),
+                        l.get(i)));
+            }
+            if (Iterable.class.isInstance(value)) {
+                final Stream.Builder<Object> b = Stream.builder();
+                ((Iterable<?>) value).forEach(b);
+                return b.build()
+                    .map(o -> multiplexContext.child(
+                        setContainerInformation(NodeImpl.atIndex(null), ITERABLE_ELEMENT, descriptor.getElementClass()),
+                        o));
+            }
+            return Stream.of(multiplexContext);
+        }
+
+        // RI apparently wants to use e.g. Set for Iterable containers, so use declared type + assigned type
+        // variable if present. not sure I agree, FWIW
+        private NodeImpl setContainerInformation(NodeImpl node, TypeVariable<?> originalTypeVariable,
+            Class<?> containerType) {
+            final TypeVariable<?> tv;
+            if (containerType.equals(originalTypeVariable.getGenericDeclaration())) {
+                tv = originalTypeVariable;
+            } else {
+                final Type assignedType =
+                    TypeUtils.getTypeArguments(containerType, (Class<?>) originalTypeVariable.getGenericDeclaration())
+                        .get(originalTypeVariable);
+
+                tv = assignedType instanceof TypeVariable<?> ? (TypeVariable<?>) assignedType : null;
+            }
+            final int i = tv == null ? -1 : ObjectUtils.indexOf(containerType.getTypeParameters(), tv);
+            return node.inContainer(containerType, i < 0 ? null : Integer.valueOf(i));
+        }
+
+        @Override
+        Object getBean() {
+            return Optional.ofNullable(parent).map(Frame::getBean).orElse(null);
+        }
+    }
+
+    private class ContainerElementConstraintsFrame extends SproutFrame<ContainerElementTypeD> {
+
+        ContainerElementConstraintsFrame(ValidationJob<T>.Frame<?> parent, ContainerElementTypeD descriptor,
+            GraphContext context) {
+            super(parent, descriptor, context);
+        }
+
+        @Override
+        void recurse(GroupStrategy groups, Consumer<ConstraintViolation<T>> sink) {
+        }
+    }
+
+    private class ContainerElementCascadeFrame extends SproutFrame<ContainerElementTypeD> {
+
+        ContainerElementCascadeFrame(ValidationJob<T>.Frame<?> parent, ContainerElementTypeD descriptor,
+            GraphContext context) {
+            super(parent, descriptor, context);
+        }
+
+        @Override
+        void validateDescriptorConstraints(GroupStrategy groups, Consumer<ConstraintViolation<T>> sink) {
+        }
+
+        @Override
+        protected GraphContext getMultiplexContext() {
+            final PathImpl path = context.getPath();
+
+            GraphContext ancestor = context.getParent();
+            Validate.validState(ancestor != null, "Expected parent context");
+
+            final NodeImpl leafNode = path.getLeafNode();
+
+            final NodeImpl newLeaf;
+
+            if (leafNode.getKind() == ElementKind.CONTAINER_ELEMENT) {
+                // recurse using elided path:
+                path.removeLeafNode();
+
+                while (!path.equals(ancestor.getPath())) {
+                    ancestor = ancestor.getParent();
+                    Validate.validState(ancestor != null, "Expected parent context");
+                }
+                newLeaf = new NodeImpl.PropertyNodeImpl(leafNode);
+                newLeaf.setName(null);
+            } else {
+                final ContainerElementKey key = descriptor.getKey();
+                newLeaf = new NodeImpl.PropertyNodeImpl((String) null).inContainer(key.getContainerClass(),
+                    key.getTypeArgumentIndex());
+            }
+            path.addNode(newLeaf);
+
+            return ancestor.child(path, context.getValue());
+        }
+    }
+
+    private class UnwrappedElementConstraintValidationPseudoFrame<D extends ElementD<?, ?>> extends Frame<D> {
+        final Lazy<IllegalStateException> exc = new Lazy<>(() -> Exceptions.create(IllegalStateException::new,
+            "%s is not meant to participate in validation lifecycle", getClass()));
+
+        UnwrappedElementConstraintValidationPseudoFrame(ValidationJob<T>.Frame<D> parent, GraphContext context) {
+            super(parent, parent.descriptor, context);
+        }
+
+        @Override
+        void validateDescriptorConstraints(GroupStrategy groups, Consumer<ConstraintViolation<T>> sink) {
+            throw exc.get();
+        }
+
+        @Override
+        void recurse(GroupStrategy groups, Consumer<ConstraintViolation<T>> sink) {
+            throw exc.get();
+        }
+
+        @Override
+        Object getBean() {
+            return parent.getBean();
+        }
+    }
+
+    protected static final TypeVariable<?> MAP_VALUE = Map.class.getTypeParameters()[1];
+    protected static final TypeVariable<?> ITERABLE_ELEMENT = Iterable.class.getTypeParameters()[0];
+
+    private static Stream<ConstraintD<?>> constraintsFor(ElementD<?, ?> descriptor, GroupStrategy groups) {
+        return descriptor.getConstraintDescriptors().stream().<ConstraintD<?>> map(ConstraintD.class::cast)
+            .filter(c -> {
+                final Set<Class<?>> constraintGroups = c.getGroups();
+                return groups.getGroups().stream().map(Group::getGroup).anyMatch(g -> constraintGroups.contains(g)
+                    || constraintGroups.contains(Default.class) && c.getDeclaringClass().equals(g));
+            });
+    }
+
+    protected final ApacheFactoryContext validatorContext;
+    protected final Groups groups;
+
+    private final Lazy<Set<ConstraintViolation<T>>> results = new Lazy<>(LinkedHashSet::new);
+
+    private ConcurrentMap<ConstraintD<?>, ConcurrentMap<Path, Set<Object>>> completedValidations;
+
+    ValidationJob(ApacheFactoryContext validatorContext, Class<?>[] groups) {
+        super();
+        this.validatorContext = Validate.notNull(validatorContext, "validatorContext");
+        this.groups = validatorContext.getGroupsComputer().computeGroups(groups);
+    }
+
+    public final Set<ConstraintViolation<T>> getResults() {
+        if (results.optional().isPresent()) {
+            return results.get();
+        }
+        if (hasWork()) {
+            final Frame<?> baseFrame = computeBaseFrame();
+            Validate.validState(baseFrame != null, "%s computed null baseFrame", getClass().getName());
+
+            final Consumer<ConstraintViolation<T>> sink = results.consumer(Set::add);
+
+            completedValidations = new ConcurrentHashMap<>();
+
+            try {
+                baseFrame.process(groups.asStrategy(), sink);
+            } finally {
+                completedValidations = null;
+            }
+            if (results.optional().isPresent()) {
+                return Collections.unmodifiableSet(results.get());
+            }
+        }
+        return results.reset(Collections::emptySet).get();
+    }
+
+    @SuppressWarnings("unchecked")
+    private <O> BeanD<O> getBeanDescriptor(Object bean) {
+        final Class<? extends Object> t = Proxies.classFor(Validate.notNull(bean, "bean").getClass());
+        return (BeanD<O>) validatorContext.getDescriptorManager().getBeanDescriptor(t);
+    }
+
+    final ConstraintViolationImpl<T> createViolation(String messageTemplate, ConstraintValidatorContextImpl<T> context,
+        PathImpl propertyPath) {
+        if (!propertyPath.isRootPath()) {
+            final NodeImpl leafNode = propertyPath.getLeafNode();
+            if (leafNode.getName() == null && !(leafNode.getKind() == ElementKind.BEAN || leafNode.isInIterable())) {
+                propertyPath.removeLeafNode();
+            }
+        }
+        return createViolation(messageTemplate, interpolate(messageTemplate, context), context, propertyPath);
+    }
+
+    abstract ConstraintViolationImpl<T> createViolation(String messageTemplate, String message,
+        ConstraintValidatorContextImpl<T> context, PathImpl propertyPath);
+
+    protected abstract Frame<?> computeBaseFrame();
+
+    protected abstract Class<T> getRootBeanClass();
+
+    protected boolean hasWork() {
+        return true;
+    }
+
+    protected <U> Predicate<U> noViolations(Consumer<? super U> consumer) {
+        return u -> {
+            final int originalCount = violationCount();
+            consumer.accept(u);
+            return violationCount() == originalCount;
+        };
+    }
+
+    private int violationCount() {
+        final Optional<Set<ConstraintViolation<T>>> maybeResults = results.optional();
+        return maybeResults.isPresent() ? maybeResults.get().size() : 0;
+    }
+
+    private final String interpolate(String messageTemplate, MessageInterpolator.Context context) {
+        try {
+            return validatorContext.getMessageInterpolator().interpolate(messageTemplate, context);
+        } catch (ValidationException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new ValidationException(e);
+        }
+    }
+}

Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJobFactory.java
URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJobFactory.java?rev=1843674&view=auto
==============================================================================
--- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJobFactory.java (added)
+++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJobFactory.java Fri Oct 12 15:00:48 2018
@@ -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.job;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+import javax.validation.ValidationException;
+import javax.validation.Validator;
+import javax.validation.executable.ExecutableValidator;
+
+import org.apache.bval.jsr.ApacheFactoryContext;
+import org.apache.bval.util.Validate;
+
+/**
+ * Creates {@link ValidationJob} instances.
+ */
+public class ValidationJobFactory {
+
+    private final ApacheFactoryContext validatorContext;
+
+    /**
+     * Create a new {@link ValidationJobFactory}.
+     * 
+     * @param validatorContext
+     */
+    public ValidationJobFactory(ApacheFactoryContext validatorContext) {
+        super();
+        this.validatorContext = Validate.notNull(validatorContext, "validatorContext");
+    }
+
+    /**
+     * @see Validator#validate(Object, Class...)
+     */
+    public <T> ValidateBean<T> validateBean(T bean, Class<?>... groups) {
+        return new ValidateBean<>(validatorContext, bean, groups);
+    }
+
+    /**
+     * @see Validator#validateProperty(Object, String, Class...)
+     */
+    public <T> ValidateProperty<T> validateProperty(T bean, String property, Class<?>... groups) {
+        try {
+            @SuppressWarnings({ "unchecked", "rawtypes" })
+            final ValidateProperty<T> result = new ValidateProperty(validatorContext, bean, property, groups);
+            return result;
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new ValidationException(e);
+        }
+    }
+
+    /**
+     * @see Validator#validateValue(Class, String, Object, Class...)
+     */
+    public <T> ValidateProperty<T> validateValue(Class<T> rootBeanClass, String property, Object value,
+        Class<?>... groups) {
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        final ValidateProperty<T> result =
+            new ValidateProperty(validatorContext, rootBeanClass, property, value, groups);
+        return result;
+    }
+
+    /**
+     * @see ExecutableValidator#validateParameters(Object, Method, Object[], Class...)
+     */
+    public <T> ValidateParameters.ForMethod<T> validateParameters(T object, Method method, Object[] parameterValues,
+        Class<?>... groups) {
+        return new ValidateParameters.ForMethod<T>(validatorContext, object, method, parameterValues, groups);
+    }
+
+    /**
+     * @see ExecutableValidator#validateReturnValue(Object, Method, Object, Class...)
+     */
+    public <T> ValidateReturnValue.ForMethod<T> validateReturnValue(T object, Method method, Object returnValue,
+        Class<?>... groups) {
+        return new ValidateReturnValue.ForMethod<>(validatorContext, object, method, returnValue, groups);
+    }
+
+    /**
+     * @see ExecutableValidator#validateConstructorParameters(Constructor, Object[], Class...)
+     */
+    public <T> ValidateParameters.ForConstructor<T> validateConstructorParameters(Constructor<? extends T> constructor,
+        Object[] parameterValues, Class<?>... groups) {
+        return new ValidateParameters.ForConstructor<T>(validatorContext, constructor, parameterValues, groups);
+    }
+
+    /**
+     * @see ExecutableValidator#validateConstructorReturnValue(Constructor, Object, Class...)
+     */
+    public <T> ValidateReturnValue.ForConstructor<T> validateConstructorReturnValue(
+        Constructor<? extends T> constructor, T createdObject, Class<?>... groups) {
+        return new ValidateReturnValue.ForConstructor<T>(validatorContext, constructor, createdObject, groups);
+    }
+}

Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationBehavior.java
URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationBehavior.java?rev=1843674&view=auto
==============================================================================
--- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationBehavior.java (added)
+++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationBehavior.java Fri Oct 12 15:00:48 2018
@@ -0,0 +1,35 @@
+/*
+ *  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.metadata;
+
+import org.apache.bval.jsr.metadata.MetadataBuilder;
+
+/**
+ * Models the behavior of a {@link MetadataBuilder} with regard to bean validation annotations.
+ * 
+ * @see DualBuilder
+ */
+public enum AnnotationBehavior implements AnnotationBehaviorMergeStrategy {
+    //@formatter:off
+    INCLUDE, EXCLUDE, ABSTAIN;
+    //@formatter:on
+
+    @Override
+    public AnnotationBehavior apply(Iterable<? extends HasAnnotationBehavior> t) {
+        return this;
+    }
+}

Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationBehaviorMergeStrategy.java
URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationBehaviorMergeStrategy.java?rev=1843674&view=auto
==============================================================================
--- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationBehaviorMergeStrategy.java (added)
+++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationBehaviorMergeStrategy.java Fri Oct 12 15:00:48 2018
@@ -0,0 +1,54 @@
+/*
+ *  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.metadata;
+
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.bval.util.Validate;
+
+@FunctionalInterface
+public interface AnnotationBehaviorMergeStrategy
+    extends Function<Iterable<? extends HasAnnotationBehavior>, AnnotationBehavior> {
+
+    public static AnnotationBehaviorMergeStrategy first() {
+        return coll -> {
+            final Iterator<? extends HasAnnotationBehavior> iterator = coll.iterator();
+            return iterator.hasNext() ? iterator.next().getAnnotationBehavior() : AnnotationBehavior.ABSTAIN;
+        };
+    }
+
+    public static AnnotationBehaviorMergeStrategy consensus() {
+        return coll -> {
+            final Stream.Builder<HasAnnotationBehavior> b = Stream.builder();
+            coll.forEach(b);
+            final Set<AnnotationBehavior> annotationBehaviors =
+                b.build().map(HasAnnotationBehavior::getAnnotationBehavior).filter(Objects::nonNull)
+                    .filter(Predicate.isEqual(AnnotationBehavior.ABSTAIN).negate())
+                    .collect(Collectors.toCollection(() -> EnumSet.noneOf(AnnotationBehavior.class)));
+            Validate.validState(annotationBehaviors.size() <= 1,
+                "Conflicting annotation inclusion behaviors found among %s", coll);
+            return annotationBehaviors.isEmpty() ? AnnotationBehavior.ABSTAIN : annotationBehaviors.iterator().next();
+        };
+    }
+}

Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationDeclaredValidatorMappingProvider.java
URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationDeclaredValidatorMappingProvider.java?rev=1843674&view=auto
==============================================================================
--- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationDeclaredValidatorMappingProvider.java (added)
+++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationDeclaredValidatorMappingProvider.java Fri Oct 12 15:00:48 2018
@@ -0,0 +1,42 @@
+/*
+ *  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.metadata;
+
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.validation.Constraint;
+import javax.validation.ConstraintValidator;
+
+import org.apache.bval.util.Validate;
+
+public class AnnotationDeclaredValidatorMappingProvider extends ValidatorMappingProvider {
+    public static final AnnotationDeclaredValidatorMappingProvider INSTANCE =
+        new AnnotationDeclaredValidatorMappingProvider();
+
+    @Override
+    protected <A extends Annotation> ValidatorMapping<A> doGetValidatorMapping(Class<A> constraintType) {
+        Validate.notNull(constraintType);
+        Validate.isTrue(constraintType.isAnnotationPresent(Constraint.class),
+            "%s does not represent a validation constraint", constraintType);
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        final List<Class<? extends ConstraintValidator<A, ?>>> validatorTypes =
+            (List) Arrays.asList(constraintType.getAnnotation(Constraint.class).validatedBy());
+        return new ValidatorMapping<>("@Constraint.validatedBy()", validatorTypes);
+    }
+}

Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ClassLoadingValidatorMappingProvider.java
URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ClassLoadingValidatorMappingProvider.java?rev=1843674&view=auto
==============================================================================
--- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ClassLoadingValidatorMappingProvider.java (added)
+++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ClassLoadingValidatorMappingProvider.java Fri Oct 12 15:00:48 2018
@@ -0,0 +1,48 @@
+/*
+ * 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.metadata;
+
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+import org.apache.bval.util.reflection.Reflection;
+import org.apache.commons.weaver.privilizer.Privilizing;
+import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
+
+@Privilizing(@CallTo(Reflection.class))
+public abstract class ClassLoadingValidatorMappingProvider extends ValidatorMappingProvider {
+
+    protected final <T> Stream<Class<? extends T>> load(Stream<String> classNames, Class<T> assignableTo,
+        Consumer<? super ClassNotFoundException> handleException) {
+        return classNames.map(className -> {
+            try {
+                return Reflection.toClass(className, getClassLoader());
+            } catch (ClassNotFoundException e) {
+                handleException.accept(e);
+                return (Class<?>) null;
+            }
+        }).filter(Objects::nonNull).map(c -> (Class<? extends T>) c.asSubclass(assignableTo));
+    }
+
+    protected ClassLoader getClassLoader() {
+        final ClassLoader classloader = Thread.currentThread().getContextClassLoader();
+        return classloader == null ? getClass().getClassLoader() : classloader;
+    }
+}