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 [10/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/...

Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/CompositeBuilder.java
URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/CompositeBuilder.java?rev=1843674&view=auto
==============================================================================
--- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/CompositeBuilder.java (added)
+++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/CompositeBuilder.java Fri Oct 12 15:00:48 2018
@@ -0,0 +1,296 @@
+/*
+ *  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.lang.reflect.AnnotatedElement;
+import java.lang.reflect.AnnotatedType;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import javax.validation.ElementKind;
+import javax.validation.ParameterNameProvider;
+
+import org.apache.bval.jsr.ApacheValidatorFactory;
+import org.apache.bval.jsr.groups.GroupConversion;
+import org.apache.bval.jsr.util.Methods;
+import org.apache.bval.jsr.util.ToUnmodifiable;
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.Reflection;
+
+public class CompositeBuilder {
+
+    class Delegator<DELEGATE extends HasAnnotationBehavior> implements HasAnnotationBehavior {
+
+        protected final List<DELEGATE> delegates;
+
+        Delegator(List<DELEGATE> delegates) {
+            this.delegates = Validate.notNull(delegates, "delegates");
+            Validate.isTrue(!delegates.isEmpty(), "no delegates specified");
+            Validate.isTrue(delegates.stream().noneMatch(Objects::isNull), "One or more supplied delegates was null");
+        }
+
+        @Override
+        public AnnotationBehavior getAnnotationBehavior() {
+            return annotationBehaviorStrategy.apply(delegates);
+        }
+
+        <K, D> Map<K, D> merge(Function<DELEGATE, Map<K, D>> toMap, Function<List<D>, D> merge) {
+            return merge(toMap, (k, l) -> merge.apply(l));
+        }
+
+        <K, D> Map<K, D> merge(Function<DELEGATE, Map<K, D>> toMap, BiFunction<K, List<D>, D> merge) {
+            final List<Map<K, D>> maps =
+                delegates.stream().map(toMap).filter(m -> !m.isEmpty()).collect(Collectors.toList());
+
+            final Function<? super K, ? extends D> valueMapper = k -> {
+                final List<D> mappedDelegates =
+                    maps.stream().map(m -> m.get(k)).filter(Objects::nonNull).collect(Collectors.toList());
+                return mappedDelegates.size() == 1 ? mappedDelegates.get(0) : merge.apply(k, mappedDelegates);
+            };
+            return maps.stream().map(Map::keySet).flatMap(Collection::stream).distinct()
+                .collect(Collectors.toMap(Function.identity(), valueMapper));
+        }
+    }
+
+    class ForBean<T> extends CompositeBuilder.Delegator<MetadataBuilder.ForBean<T>>
+        implements MetadataBuilder.ForBean<T> {
+
+        ForBean(List<MetadataBuilder.ForBean<T>> delegates) {
+            super(delegates);
+        }
+
+        @Override
+        public MetadataBuilder.ForClass<T> getClass(Meta<Class<T>> meta) {
+            return new CompositeBuilder.ForClass<>(
+                delegates.stream().map(d -> d.getClass(meta)).collect(Collectors.toList()));
+        }
+
+        @Override
+        public Map<String, MetadataBuilder.ForContainer<Field>> getFields(Meta<Class<T>> meta) {
+            return merge(b -> b.getFields(meta), (f, l) -> {
+                final Field fld = Reflection.find(meta.getHost(), t -> Reflection.getDeclaredField(t, f));
+                if (fld == null) {
+                    Exceptions.raise(IllegalStateException::new, "Could not find field %s of %s", f, meta.getHost());
+                }
+                return forContainer(l, new Meta.ForField(fld), ElementKind.PROPERTY);
+            });
+        }
+
+        @Override
+        public Map<String, MetadataBuilder.ForContainer<Method>> getGetters(Meta<Class<T>> meta) {
+            return merge(b -> b.getGetters(meta), (g, l) -> {
+                final Method getter = Methods.getter(meta.getHost(), g);
+                if (getter == null) {
+                    Exceptions.raise(IllegalStateException::new, "Could not find getter for property %s of %s", g,
+                        meta.getHost());
+                }
+                return forContainer(l, new Meta.ForMethod(getter), ElementKind.PROPERTY);
+            });
+        }
+
+        @Override
+        public Map<Signature, MetadataBuilder.ForExecutable<Constructor<? extends T>>> getConstructors(Meta<Class<T>> meta) {
+            return merge(b -> b.getConstructors(meta),
+                d -> new CompositeBuilder.ForExecutable<>(d, ParameterNameProvider::getParameterNames));
+        }
+
+        @Override
+        public Map<Signature, MetadataBuilder.ForExecutable<Method>> getMethods(Meta<Class<T>> meta) {
+            return merge(b -> b.getMethods(meta),
+                d -> new CompositeBuilder.ForExecutable<>(d, ParameterNameProvider::getParameterNames));
+        }
+    }
+
+    class ForElement<DELEGATE extends MetadataBuilder.ForElement<E>, E extends AnnotatedElement>
+        extends Delegator<DELEGATE> implements MetadataBuilder.ForElement<E> {
+
+        ForElement(List<DELEGATE> delegates) {
+            super(delegates);
+        }
+
+        @Override
+        public Map<Meta<E>, Annotation[]> getConstraintDeclarationMap(Meta<E> meta) {
+            return CompositeBuilder.this.getConstraintDeclarationMap(this, meta);
+        }
+
+        @Override
+        public final Annotation[] getDeclaredConstraints(Meta<E> meta) {
+            return delegates.stream().map(d -> d.getDeclaredConstraints(meta)).flatMap(Stream::of)
+                .toArray(Annotation[]::new);
+        }
+    }
+
+    class ForClass<T> extends ForElement<MetadataBuilder.ForClass<T>, Class<T>> implements MetadataBuilder.ForClass<T> {
+
+        ForClass(List<MetadataBuilder.ForClass<T>> delegates) {
+            super(delegates);
+        }
+
+        @Override
+        public List<Class<?>> getGroupSequence(Meta<Class<T>> meta) {
+            return CompositeBuilder.this.getGroupSequence(this, meta);
+        }
+    }
+
+    class ForContainer<DELEGATE extends MetadataBuilder.ForContainer<E>, E extends AnnotatedElement>
+        extends CompositeBuilder.ForElement<DELEGATE, E> implements MetadataBuilder.ForContainer<E> {
+
+        ForContainer(List<DELEGATE> delegates) {
+            super(delegates);
+        }
+
+        @Override
+        public boolean isCascade(Meta<E> meta) {
+            return delegates.stream().anyMatch(d -> d.isCascade(meta));
+        }
+
+        @Override
+        public Set<GroupConversion> getGroupConversions(Meta<E> meta) {
+            return delegates.stream().map(d -> d.getGroupConversions(meta)).flatMap(Collection::stream)
+                .collect(ToUnmodifiable.set());
+        }
+
+        @Override
+        public Map<ContainerElementKey, MetadataBuilder.ForContainer<AnnotatedType>> getContainerElementTypes(
+            Meta<E> meta) {
+            return merge(b -> b.getContainerElementTypes(meta),
+                (k, l) -> forContainer(l, new Meta.ForContainerElement(meta, k), ElementKind.CONTAINER_ELEMENT));
+        }
+    }
+
+    class ForExecutable<DELEGATE extends MetadataBuilder.ForExecutable<E>, E extends Executable>
+        extends Delegator<DELEGATE> implements MetadataBuilder.ForExecutable<E> {
+
+        private final BiFunction<ParameterNameProvider, E, List<String>> getParameterNames;
+
+        ForExecutable(List<DELEGATE> delegates, BiFunction<ParameterNameProvider, E, List<String>> getParameterNames) {
+            super(delegates);
+            this.getParameterNames = Validate.notNull(getParameterNames, "getParameterNames");
+        }
+
+        @Override
+        public MetadataBuilder.ForContainer<E> getReturnValue(Meta<E> meta) {
+            return CompositeBuilder.this.forContainer(
+                delegates.stream().map(d -> d.getReturnValue(meta)).collect(Collectors.toList()), meta,
+                ElementKind.RETURN_VALUE);
+        }
+
+        @Override
+        public List<MetadataBuilder.ForContainer<Parameter>> getParameters(Meta<E> meta) {
+            final List<List<MetadataBuilder.ForContainer<Parameter>>> parameterLists =
+                delegates.stream().map(d -> d.getParameters(meta)).collect(Collectors.toList());
+
+            final Set<Integer> parameterCounts = parameterLists.stream().map(List::size).collect(Collectors.toSet());
+            Validate.validState(parameterCounts.size() == 1, "Mismatched parameter counts: %s", parameterCounts);
+
+            final int parameterCount = parameterCounts.iterator().next().intValue();
+            final List<Meta<Parameter>> metaParams = getMetaParameters(meta, getParameterNames);
+            return IntStream.range(0, parameterCount).mapToObj(n -> {
+                return forContainer(parameterLists.stream().map(l -> l.get(n)).collect(Collectors.toList()),
+                    metaParams.get(n), ElementKind.PARAMETER);
+            }).collect(ToUnmodifiable.list());
+        }
+
+        @Override
+        public MetadataBuilder.ForElement<E> getCrossParameter(Meta<E> meta) {
+            return forCrossParameter(
+                delegates.stream().map(d -> d.getCrossParameter(meta)).collect(Collectors.toList()), meta);
+        }
+    }
+
+    public static CompositeBuilder with(ApacheValidatorFactory validatorFactory,
+        AnnotationBehaviorMergeStrategy annotationBehaviorStrategy) {
+        return new CompositeBuilder(validatorFactory, annotationBehaviorStrategy);
+    }
+
+    private final AnnotationBehaviorMergeStrategy annotationBehaviorStrategy;
+    protected final ApacheValidatorFactory validatorFactory;
+
+    protected CompositeBuilder(ApacheValidatorFactory validatorFactory,
+        AnnotationBehaviorMergeStrategy annotationBehaviorMergeStrategy) {
+        super();
+        this.annotationBehaviorStrategy =
+            Validate.notNull(annotationBehaviorMergeStrategy, "annotationBehaviorMergeStrategy");
+        this.validatorFactory = Validate.notNull(validatorFactory, "validatorFactory");
+    }
+
+    public <T> Collector<MetadataBuilder.ForBean<T>, ?, MetadataBuilder.ForBean<T>> compose() {
+        return Collectors.collectingAndThen(Collectors.toList(),
+            delegates -> delegates.isEmpty() ? EmptyBuilder.instance().forBean()
+                : delegates.size() == 1 ? delegates.get(0) : new CompositeBuilder.ForBean<>(delegates));
+    }
+
+    public <E extends AnnotatedElement> Collector<MetadataBuilder.ForContainer<E>, ?, MetadataBuilder.ForContainer<E>> composeContainer() {
+        return Collectors.collectingAndThen(Collectors.toList(),
+            delegates -> delegates.isEmpty() ? EmptyBuilder.instance().forContainer()
+                : delegates.size() == 1 ? delegates.get(0) : new CompositeBuilder.ForContainer<>(delegates));
+    }
+
+    protected final <E extends Executable> List<Meta<Parameter>> getMetaParameters(Meta<E> meta,
+        BiFunction<ParameterNameProvider, E, List<String>> getParameterNames) {
+        final Parameter[] parameters = meta.getHost().getParameters();
+        final List<String> parameterNames =
+            getParameterNames.apply(validatorFactory.getParameterNameProvider(), meta.getHost());
+
+        if (parameterNames.size() != parameters.length) {
+            Exceptions.raise(IllegalStateException::new, "%s returned wrong number of parameter names",
+                validatorFactory.getParameterNameProvider());
+        }
+        return IntStream.range(0, parameters.length)
+            .mapToObj(n -> new Meta.ForParameter(parameters[n], parameterNames.get(n))).collect(Collectors.toList());
+    }
+
+    protected <E extends AnnotatedElement> Map<Meta<E>, Annotation[]> getConstraintDeclarationMap(
+        CompositeBuilder.ForElement<? extends MetadataBuilder.ForElement<E>, E> composite, Meta<E> meta) {
+        return Collections.singletonMap(meta, composite.getDeclaredConstraints(meta));
+    }
+
+    protected <T> List<Class<?>> getGroupSequence(CompositeBuilder.ForClass<T> composite, Meta<Class<T>> meta) {
+        final List<List<Class<?>>> groupSequence =
+            composite.delegates.stream().map(d -> d.getGroupSequence(meta)).collect(Collectors.toList());
+        Validate.validState(groupSequence.size() <= 1,
+            "group sequence returned from multiple composite class metadata builders");
+        return groupSequence.isEmpty() ? null : groupSequence.get(0);
+    }
+
+    protected <DELEGATE extends MetadataBuilder.ForContainer<E>, E extends AnnotatedElement> MetadataBuilder.ForContainer<E> forContainer(
+        List<DELEGATE> delegates, Meta<E> meta, ElementKind elementKind) {
+        return new CompositeBuilder.ForContainer<>(delegates);
+    }
+
+    protected <DELEGATE extends MetadataBuilder.ForElement<E>, E extends Executable> MetadataBuilder.ForElement<E> forCrossParameter(
+        List<DELEGATE> delegates, Meta<E> meta) {
+        return new CompositeBuilder.ForElement<>(delegates);
+    }
+}

Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/CompositeValidatorMappingProvider.java
URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/CompositeValidatorMappingProvider.java?rev=1843674&view=auto
==============================================================================
--- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/CompositeValidatorMappingProvider.java (added)
+++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/CompositeValidatorMappingProvider.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.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import org.apache.bval.util.Validate;
+
+public class CompositeValidatorMappingProvider extends ValidatorMappingProvider {
+
+    private final List<ValidatorMappingProvider> delegates;
+
+    public CompositeValidatorMappingProvider(List<ValidatorMappingProvider> delegates) {
+        super();
+        this.delegates = Validate.notNull(delegates, "delegates");
+        Validate.isTrue(!delegates.isEmpty(), "no delegates specified");
+        Validate.isTrue(delegates.stream().noneMatch(Objects::isNull), "One or more supplied delegates was null");
+    }
+
+    @Override
+    protected <A extends Annotation> ValidatorMapping<A> doGetValidatorMapping(Class<A> constraintType) {
+        return ValidatorMapping.merge(delegates.stream().map(d -> d.doGetValidatorMapping(constraintType))
+            .filter(Objects::nonNull).collect(Collectors.toList()), AnnotationBehaviorMergeStrategy.consensus());
+    }
+}

Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ContainerElementKey.java
URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ContainerElementKey.java?rev=1843674&view=auto
==============================================================================
--- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ContainerElementKey.java (added)
+++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ContainerElementKey.java Fri Oct 12 15:00:48 2018
@@ -0,0 +1,218 @@
+/*
+ *  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 static java.util.Comparator.comparing;
+import static java.util.Comparator.naturalOrder;
+import static java.util.Comparator.nullsFirst;
+
+import java.lang.reflect.AnnotatedParameterizedType;
+import java.lang.reflect.AnnotatedType;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.logging.Logger;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import javax.validation.valueextraction.ExtractedValue;
+import javax.validation.valueextraction.ValueExtractor;
+import javax.validation.valueextraction.ValueExtractorDefinitionException;
+
+import org.apache.bval.util.EmulatedAnnotatedType;
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.Lazy;
+import org.apache.bval.util.LazyInt;
+import org.apache.bval.util.ObjectUtils;
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.TypeUtils;
+
+public class ContainerElementKey implements Comparable<ContainerElementKey> {
+    public static final Comparator<ContainerElementKey> COMPARATOR =
+        nullsFirst(comparing(ContainerElementKey::containerClassName)
+            .thenComparing(ContainerElementKey::getTypeArgumentIndex, nullsFirst(naturalOrder())));
+
+    private static Logger log = Logger.getLogger(ContainerElementKey.class.getName());
+
+    public static ContainerElementKey forValueExtractor(ValueExtractor<?> extractor) {
+        @SuppressWarnings("rawtypes")
+        final Class<? extends ValueExtractor> extractorType = extractor.getClass();
+        final Lazy<Set<ContainerElementKey>> result = new Lazy<>(HashSet::new);
+
+        Stream.of(extractorType.getAnnotatedInterfaces()).filter(AnnotatedParameterizedType.class::isInstance)
+            .map(AnnotatedParameterizedType.class::cast)
+            .filter(apt -> ValueExtractor.class.equals(((ParameterizedType) apt.getType()).getRawType()))
+            .forEach(decl -> {
+                final AnnotatedType containerType = decl.getAnnotatedActualTypeArguments()[0];
+
+                if (containerType.isAnnotationPresent(ExtractedValue.class)) {
+                    final Class<?> extractedType = containerType.getAnnotation(ExtractedValue.class).type();
+                    if (void.class.equals(extractedType)) {
+                        Exceptions.raise(ValueExtractorDefinitionException::new, "%s does not specify %s type for %s",
+                            extractorType, ExtractedValue.class.getSimpleName(), containerType);
+                    }
+                    result.get().add(new ContainerElementKey(containerType, null) {
+                        public AnnotatedType getAnnotatedType() {
+                            return EmulatedAnnotatedType.wrap(extractedType);
+                        }
+                    });
+                }
+                Optional.of(containerType).filter(AnnotatedParameterizedType.class::isInstance)
+                    .map(AnnotatedParameterizedType.class::cast)
+                    .map(AnnotatedParameterizedType::getAnnotatedActualTypeArguments).ifPresent(args -> {
+                        IntStream.range(0, args.length).forEach(n -> {
+                            if (args[n].isAnnotationPresent(ExtractedValue.class)) {
+                                if (!void.class.equals(args[n].getAnnotation(ExtractedValue.class).type())) {
+                                    log.warning(String.format("Ignoring non-default %s type specified for %s by %s",
+                                        ExtractedValue.class.getSimpleName(), containerType.getType(), extractorType));
+                                }
+                                result.get().add(new ContainerElementKey(containerType, Integer.valueOf(n)));
+                            }
+                        });
+                    });
+            });
+        return result.optional().filter(s -> s.size() == 1)
+            .orElseThrow(() -> new ValueExtractorDefinitionException(extractorType.getName())).iterator().next();
+    }
+
+    public static ContainerElementKey forTypeVariable(TypeVariable<?> var) {
+        final Class<?> container = (Class<?>) var.getGenericDeclaration();
+        final int argIndex = ObjectUtils.indexOf(container.getTypeParameters(), var);
+        return new ContainerElementKey(container, Integer.valueOf(argIndex));
+    }
+
+    private static Integer validTypeArgumentIndex(Integer typeArgumentIndex, Class<?> containerClass) {
+        if (typeArgumentIndex != null) {
+            final int i = typeArgumentIndex.intValue();
+            Validate.isTrue(i >= 0 && i < containerClass.getTypeParameters().length,
+                "type argument index %d is invalid for container type %s", typeArgumentIndex, containerClass);
+        }
+        return typeArgumentIndex;
+    }
+
+    private final Integer typeArgumentIndex;
+    private final Class<?> containerClass;
+    private final LazyInt hashCode = new LazyInt(() -> Objects.hash(getContainerClass(), getTypeArgumentIndex()));
+    private final Lazy<String> toString = new Lazy<>(() -> String.format("%s: %s<[%d]>",
+        ContainerElementKey.class.getSimpleName(), getContainerClass().getName(), getTypeArgumentIndex()));
+    private final AnnotatedType annotatedType;
+
+    public ContainerElementKey(AnnotatedType containerType, Integer typeArgumentIndex) {
+        super();
+        Validate.notNull(containerType, "containerType");
+        this.containerClass = TypeUtils.getRawType(containerType.getType(), null);
+        this.typeArgumentIndex = validTypeArgumentIndex(typeArgumentIndex, containerClass);
+        this.annotatedType = typeArgumentIndex == null ? containerType : ((AnnotatedParameterizedType) containerType)
+            .getAnnotatedActualTypeArguments()[typeArgumentIndex.intValue()];
+    }
+
+    public ContainerElementKey(Class<?> containerClass, Integer typeArgumentIndex) {
+        Validate.notNull(containerClass, "containerClass");
+        this.containerClass = containerClass;
+        this.typeArgumentIndex = validTypeArgumentIndex(typeArgumentIndex, containerClass);
+        this.annotatedType = typeArgumentIndex == null ? null
+            : EmulatedAnnotatedType.wrap(containerClass.getTypeParameters()[typeArgumentIndex.intValue()]);
+    }
+
+    public Class<?> getContainerClass() {
+        return containerClass;
+    }
+
+    public Integer getTypeArgumentIndex() {
+        return typeArgumentIndex;
+    }
+
+    public AnnotatedType getAnnotatedType() {
+        return Optional.ofNullable(annotatedType).orElseThrow(UnsupportedOperationException::new);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        return obj == this || Optional.ofNullable(obj).filter(ContainerElementKey.class::isInstance)
+            .map(ContainerElementKey.class::cast).filter(cek -> Objects.equals(containerClass, cek.containerClass)
+                && Objects.equals(typeArgumentIndex, cek.typeArgumentIndex))
+            .isPresent();
+    }
+
+    @Override
+    public int hashCode() {
+        return hashCode.getAsInt();
+    }
+
+    @Override
+    public String toString() {
+        return toString.get();
+    }
+
+    @Override
+    public int compareTo(ContainerElementKey o) {
+        return COMPARATOR.compare(this, o);
+    }
+
+    public Set<ContainerElementKey> getAssignableKeys() {
+        final Lazy<Set<ContainerElementKey>> result = new Lazy<>(LinkedHashSet::new);
+        hierarchy(result.consumer(Set::add));
+        return result.optional().map(Collections::unmodifiableSet).orElseGet(Collections::emptySet);
+    }
+
+    public boolean represents(TypeVariable<?> var) {
+        return Stream.concat(Stream.of(this), getAssignableKeys().stream())
+            .anyMatch(cek -> cek.typeArgumentIndex != null
+                && cek.containerClass.getTypeParameters()[cek.typeArgumentIndex.intValue()].equals(var));
+    }
+
+    private void hierarchy(Consumer<ContainerElementKey> sink) {
+        final TypeVariable<?> var;
+        if (typeArgumentIndex == null) {
+            var = null;
+        } else {
+            var = containerClass.getTypeParameters()[typeArgumentIndex.intValue()];
+        }
+        final Lazy<Set<ContainerElementKey>> round = new Lazy<>(LinkedHashSet::new);
+        Stream
+            .concat(Stream.of(containerClass.getAnnotatedSuperclass()),
+                Stream.of(containerClass.getAnnotatedInterfaces()))
+            .filter(AnnotatedParameterizedType.class::isInstance).map(AnnotatedParameterizedType.class::cast)
+            .forEach(t -> {
+                final AnnotatedType[] args = ((AnnotatedParameterizedType) t).getAnnotatedActualTypeArguments();
+                for (int i = 0; i < args.length; i++) {
+                    final Type boundArgumentType = args[i].getType();
+                    if (boundArgumentType instanceof Class<?> || boundArgumentType.equals(var)) {
+                        round.get().add(new ContainerElementKey(t, Integer.valueOf(i)));
+                    }
+                }
+            });
+
+        round.optional().ifPresent(s -> {
+            s.forEach(sink);
+            // recurse:
+            s.forEach(k -> k.hierarchy(sink));
+        });
+    }
+
+    private String containerClassName() {
+        return getContainerClass().getName();
+    }
+}

Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/DualBuilder.java
URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/DualBuilder.java?rev=1843674&view=auto
==============================================================================
--- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/DualBuilder.java (added)
+++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/DualBuilder.java Fri Oct 12 15:00:48 2018
@@ -0,0 +1,367 @@
+/*
+ *  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.lang.reflect.AnnotatedElement;
+import java.lang.reflect.AnnotatedType;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import org.apache.bval.jsr.ApacheValidatorFactory;
+import org.apache.bval.jsr.groups.GroupConversion;
+import org.apache.bval.jsr.util.Methods;
+import org.apache.bval.jsr.util.ToUnmodifiable;
+import org.apache.bval.util.Validate;
+
+/**
+ * Maintains two metadata builds in parallel. The "primary" build is assumed to be the reflection/annotation-based build
+ * and is subject to the {@link AnnotationBehavior} prescribed by the "custom" build.
+ */
+public class DualBuilder {
+
+    private static class Delegator<DELEGATE extends HasAnnotationBehavior> implements HasAnnotationBehavior {
+
+        private final Delegator<?> parent;
+        protected final DELEGATE primaryDelegate;
+        protected final DELEGATE customDelegate;
+
+        Delegator(Delegator<?> parent, DELEGATE primaryDelegate, DELEGATE customDelegate) {
+            this.parent = parent;
+            this.primaryDelegate = Validate.notNull(primaryDelegate, "primaryDelegate");
+            this.customDelegate = Validate.notNull(customDelegate, "customDelegate");
+        }
+
+        AnnotationBehavior getCustomAnnotationBehavior() {
+            final AnnotationBehavior annotationBehavior = customDelegate.getAnnotationBehavior();
+            Validate.validState(annotationBehavior != null, "null %s returned from %s",
+                AnnotationBehavior.class.getSimpleName(), customDelegate);
+            if (annotationBehavior == AnnotationBehavior.ABSTAIN && parent != null) {
+                return parent.getCustomAnnotationBehavior();
+            }
+            return annotationBehavior;
+        }
+
+        protected Stream<DELEGATE> activeDelegates() {
+            return getCustomAnnotationBehavior() == AnnotationBehavior.EXCLUDE ? Stream.of(customDelegate)
+                : Stream.of(primaryDelegate, customDelegate);
+        }
+
+        <K, D> Map<K, D> merge(Function<DELEGATE, Map<K, D>> toMap, BiFunction<D, D, D> parallel,
+            Supplier<D> emptyBuilder) {
+
+            final Map<K, D> primaries = toMap.apply(primaryDelegate);
+            final Map<K, D> customs = toMap.apply(customDelegate);
+
+            if (primaries.isEmpty() && customs.isEmpty()) {
+                return Collections.emptyMap();
+            }
+
+            final Function<? super K, ? extends D> valueMapper = k -> {
+                final D primary = primaries.get(k);
+                final D custom = customs.get(k);
+
+                if (custom == null) {
+                    if (primary != null) {
+                        switch (getCustomAnnotationBehavior()) {
+                        case INCLUDE:
+                        case ABSTAIN:
+                            return primary;
+                        default:
+                            break;
+                        }
+                    }
+                    return emptyBuilder.get();
+                }
+                return parallel.apply(primary, custom);
+            };
+            return Stream.of(primaries, customs).map(Map::keySet).flatMap(Collection::stream).distinct()
+                .collect(Collectors.toMap(Function.identity(), valueMapper));
+        }
+    }
+
+    private static class ForBean<T> extends DualBuilder.Delegator<MetadataBuilder.ForBean<T>>
+        implements MetadataBuilder.ForBean<T> {
+
+        ForBean(MetadataBuilder.ForBean<T> primaryDelegate, MetadataBuilder.ForBean<T> customDelegate) {
+            super(null, primaryDelegate, customDelegate);
+        }
+
+        @Override
+        public MetadataBuilder.ForClass<T> getClass(Meta<Class<T>> meta) {
+            return new DualBuilder.ForClass<>(this, primaryDelegate.getClass(meta), customDelegate.getClass(meta));
+        }
+
+        @Override
+        public Map<String, MetadataBuilder.ForContainer<Field>> getFields(Meta<Class<T>> meta) {
+            return merge(b -> b.getFields(meta), (t, u) -> new DualBuilder.ForContainer<>(this, t, u),
+                EmptyBuilder.instance()::forContainer);
+        }
+
+        @Override
+        public Map<String, MetadataBuilder.ForContainer<Method>> getGetters(Meta<Class<T>> meta) {
+            return merge(b -> b.getGetters(meta), (t, u) -> new DualBuilder.ForContainer<>(this, t, u),
+                EmptyBuilder.instance()::forContainer);
+        }
+
+        @Override
+        public Map<Signature, MetadataBuilder.ForExecutable<Constructor<? extends T>>> getConstructors(Meta<Class<T>> meta) {
+            return merge(b -> b.getConstructors(meta), (t, u) -> new DualBuilder.ForExecutable<>(this, t, u),
+                EmptyBuilder.instance()::forExecutable);
+        }
+
+        @Override
+        public Map<Signature, MetadataBuilder.ForExecutable<Method>> getMethods(Meta<Class<T>> meta) {
+            return merge(b -> b.getMethods(meta), (t, u) -> new DualBuilder.ForExecutable<>(this, t, u),
+                EmptyBuilder.instance()::forExecutable);
+        }
+    }
+
+    private static class ForElement<DELEGATE extends MetadataBuilder.ForElement<E>, E extends AnnotatedElement>
+        extends Delegator<DELEGATE> implements MetadataBuilder.ForElement<E> {
+
+        ForElement(Delegator<?> parent, DELEGATE primaryDelegate, DELEGATE customDelegate) {
+            super(parent, primaryDelegate, customDelegate);
+        }
+
+        @Override
+        public final Annotation[] getDeclaredConstraints(Meta<E> meta) {
+            return activeDelegates().map(d -> d.getDeclaredConstraints(meta)).flatMap(Stream::of)
+                .toArray(Annotation[]::new);
+        }
+    }
+
+    private static class ForClass<T> extends ForElement<MetadataBuilder.ForClass<T>, Class<T>>
+        implements MetadataBuilder.ForClass<T> {
+
+        ForClass(Delegator<?> parent, MetadataBuilder.ForClass<T> primaryDelegate,
+            MetadataBuilder.ForClass<T> customDelegate) {
+            super(parent, primaryDelegate, customDelegate);
+        }
+
+        @Override
+        public List<Class<?>> getGroupSequence(Meta<Class<T>> meta) {
+            final List<Class<?>> customGroupSequence = customDelegate.getGroupSequence(meta);
+            if (customGroupSequence != null) {
+                return customGroupSequence;
+            }
+            return customDelegate.getAnnotationBehavior() == AnnotationBehavior.EXCLUDE ? null
+                : primaryDelegate.getGroupSequence(meta);
+        }
+    }
+
+    private static class ForContainer<DELEGATE extends MetadataBuilder.ForContainer<E>, E extends AnnotatedElement>
+        extends DualBuilder.ForElement<DELEGATE, E> implements MetadataBuilder.ForContainer<E> {
+
+        ForContainer(Delegator<?> parent, DELEGATE primaryDelegate, DELEGATE customDelegate) {
+            super(parent, primaryDelegate, customDelegate);
+        }
+
+        @Override
+        public final boolean isCascade(Meta<E> meta) {
+            return activeDelegates().anyMatch(d -> d.isCascade(meta));
+        }
+
+        @Override
+        public final Set<GroupConversion> getGroupConversions(Meta<E> meta) {
+            return activeDelegates().map(d -> d.getGroupConversions(meta)).flatMap(Collection::stream)
+                .collect(ToUnmodifiable.set());
+        }
+
+        @Override
+        public final Map<ContainerElementKey, MetadataBuilder.ForContainer<AnnotatedType>> getContainerElementTypes(
+            Meta<E> meta) {
+            return merge(b -> b.getContainerElementTypes(meta), (t, u) -> new DualBuilder.ForContainer<>(this, t, u),
+                EmptyBuilder.instance()::forContainer);
+        }
+    }
+
+    private static class ForExecutable<DELEGATE extends MetadataBuilder.ForExecutable<E>, E extends Executable>
+        extends Delegator<DELEGATE> implements MetadataBuilder.ForExecutable<E> {
+
+        ForExecutable(Delegator<?> parent, DELEGATE primaryDelegate, DELEGATE customDelegate) {
+            super(parent, primaryDelegate, customDelegate);
+        }
+
+        @Override
+        public MetadataBuilder.ForContainer<E> getReturnValue(Meta<E> meta) {
+            return new DualBuilder.ForContainer<>(this, primaryDelegate.getReturnValue(meta),
+                customDelegate.getReturnValue(meta));
+        }
+
+        @Override
+        public List<MetadataBuilder.ForContainer<Parameter>> getParameters(Meta<E> meta) {
+
+            final List<MetadataBuilder.ForContainer<Parameter>> primaries = primaryDelegate.getParameters(meta);
+            final List<MetadataBuilder.ForContainer<Parameter>> customs = customDelegate.getParameters(meta);
+
+            Validate.validState(primaries.size() == customs.size(), "Mismatched parameter counts: %d vs. %d",
+                primaries.size(), customs.size());
+
+            return IntStream.range(0, primaries.size())
+                .mapToObj(n -> new DualBuilder.ForContainer<>(this, primaries.get(n), customs.get(n)))
+                .collect(ToUnmodifiable.list());
+        }
+
+        @Override
+        public MetadataBuilder.ForElement<E> getCrossParameter(Meta<E> meta) {
+            return new DualBuilder.ForElement<MetadataBuilder.ForElement<E>, E>(this,
+                primaryDelegate.getCrossParameter(meta), customDelegate.getCrossParameter(meta));
+        }
+    }
+
+    private static class CustomWrapper {
+        private static class ForBean<T> implements MetadataBuilder.ForBean<T> {
+
+            private final MetadataBuilder.ForBean<T> wrapped;
+            private final Map<String, MetadataBuilder.ForContainer<Method>> getters;
+            private final Map<Signature, MetadataBuilder.ForExecutable<Method>> methods;
+
+            ForBean(MetadataBuilder.ForBean<T> wrapped, Map<String, MetadataBuilder.ForContainer<Method>> getters,
+                Map<Signature, MetadataBuilder.ForExecutable<Method>> methods) {
+                super();
+                this.wrapped = Validate.notNull(wrapped, "wrapped");
+                this.getters = Validate.notNull(getters, "getters");
+                this.methods = Validate.notNull(methods, "methods");
+            }
+
+            @Override
+            public AnnotationBehavior getAnnotationBehavior() {
+                return wrapped.getAnnotationBehavior();
+            }
+
+            @Override
+            public MetadataBuilder.ForClass<T> getClass(Meta<Class<T>> meta) {
+                return wrapped.getClass(meta);
+            }
+
+            @Override
+            public Map<String, MetadataBuilder.ForContainer<Field>> getFields(Meta<Class<T>> meta) {
+                return wrapped.getFields(meta);
+            }
+
+            @Override
+            public Map<String, MetadataBuilder.ForContainer<Method>> getGetters(Meta<Class<T>> meta) {
+                return getters;
+            }
+
+            @Override
+            public Map<Signature, MetadataBuilder.ForExecutable<Constructor<? extends T>>> getConstructors(
+                Meta<Class<T>> meta) {
+                return wrapped.getConstructors(meta);
+            }
+
+            @Override
+            public Map<Signature, MetadataBuilder.ForExecutable<Method>> getMethods(Meta<Class<T>> meta) {
+                return methods;
+            }
+        }
+
+        private static class ForGetterMethod implements MetadataBuilder.ForExecutable<Method> {
+            private final MetadataBuilder.ForContainer<Method> returnValue;
+
+            private ForGetterMethod(MetadataBuilder.ForContainer<Method> returnValue) {
+                super();
+                this.returnValue = Validate.notNull(returnValue, "returnValue");
+            }
+
+            @Override
+            public AnnotationBehavior getAnnotationBehavior() {
+                return returnValue.getAnnotationBehavior();
+            }
+
+            @Override
+            public MetadataBuilder.ForContainer<Method> getReturnValue(Meta<Method> meta) {
+                return returnValue;
+            }
+
+            @Override
+            public MetadataBuilder.ForElement<Method> getCrossParameter(Meta<Method> meta) {
+                return EmptyBuilder.instance().forElement();
+            }
+
+            @Override
+            public List<MetadataBuilder.ForContainer<Parameter>> getParameters(Meta<Method> meta) {
+                return Collections.emptyList();
+            }
+        }
+    }
+
+    public static <T> MetadataBuilder.ForBean<T> forBean(Class<T> beanClass, MetadataBuilder.ForBean<T> primaryDelegate,
+        MetadataBuilder.ForBean<T> customDelegate, ApacheValidatorFactory validatorFactory) {
+        return new DualBuilder.ForBean<>(primaryDelegate, wrapCustom(customDelegate, beanClass, validatorFactory));
+    }
+
+    private static <T> MetadataBuilder.ForBean<T> wrapCustom(MetadataBuilder.ForBean<T> customDelegate,
+        Class<T> beanClass, ApacheValidatorFactory validatorFactory) {
+        final Meta.ForClass<T> meta = new Meta.ForClass<>(beanClass);
+
+        final Map<String, MetadataBuilder.ForContainer<Method>> getters = customDelegate.getGetters(meta);
+        final Map<Signature, MetadataBuilder.ForExecutable<Method>> methods = customDelegate.getMethods(meta);
+
+        if (getters.isEmpty() && methods.keySet().stream().noneMatch(Signature::isGetter)) {
+            // nothing to merge
+            return customDelegate;
+        }
+        final CompositeBuilder composite =
+            CompositeBuilder.with(validatorFactory, AnnotationBehaviorMergeStrategy.consensus());
+
+        final Map<String, MetadataBuilder.ForContainer<Method>> mergedGetters = new TreeMap<>(getters);
+
+        methods.forEach((k, v) -> {
+            if (k.isGetter()) {
+                mergedGetters.compute(Methods.propertyName(k.getName()), (p, d) -> {
+                    final Method getter = Methods.getter(beanClass, p);
+                    return Stream.of(d, v.getReturnValue(new Meta.ForMethod(getter))).filter(Objects::nonNull)
+                        .collect(composite.composeContainer());
+                });
+            }
+        });
+        final Map<Signature, MetadataBuilder.ForExecutable<Method>> mergedMethods = new TreeMap<>(methods);
+
+        getters.forEach((k, v) -> {
+            final Method getter = Methods.getter(beanClass, k);
+            final Signature signature = Signature.of(getter);
+            
+            final MetadataBuilder.ForContainer<Method> rv;
+            if (methods.containsKey(signature)) {
+                rv = Stream.of(methods.get(signature).getReturnValue(new Meta.ForMethod(getter)), v)
+                    .collect(composite.composeContainer());
+            } else {
+                rv = v;
+            }
+            mergedMethods.put(signature, new CustomWrapper.ForGetterMethod(rv));
+        });
+        return new CustomWrapper.ForBean<>(customDelegate, mergedGetters, mergedMethods);
+    }
+}

Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/DualValidationMappingProvider.java
URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/DualValidationMappingProvider.java?rev=1843674&view=auto
==============================================================================
--- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/DualValidationMappingProvider.java (added)
+++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/DualValidationMappingProvider.java Fri Oct 12 15:00:48 2018
@@ -0,0 +1,50 @@
+/*
+ *  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 org.apache.bval.util.Validate;
+
+public class DualValidationMappingProvider extends ValidatorMappingProvider {
+    private final ValidatorMappingProvider primaryDelegate;
+    private final ValidatorMappingProvider secondaryDelegate;
+
+    public DualValidationMappingProvider(ValidatorMappingProvider primary, ValidatorMappingProvider secondary) {
+        super();
+        this.primaryDelegate = Validate.notNull(primary, "primary delegate");
+        this.secondaryDelegate = Validate.notNull(secondary, "secondary delegate");
+    }
+
+    @Override
+    protected <A extends Annotation> ValidatorMapping<A> doGetValidatorMapping(Class<A> constraintType) {
+
+        final ValidatorMapping<A> secondaryMapping = secondaryDelegate.doGetValidatorMapping(constraintType);
+        final ValidatorMapping<A> primaryMapping = primaryDelegate.doGetValidatorMapping(constraintType);
+        if (secondaryMapping == null) {
+            return primaryMapping;
+        }
+        final AnnotationBehavior annotationBehavior = secondaryMapping.getAnnotationBehavior();
+
+        if (primaryMapping == null || annotationBehavior == AnnotationBehavior.EXCLUDE) {
+            return secondaryMapping;
+        }
+        return ValidatorMapping.merge(Arrays.asList(primaryMapping, secondaryMapping),
+            AnnotationBehaviorMergeStrategy.consensus());
+    }
+}

Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/EmptyBuilder.java
URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/EmptyBuilder.java?rev=1843674&view=auto
==============================================================================
--- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/EmptyBuilder.java (added)
+++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/EmptyBuilder.java Fri Oct 12 15:00:48 2018
@@ -0,0 +1,187 @@
+/*
+ *  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.lang.reflect.AnnotatedElement;
+import java.lang.reflect.AnnotatedType;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.bval.jsr.groups.GroupConversion;
+import org.apache.bval.util.Lazy;
+import org.apache.bval.util.ObjectUtils;
+import org.apache.bval.util.Validate;
+
+public class EmptyBuilder {
+    private static final Map<AnnotationBehavior, EmptyBuilder> INSTANCES = new EnumMap<>(AnnotationBehavior.class);
+
+    public static EmptyBuilder instance() {
+        return instance(AnnotationBehavior.ABSTAIN);
+    }
+
+    public static EmptyBuilder instance(AnnotationBehavior annotationBehavior) {
+        return INSTANCES.computeIfAbsent(annotationBehavior, EmptyBuilder::new);
+    }
+
+    private class Level implements HasAnnotationBehavior {
+
+        @Override
+        public final AnnotationBehavior getAnnotationBehavior() {
+            return annotationBehavior;
+        }
+    }
+
+    private class ForBean<T> extends Level implements MetadataBuilder.ForBean<T> {
+        @SuppressWarnings("rawtypes")
+        private final Lazy<EmptyBuilder.ForClass> forClass = new Lazy<>(EmptyBuilder.ForClass::new);
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public MetadataBuilder.ForClass<T> getClass(Meta<Class<T>> meta) {
+            return forClass.get();
+        }
+
+        @Override
+        public Map<String, MetadataBuilder.ForContainer<Field>> getFields(Meta<Class<T>> meta) {
+            return Collections.emptyMap();
+        }
+
+        @Override
+        public Map<String, MetadataBuilder.ForContainer<Method>> getGetters(Meta<Class<T>> meta) {
+            return Collections.emptyMap();
+        }
+
+        @Override
+        public Map<Signature, MetadataBuilder.ForExecutable<Constructor<? extends T>>> getConstructors(Meta<Class<T>> meta) {
+            return Collections.emptyMap();
+        }
+
+        @Override
+        public Map<Signature, MetadataBuilder.ForExecutable<Method>> getMethods(Meta<Class<T>> meta) {
+            return Collections.emptyMap();
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return true;
+        }
+    }
+
+    private class ForElement<E extends AnnotatedElement> extends Level implements MetadataBuilder.ForElement<E> {
+
+        @Override
+        public final Annotation[] getDeclaredConstraints(Meta<E> meta) {
+            return ObjectUtils.EMPTY_ANNOTATION_ARRAY;
+        }
+    }
+
+    private class ForClass<T> extends ForElement<Class<T>> implements MetadataBuilder.ForClass<T> {
+
+        @Override
+        public List<Class<?>> getGroupSequence(Meta<Class<T>> meta) {
+            return null;
+        }
+    }
+
+    private class ForContainer<E extends AnnotatedElement> extends ForElement<E>
+        implements MetadataBuilder.ForContainer<E> {
+
+        @Override
+        public boolean isCascade(Meta<E> meta) {
+            return false;
+        }
+
+        @Override
+        public Set<GroupConversion> getGroupConversions(Meta<E> meta) {
+            return Collections.emptySet();
+        }
+
+        @Override
+        public Map<ContainerElementKey, MetadataBuilder.ForContainer<AnnotatedType>> getContainerElementTypes(
+            Meta<E> meta) {
+            return Collections.emptyMap();
+        }
+    }
+
+    private class ForExecutable<E extends Executable> extends Level implements MetadataBuilder.ForExecutable<E> {
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public MetadataBuilder.ForElement<E> getCrossParameter(Meta<E> meta) {
+            return forElement.get();
+        }
+
+        @Override
+        public List<MetadataBuilder.ForContainer<Parameter>> getParameters(Meta<E> meta) {
+            return Collections.emptyList();
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public MetadataBuilder.ForContainer<E> getReturnValue(Meta<E> meta) {
+            return forContainer.get();
+        }
+    }
+
+    private final AnnotationBehavior annotationBehavior;
+    @SuppressWarnings("rawtypes")
+    private final Lazy<EmptyBuilder.ForBean> forBean;
+    @SuppressWarnings("rawtypes")
+    private final Lazy<EmptyBuilder.ForContainer> forContainer;
+    @SuppressWarnings("rawtypes")
+    private final Lazy<EmptyBuilder.ForExecutable> forExecutable;
+    @SuppressWarnings("rawtypes")
+    private final Lazy<EmptyBuilder.ForElement> forElement;
+
+    private EmptyBuilder(AnnotationBehavior annotationBehavior) {
+        super();
+        this.annotationBehavior = Validate.notNull(annotationBehavior, "annotationBehavior");
+        forBean = new Lazy<>(EmptyBuilder.ForBean::new);
+        forContainer = new Lazy<>(EmptyBuilder.ForContainer::new);
+        forExecutable = new Lazy<>(EmptyBuilder.ForExecutable::new);
+        forElement = new Lazy<>(EmptyBuilder.ForElement::new);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> MetadataBuilder.ForBean<T> forBean() {
+        return forBean.get();
+    }
+
+    @SuppressWarnings("unchecked")
+    public <E extends AnnotatedElement> MetadataBuilder.ForContainer<E> forContainer() {
+        return forContainer.get();
+    }
+
+    @SuppressWarnings("unchecked")
+    public <E extends Executable> MetadataBuilder.ForExecutable<E> forExecutable() {
+        return forExecutable.get();
+    }
+
+    @SuppressWarnings("unchecked")
+    public <E extends AnnotatedElement> MetadataBuilder.ForElement<E> forElement() {
+        return forElement.get();
+    }
+}

Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HasAnnotationBehavior.java
URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HasAnnotationBehavior.java?rev=1843674&view=auto
==============================================================================
--- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HasAnnotationBehavior.java (added)
+++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HasAnnotationBehavior.java Fri Oct 12 15:00:48 2018
@@ -0,0 +1,24 @@
+/*
+ *  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;
+
+public interface HasAnnotationBehavior {
+
+    default AnnotationBehavior getAnnotationBehavior() {
+        return AnnotationBehavior.ABSTAIN;
+    }
+}
\ No newline at end of file

Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HierarchyBuilder.java
URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HierarchyBuilder.java?rev=1843674&view=auto
==============================================================================
--- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HierarchyBuilder.java (added)
+++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HierarchyBuilder.java Fri Oct 12 15:00:48 2018
@@ -0,0 +1,397 @@
+/*
+ *  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.lang.reflect.AnnotatedElement;
+import java.lang.reflect.AnnotatedType;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import javax.validation.ElementKind;
+import javax.validation.ParameterNameProvider;
+
+import org.apache.bval.jsr.ApacheValidatorFactory;
+import org.apache.bval.jsr.groups.GroupConversion;
+import org.apache.bval.jsr.util.Methods;
+import org.apache.bval.jsr.util.Proxies;
+import org.apache.bval.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.commons.weaver.privilizer.Privilizing;
+import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
+
+@Privilizing(@CallTo(Reflection.class))
+public class HierarchyBuilder extends CompositeBuilder {
+    static abstract class HierarchyDelegate<E extends AnnotatedElement, D extends HasAnnotationBehavior> {
+        final D delegate;
+        final Meta<E> hierarchyElement;
+
+        HierarchyDelegate(D delegate, Meta<E> hierarchyElement) {
+            super();
+            this.delegate = Validate.notNull(delegate, "delegate");
+            this.hierarchyElement = Validate.notNull(hierarchyElement, "hierarchyElement");
+        }
+
+        Meta<E> getHierarchyElement() {
+            return hierarchyElement;
+        }
+    }
+
+    static abstract class ElementDelegate<E extends AnnotatedElement, T extends MetadataBuilder.ForElement<E>>
+        extends HierarchyDelegate<E, T> {
+
+        ElementDelegate(T delegate, Meta<E> hierarchyElement) {
+            super(delegate, hierarchyElement);
+        }
+
+        Annotation[] getDeclaredConstraints() {
+            return delegate.getDeclaredConstraints(hierarchyElement);
+        }
+    }
+
+    private class BeanDelegate<H, T extends H> extends HierarchyDelegate<Class<H>, MetadataBuilder.ForBean<H>>
+        implements MetadataBuilder.ForBean<T> {
+
+        BeanDelegate(MetadataBuilder.ForBean<H> delegate, Class<H> hierarchyType) {
+            super(delegate, new Meta.ForClass<H>(hierarchyType));
+        }
+
+        @Override
+        public MetadataBuilder.ForClass<T> getClass(Meta<Class<T>> meta) {
+            return new ClassDelegate<>(delegate.getClass(hierarchyElement), hierarchyElement);
+        }
+
+        @Override
+        public Map<String, MetadataBuilder.ForContainer<Field>> getFields(Meta<Class<T>> meta) {
+            final Map<String, MetadataBuilder.ForContainer<Field>> fields = delegate.getFields(hierarchyElement);
+
+            if (fields.isEmpty()) {
+                return fields;
+            }
+            final Map<String, MetadataBuilder.ForContainer<Field>> result = new LinkedHashMap<>();
+
+            fields.forEach((k, v) -> {
+                final Field fld = Reflection.getDeclaredField(hierarchyElement.getHost(), k);
+                Exceptions.raiseIf(fld == null, IllegalStateException::new, "delegate builder specified unknown field");
+                result.put(k, new ContainerDelegate<Field>(v, new Meta.ForField(fld)));
+            });
+            return result;
+        }
+
+        @Override
+        public Map<Signature, MetadataBuilder.ForExecutable<Constructor<? extends T>>> getConstructors(Meta<Class<T>> meta) {
+            if (hierarchyElement.equals(meta)) {
+                @SuppressWarnings("unchecked")
+                final Map<Signature, MetadataBuilder.ForExecutable<Constructor<? extends T>>> result =
+                    ((MetadataBuilder.ForBean<T>) delegate).getConstructors(meta);
+                return result;
+            }
+            // ignore hierarchical ctors:
+            return Collections.emptyMap();
+        }
+
+        @Override
+        public Map<String, MetadataBuilder.ForContainer<Method>> getGetters(Meta<Class<T>> meta) {
+            final Map<String, MetadataBuilder.ForContainer<Method>> getters = delegate.getGetters(hierarchyElement);
+            if (getters.isEmpty()) {
+                return getters;
+            }
+            final Map<String, MetadataBuilder.ForContainer<Method>> result = new LinkedHashMap<>();
+            final List<ContainerDelegate<Method>> delegates = new ArrayList<>();
+
+            getters.forEach((k, v) -> {
+                final Method getter = Methods.getter(hierarchyElement.getHost(), k);
+
+                Exceptions.raiseIf(getter == null, IllegalStateException::new,
+                    "delegate builder specified unknown getter");
+
+                final ContainerDelegate<Method> d = new ContainerDelegate<>(v, new Meta.ForMethod(getter));
+                result.put(k, d);
+                delegates.add(d);
+            });
+            Liskov.validateValidateOnExecution(delegates);
+
+            return result;
+        }
+
+        @Override
+        public Map<Signature, MetadataBuilder.ForExecutable<Method>> getMethods(Meta<Class<T>> meta) {
+            final Map<Signature, MetadataBuilder.ForExecutable<Method>> methods = delegate.getMethods(hierarchyElement);
+            if (methods.isEmpty()) {
+                return methods;
+            }
+            final Map<Signature, MetadataBuilder.ForExecutable<Method>> result = new LinkedHashMap<>();
+            final List<ExecutableDelegate<Method>> delegates = new ArrayList<>();
+            methods.forEach((k, v) -> {
+                final ExecutableDelegate<Method> d = new ExecutableDelegate<>(v,
+                    new Meta.ForMethod(
+                        Reflection.getDeclaredMethod(hierarchyElement.getHost(), k.getName(), k.getParameterTypes())),
+                    ParameterNameProvider::getParameterNames);
+                result.put(k, d);
+                delegates.add(d);
+            });
+            Liskov.validateValidateOnExecution(delegates);
+
+            return result;
+        }
+    }
+
+    private class ClassDelegate<H, T extends H> extends ElementDelegate<Class<H>, MetadataBuilder.ForClass<H>>
+        implements MetadataBuilder.ForClass<T> {
+
+        ClassDelegate(MetadataBuilder.ForClass<H> delegate, Meta<Class<H>> hierarchyType) {
+            super(delegate, hierarchyType);
+        }
+
+        @Override
+        public List<Class<?>> getGroupSequence(Meta<Class<T>> meta) {
+            return delegate.getGroupSequence(hierarchyElement);
+        }
+
+        @Override
+        public Annotation[] getDeclaredConstraints(Meta<Class<T>> meta) {
+            return getDeclaredConstraints();
+        }
+    }
+
+    class ContainerDelegate<E extends AnnotatedElement> extends ElementDelegate<E, MetadataBuilder.ForContainer<E>>
+        implements MetadataBuilder.ForContainer<E> {
+
+        ContainerDelegate(MetadataBuilder.ForContainer<E> delegate, Meta<E> hierarchyElement) {
+            super(delegate, hierarchyElement);
+        }
+        
+        boolean isCascade() {
+            return delegate.isCascade(hierarchyElement);
+        }
+
+        @Override
+        public final boolean isCascade(Meta<E> meta) {
+            return isCascade();
+        }
+
+        Set<GroupConversion> getGroupConversions() {
+            return delegate.getGroupConversions(hierarchyElement);
+        }
+
+        @Override
+        public final Set<GroupConversion> getGroupConversions(Meta<E> meta) {
+            return getGroupConversions();
+        }
+
+        @Override
+        public Map<ContainerElementKey, MetadataBuilder.ForContainer<AnnotatedType>> getContainerElementTypes(
+            Meta<E> meta) {
+            final Map<ContainerElementKey, MetadataBuilder.ForContainer<AnnotatedType>> containerElementTypes =
+                delegate.getContainerElementTypes(hierarchyElement);
+
+            final Map<ContainerElementKey, MetadataBuilder.ForContainer<AnnotatedType>> result = new LinkedHashMap<>();
+
+            containerElementTypes.forEach((k, v) -> {
+                result.put(k, new ContainerDelegate<>(v, new Meta.ForContainerElement(hierarchyElement, k)));
+            });
+            return result;
+        }
+
+        @Override
+        public Annotation[] getDeclaredConstraints(Meta<E> meta) {
+            return getDeclaredConstraints();
+        }
+    }
+
+    private class ExecutableDelegate<E extends Executable>
+        extends HierarchyDelegate<E, MetadataBuilder.ForExecutable<E>> implements MetadataBuilder.ForExecutable<E> {
+
+        final BiFunction<ParameterNameProvider, E, List<String>> getParameterNames;
+
+        ExecutableDelegate(MetadataBuilder.ForExecutable<E> delegate, Meta<E> hierarchyElement,
+            BiFunction<ParameterNameProvider, E, List<String>> getParameterNames) {
+            super(delegate, hierarchyElement);
+            this.getParameterNames = Validate.notNull(getParameterNames, "getParameterNames");
+        }
+
+        @Override
+        public MetadataBuilder.ForContainer<E> getReturnValue(Meta<E> meta) {
+            return new ContainerDelegate<>(delegate.getReturnValue(hierarchyElement), hierarchyElement);
+        }
+
+        @Override
+        public MetadataBuilder.ForElement<E> getCrossParameter(Meta<E> meta) {
+            return new CrossParameterDelegate<>(delegate.getCrossParameter(hierarchyElement), hierarchyElement);
+        }
+
+        @Override
+        public List<MetadataBuilder.ForContainer<Parameter>> getParameters(Meta<E> meta) {
+            final List<MetadataBuilder.ForContainer<Parameter>> parameterDelegates =
+                delegate.getParameters(hierarchyElement);
+
+            if (parameterDelegates.isEmpty()) {
+                return parameterDelegates;
+            }
+            final List<Meta<Parameter>> metaParameters = getMetaParameters(hierarchyElement, getParameterNames);
+
+            if (metaParameters.size() != parameterDelegates.size()) {
+                Exceptions.raise(IllegalStateException::new, "Got wrong number of parameter delegates for %s",
+                    meta.getHost());
+            }
+            return IntStream.range(0, parameterDelegates.size())
+                .mapToObj(n -> new ContainerDelegate<>(parameterDelegates.get(n), metaParameters.get(n)))
+                .collect(Collectors.toList());
+        }
+    }
+
+    private class CrossParameterDelegate<E extends Executable>
+        extends ElementDelegate<E, MetadataBuilder.ForElement<E>> implements MetadataBuilder.ForElement<E> {
+
+        CrossParameterDelegate(MetadataBuilder.ForElement<E> delegate, Meta<E> hierarchyElement) {
+            super(delegate, hierarchyElement);
+        }
+
+        @Override
+        public Annotation[] getDeclaredConstraints(Meta<E> meta) {
+            return getDeclaredConstraints();
+        }
+    }
+
+    private class ForCrossParameter<E extends Executable>
+        extends CompositeBuilder.ForElement<CrossParameterDelegate<E>, E> {
+
+        ForCrossParameter(List<CrossParameterDelegate<E>> delegates) {
+            super(delegates);
+            Liskov.validateCrossParameterHierarchy(delegates);
+        }
+    }
+
+    private class ForContainer<E extends AnnotatedElement>
+        extends CompositeBuilder.ForContainer<ContainerDelegate<E>, E> {
+
+        ForContainer(List<ContainerDelegate<E>> delegates, ElementKind elementKind) {
+            super(delegates);
+            Liskov.validateContainerHierarchy(delegates, Validate.notNull(elementKind, "elementKind"));
+        }
+    }
+
+    private final Function<Class<?>, MetadataBuilder.ForBean<?>> getBeanBuilder;
+
+    public HierarchyBuilder(ApacheValidatorFactory validatorFactory,
+        Function<Class<?>, MetadataBuilder.ForBean<?>> getBeanBuilder) {
+        super(validatorFactory, AnnotationBehaviorMergeStrategy.first());
+        this.getBeanBuilder = Validate.notNull(getBeanBuilder, "getBeanBuilder function was null");
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public <T> MetadataBuilder.ForBean<T> forBean(Class<T> beanClass) {
+        final List<MetadataBuilder.ForBean<?>> delegates = new ArrayList<>();
+
+        /*
+         * First add the delegate for the requested bean class, forcing to empty if absent. This is important for the
+         * same reason that we use the #first() AnnotationBehaviorMergeStrategy: namely, that custom metadata overrides
+         * only from the immediately available mapping per the BV spec.
+         */
+        delegates.add(Optional.of(beanClass).map(getBeanBuilder).orElseGet(() -> EmptyBuilder.instance().forBean()));
+
+        // iterate the hierarchy, skipping the first (i.e. beanClass handled above)
+        final Iterator<Class<?>> hierarchy = Reflection.hierarchy(beanClass, Interfaces.INCLUDE).iterator();
+        hierarchy.next();
+
+        // filter; map; skip empty hierarchy builders, mapping others to BeanDelegate
+        hierarchy.forEachRemaining(t -> Optional.of(t).filter(this::canValidate).map(getBeanBuilder)
+            .filter(b -> !b.isEmpty()).map(b -> new BeanDelegate(b, t)).ifPresent(delegates::add));
+
+        if (delegates.size() == 1) {
+            return (MetadataBuilder.ForBean<T>) delegates.get(0);
+        }
+        // pretend:
+        return delegates.stream().<MetadataBuilder.ForBean<T>> map(MetadataBuilder.ForBean.class::cast)
+            .collect(compose());
+    }
+
+    @Override
+    protected <E extends AnnotatedElement> Map<Meta<E>, Annotation[]> getConstraintDeclarationMap(
+        CompositeBuilder.ForElement<? extends MetadataBuilder.ForElement<E>, E> composite, Meta<E> meta) {
+
+        @SuppressWarnings("unchecked")
+        final Function<MetadataBuilder.ForElement<E>, Meta<E>> keyMapper =
+            d -> Optional.of(d).filter(HierarchyDelegate.class::isInstance).map(HierarchyDelegate.class::cast)
+                .map(HierarchyDelegate::getHierarchyElement).orElse(meta);
+
+        return composite.delegates.stream().collect(Collectors.toMap(keyMapper, d -> d.getDeclaredConstraints(meta),
+            (u, v) -> Stream.of(u, v).flatMap(Stream::of).toArray(Annotation[]::new), LinkedHashMap::new));
+    }
+
+    @Override
+    protected <T> List<Class<?>> getGroupSequence(CompositeBuilder.ForClass<T> composite, Meta<Class<T>> meta) {
+        return composite.delegates.get(0).getGroupSequence(meta);
+    }
+
+    @Override
+    protected <DELEGATE extends MetadataBuilder.ForContainer<E>, E extends AnnotatedElement> MetadataBuilder.ForContainer<E> forContainer(
+        List<DELEGATE> delegates, Meta<E> meta, ElementKind elementKind) {
+
+        if (delegates.isEmpty()) {
+            return super.forContainer(delegates, meta, elementKind);
+        }
+        final List<ContainerDelegate<E>> hierarchyDelegates = delegates.stream()
+            .<ContainerDelegate<E>> map(
+                d -> d instanceof ContainerDelegate<?> ? (ContainerDelegate<E>) d : new ContainerDelegate<>(d, meta))
+            .collect(Collectors.toList());
+
+        @SuppressWarnings("unchecked")
+        final CompositeBuilder.ForContainer<DELEGATE, E> result =
+            (CompositeBuilder.ForContainer<DELEGATE, E>) new HierarchyBuilder.ForContainer<E>(hierarchyDelegates,
+                elementKind);
+
+        return result;
+    }
+
+    @Override
+    protected <DELEGATE extends MetadataBuilder.ForElement<E>, E extends Executable> MetadataBuilder.ForElement<E> forCrossParameter(
+        List<DELEGATE> delegates, Meta<E> meta) {
+
+        if (delegates.isEmpty()) {
+            return super.forCrossParameter(delegates, meta);
+        }
+        final List<CrossParameterDelegate<E>> hierarchyDelegates =
+            delegates.stream()
+                .<CrossParameterDelegate<E>> map(d -> d instanceof CrossParameterDelegate<?>
+                    ? (CrossParameterDelegate<E>) d : new CrossParameterDelegate<>(d, meta))
+                .collect(Collectors.toList());
+        return new HierarchyBuilder.ForCrossParameter<>(hierarchyDelegates);
+    }
+
+    private boolean canValidate(Class<?> t) {
+        return !(t.getName().startsWith("java.") || Proxies.isProxyClass(t));
+    }
+}

Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/Liskov.java
URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/Liskov.java?rev=1843674&view=auto
==============================================================================
--- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/Liskov.java (added)
+++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/Liskov.java Fri Oct 12 15:00:48 2018
@@ -0,0 +1,231 @@
+/*
+ *  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.ElementType;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import javax.validation.ConstraintDeclarationException;
+import javax.validation.ElementKind;
+import javax.validation.Valid;
+import javax.validation.executable.ValidateOnExecution;
+
+import org.apache.bval.jsr.metadata.HierarchyBuilder.ContainerDelegate;
+import org.apache.bval.jsr.metadata.HierarchyBuilder.ElementDelegate;
+import org.apache.bval.jsr.metadata.HierarchyBuilder.HierarchyDelegate;
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.Validate;
+
+class Liskov {
+    //@formatter:off
+    private enum ValidationElement {
+        constraints, cascades, groupConversions, validateOnExecution;
+    }
+
+    private enum StrengtheningIssue implements Predicate<Map<Meta<?>, Set<ValidationElement>>> {
+        overriddenHierarchy("overridden %s in inheritance hierarchy: %s") {
+
+            @Override
+            public boolean test(Map<Meta<?>, Set<ValidationElement>> detectedValidationElements) {
+                boolean lowestFound = false;
+
+                for (Set<ValidationElement> validated : detectedValidationElements.values()) {
+                    if (lowestFound) {
+                        return false;
+                    }
+                    lowestFound = !validated.isEmpty();
+                }
+                return true;
+            }
+        },
+        unrelatedInheritance("declared %s in unrelated inheritance hierarchies: %s") {
+
+            @Override
+            public boolean test(Map<Meta<?>, Set<ValidationElement>> detectedValidationElements) {
+                final Set<Class<?>> interfaces = detectedValidationElements.keySet().stream().map(Meta::getDeclaringClass)
+                        .filter(Class::isInterface).collect(Collectors.toSet());
+                if (interfaces.isEmpty()) {
+                    return true;
+                }
+                final boolean allRelated =
+                    detectedValidationElements.keySet().stream().map(Meta::getDeclaringClass).allMatch(ifc -> interfaces
+                        .stream().filter(Predicate.isEqual(ifc).negate()).allMatch(ifc2 -> related(ifc, ifc2)));
+
+                return allRelated;
+            }
+        };
+        //@formatter:on
+
+        final String format;
+
+        private StrengtheningIssue(String format) {
+            this.format = "Illegal strengthening: " + format;
+        }
+
+        Supplier<String> messageFor(Map<Meta<?>, Set<ValidationElement>> detectedValidationElements) {
+            return () -> {
+                final Set<ValidationElement> validationElements =
+                    detectedValidationElements.values().stream().flatMap(Collection::stream)
+                        .collect(Collectors.toCollection(() -> EnumSet.noneOf(ValidationElement.class)));
+
+                final String describeHierarchy = detectedValidationElements.keySet().stream().map(Meta::describeHost)
+                    .collect(Collectors.joining(", ", "[", "]"));
+
+                return String.format(format, validationElements, describeHierarchy);
+            };
+        }
+
+        void check(Map<Meta<?>, Set<ValidationElement>> detectedValidationElements) {
+            Exceptions.raiseUnless(test(detectedValidationElements), ConstraintDeclarationException::new,
+                messageFor(detectedValidationElements));
+        }
+    }
+
+    static void validateContainerHierarchy(Collection<? extends ContainerDelegate<?>> delegates, ElementKind elementKind) {
+        if (Validate.notNull(delegates, "delegates").isEmpty()) {
+            return;
+        }
+        if (Validate.notNull(elementKind, "elementKind") == ElementKind.CONTAINER_ELEMENT) {
+            elementKind = getContainer(delegates.iterator().next().getHierarchyElement());
+        }
+        switch (elementKind) {
+        case RETURN_VALUE:
+            noRedeclarationOfReturnValueCascading(delegates);
+
+            final Map<Meta<?>, Set<ValidationElement>> detectedValidationElements =
+                detectValidationElements(delegates, ElementDelegate::getHierarchyElement, detectGroupConversion());
+
+            // pre-check return value overridden hierarchy:
+            Stream.of(StrengtheningIssue.values())
+                .filter((Predicate<? super StrengtheningIssue>) si -> !(si == StrengtheningIssue.overriddenHierarchy
+                    && detectedValidationElements.values().stream().filter(s -> !s.isEmpty()).count() < 2))
+                .forEach(si -> si.check(detectedValidationElements));
+
+            break;
+        case PARAMETER:
+            noStrengtheningOfPreconditions(delegates, detectConstraints(), detectCascading(), detectGroupConversion());
+            break;
+        default:
+            break;
+        }
+    }
+
+    static void validateCrossParameterHierarchy(Collection<? extends ElementDelegate<?, ?>> delegates) {
+        if (Validate.notNull(delegates, "delegates").isEmpty()) {
+            return;
+        }
+        noStrengtheningOfPreconditions(delegates, detectConstraints());
+    }
+
+    static void validateValidateOnExecution(Collection<? extends HierarchyDelegate<?, ?>> delegates) {
+        noStrengtheningOfPreconditions(delegates, detectValidateOnExecution());
+    }
+
+    private static ElementKind getContainer(Meta<?> meta) {
+        Meta<?> m = meta;
+        while (m.getElementType() == ElementType.TYPE_USE) {
+            m = m.getParent();
+        }
+        switch (m.getElementType()) {
+        case METHOD:
+            return ElementKind.RETURN_VALUE;
+        case PARAMETER:
+            return ElementKind.PARAMETER;
+        default:
+            return ElementKind.PROPERTY;
+        }
+    }
+
+    private static void noRedeclarationOfReturnValueCascading(Collection<? extends ContainerDelegate<?>> delegates) {
+        final Map<Class<?>, Meta<?>> cascadedReturnValues =
+            delegates.stream().filter(ContainerDelegate::isCascade).map(HierarchyDelegate::getHierarchyElement)
+                .collect(Collectors.toMap(Meta::getDeclaringClass, Function.identity()));
+
+        final boolean anyRelated = cascadedReturnValues.keySet().stream().anyMatch(t -> cascadedReturnValues.keySet()
+            .stream().filter(Predicate.isEqual(t).negate()).anyMatch(t2 -> related(t, t2)));
+
+        Exceptions.raiseIf(anyRelated, ConstraintDeclarationException::new,
+            "Multiple method return values marked @%s in hierarchy %s",
+            f -> f.args(Valid.class.getSimpleName(), cascadedReturnValues.values()));
+    }
+
+    @SafeVarargs
+    private static <D extends HierarchyDelegate<?, ?>> void noStrengtheningOfPreconditions(Collection<? extends D> delegates,
+        Function<? super D, ValidationElement>... detectors) {
+
+        final Map<Meta<?>, Set<ValidationElement>> detectedValidationElements = 
+                detectValidationElements(delegates, HierarchyDelegate::getHierarchyElement, detectors);
+
+        if (detectedValidationElements.isEmpty()) {
+            return;
+        }
+        for (StrengtheningIssue s : StrengtheningIssue.values()) {
+            s.check(detectedValidationElements);
+        }
+    }
+
+    @SafeVarargs
+    private static <T> Map<Meta<?>, Set<ValidationElement>> detectValidationElements(Collection<? extends T> delegates,
+        Function<? super T, Meta<?>> toMeta, Function<? super T, ValidationElement>... detectors) {
+        final Map<Meta<?>, Set<ValidationElement>> detectedValidationElements = new LinkedHashMap<>();
+        delegates.forEach(d -> {
+            detectedValidationElements.put(toMeta.apply(d),
+                Stream.of(detectors).map(dt -> dt.apply(d)).filter(Objects::nonNull)
+                    .collect(Collectors.toCollection(() -> EnumSet.noneOf(ValidationElement.class))));
+        });
+        if (detectedValidationElements.values().stream().allMatch(Collection::isEmpty)) {
+            // nothing declared
+            return Collections.emptyMap();
+        }
+        return detectedValidationElements;
+    }
+
+    private static boolean related(Class<?> c1, Class<?> c2) {
+        return c1.isAssignableFrom(c2) || c2.isAssignableFrom(c1);
+    }
+
+    private static Function<ElementDelegate<?, ?>, ValidationElement> detectConstraints() {
+        return d -> d.getDeclaredConstraints().length > 0 ? ValidationElement.constraints : null;
+    }
+
+    private static Function<ContainerDelegate<?>, ValidationElement> detectCascading() {
+        return d -> d.isCascade() ? ValidationElement.cascades : null;
+    }
+
+    private static Function<ContainerDelegate<?>, ValidationElement> detectGroupConversion() {
+        return d -> d.getGroupConversions().isEmpty() ? null : ValidationElement.groupConversions;
+    }
+
+    private static Function<HierarchyDelegate<?, ?>, ValidationElement> detectValidateOnExecution() {
+        return d -> d.getHierarchyElement().getHost().isAnnotationPresent(ValidateOnExecution.class)
+            ? ValidationElement.validateOnExecution : null;
+    }
+
+    private Liskov() {
+    }
+}