You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bval.apache.org by mb...@apache.org on 2018/04/05 17:19:11 UTC

[1/3] bval git commit: no implicit groups on interfaces; retain elsewhere

Repository: bval
Updated Branches:
  refs/heads/bv2 3409b647b -> 0dd0106b0


no implicit groups on interfaces; retain elsewhere


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

Branch: refs/heads/bv2
Commit: 7fab00d5e2b6b9aa012df0a8574d3f0355a25403
Parents: 3409b64
Author: Matt Benson <mb...@apache.org>
Authored: Wed Apr 4 16:45:57 2018 -0500
Committer: Matt Benson <mb...@apache.org>
Committed: Wed Apr 4 16:45:57 2018 -0500

----------------------------------------------------------------------
 .../apache/bval/jsr/descriptor/ConstraintD.java |   1 -
 .../bval/jsr/descriptor/DescriptorManager.java  |   6 +-
 .../bval/jsr/descriptor/MetadataReader.java     |  48 ++++++--
 .../org/apache/bval/jsr/job/ValidationJob.java  |   8 +-
 .../bval/jsr/metadata/CompositeBuilder.java     |  12 +-
 .../bval/jsr/metadata/HierarchyBuilder.java     |  21 ++--
 .../bval/jsr/metadata/MetadataBuilder.java      |   6 +-
 .../bval/jsr/util/AnnotationsManager.java       | 119 ++++++++-----------
 .../org/apache/bval/jsr/BeanDescriptorTest.java |   3 -
 9 files changed, 114 insertions(+), 110 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/bval/blob/7fab00d5/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstraintD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstraintD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstraintD.java
index 494002b..a5e528b 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstraintD.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstraintD.java
@@ -87,7 +87,6 @@ public class ConstraintD<A extends Annotation> implements ConstraintDescriptor<A
 
     public ConstraintD(A annotation, Scope scope, Meta<?> meta, ApacheValidatorFactory validatorFactory) {
         this.annotation = Validate.notNull(annotation, "annotation");
-        validatorFactory.getAnnotationsManager().validateConstraintDefinition(annotation.annotationType());
         this.scope = Validate.notNull(scope, "scope");
         this.meta = Validate.notNull(meta, "meta");
 

http://git-wip-us.apache.org/repos/asf/bval/blob/7fab00d5/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java
index 8f1e22f..dff4f77 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java
@@ -50,13 +50,11 @@ public class DescriptorManager {
     private final ApacheValidatorFactory validatorFactory;
     private final ConcurrentMap<Class<?>, BeanD<?>> beanDescriptors = new ConcurrentHashMap<>();
     private final ReflectionBuilder reflectionBuilder;
-    private final MetadataReader metadataReader;
 
     public DescriptorManager(ApacheValidatorFactory validatorFactory) {
         super();
         this.validatorFactory = Validate.notNull(validatorFactory, "validatorFactory");
         this.reflectionBuilder = new ReflectionBuilder(validatorFactory);
-        this.metadataReader = new MetadataReader(validatorFactory);
     }
 
     public <T> BeanDescriptor getBeanDescriptor(Class<T> beanClass) {
@@ -66,7 +64,9 @@ public class DescriptorManager {
         if (beanDescriptors.containsKey(beanClass)) {
             return beanDescriptors.get(beanClass);
         }
-        final BeanD<T> beanD = new BeanD<>(metadataReader.forBean(beanClass, builder(beanClass)));
+        final MetadataReader.ForBean<T> reader =
+            new MetadataReader(validatorFactory, beanClass).forBean(builder(beanClass));
+        final BeanD<T> beanD = new BeanD<>(reader);
         @SuppressWarnings("unchecked")
         final BeanD<T> result =
             Optional.ofNullable((BeanD<T>) beanDescriptors.putIfAbsent(beanClass, beanD)).orElse(beanD);

http://git-wip-us.apache.org/repos/asf/bval/blob/7fab00d5/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/MetadataReader.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/MetadataReader.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/MetadataReader.java
index e5e4db6..1673107 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/MetadataReader.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/MetadataReader.java
@@ -50,7 +50,9 @@ import javax.validation.metadata.PropertyDescriptor;
 import javax.validation.metadata.Scope;
 
 import org.apache.bval.jsr.ApacheValidatorFactory;
+import org.apache.bval.jsr.ConstraintAnnotationAttributes;
 import org.apache.bval.jsr.groups.GroupConversion;
+import org.apache.bval.jsr.groups.GroupsComputer;
 import org.apache.bval.jsr.metadata.ContainerElementKey;
 import org.apache.bval.jsr.metadata.EmptyBuilder;
 import org.apache.bval.jsr.metadata.Meta;
@@ -58,7 +60,9 @@ import org.apache.bval.jsr.metadata.MetadataBuilder;
 import org.apache.bval.jsr.metadata.Signature;
 import org.apache.bval.jsr.util.Methods;
 import org.apache.bval.jsr.util.ToUnmodifiable;
+import org.apache.bval.jsr.xml.AnnotationProxyBuilder;
 import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.ObjectUtils;
 import org.apache.bval.util.Validate;
 import org.apache.bval.util.reflection.Reflection;
 
@@ -75,16 +79,43 @@ class MetadataReader {
         }
 
         Set<ConstraintD<?>> getConstraints() {
-            return builder.getConstraintsByScope(meta).entrySet().stream()
-                .flatMap(e -> describe(e.getValue(), e.getKey(), meta)).collect(ToUnmodifiable.set());
+            return builder.getConstraintDeclarationMap(meta).entrySet().stream().flatMap(e -> {
+                final Meta<E> m = e.getKey();
+                final Class<?> declaredBy = m.getDeclaringClass();
+                final Scope scope = declaredBy.equals(beanClass) ? Scope.LOCAL_ELEMENT : Scope.HIERARCHY;
+                return Stream.of(e.getValue())
+                    .peek(
+                        c -> validatorFactory.getAnnotationsManager().validateConstraintDefinition(c.annotationType()))
+                    .map(c -> rewriteConstraint(c, declaredBy))
+                    .map(c -> new ConstraintD<>(c, scope, m, validatorFactory));
+            }).collect(ToUnmodifiable.set());
         }
 
         ApacheValidatorFactory getValidatorFactory() {
             return validatorFactory;
         }
 
-        private Stream<ConstraintD<?>> describe(Annotation[] constraints, Scope scope, Meta<?> meta) {
-            return Stream.of(constraints).map(c -> new ConstraintD<>(c, scope, meta, validatorFactory));
+        private <A extends Annotation> A rewriteConstraint(A constraint, Class<?> declaredBy) {
+            boolean mustRewrite = false;
+            Class<?>[] groups =
+                ConstraintAnnotationAttributes.GROUPS.analyze(constraint.annotationType()).read(constraint);
+            if (groups.length == 0) {
+                mustRewrite = true;
+                groups = GroupsComputer.DEFAULT_GROUP;
+            }
+            if (!(declaredBy.equals(beanClass) || beanClass.isInterface())) {
+                if (ObjectUtils.arrayContains(groups, Default.class)
+                    && !ObjectUtils.arrayContains(groups, declaredBy)) {
+                    mustRewrite = true;
+                    groups = ObjectUtils.arrayAdd(groups, declaredBy);
+                }
+            }
+            if (mustRewrite) {
+                final AnnotationProxyBuilder<A> builder = new AnnotationProxyBuilder<A>(constraint);
+                builder.setGroups(groups);
+                return builder.createAnnotation();
+            }
+            return constraint;
         }
     }
 
@@ -316,13 +347,16 @@ class MetadataReader {
     }
 
     private final ApacheValidatorFactory validatorFactory;
+    private final Class<?> beanClass;
 
-    MetadataReader(ApacheValidatorFactory validatorFactory) {
+    MetadataReader(ApacheValidatorFactory validatorFactory, Class<?> beanClass) {
         super();
         this.validatorFactory = Validate.notNull(validatorFactory, "validatorFactory");
+        this.beanClass = Validate.notNull(beanClass, "beanClass");
     }
 
-    <T> MetadataReader.ForBean<T> forBean(Class<T> beanClass, MetadataBuilder.ForBean<T> builder) {
-        return new MetadataReader.ForBean<>(new Meta.ForClass<>(beanClass), builder);
+    @SuppressWarnings("unchecked")
+    <T> MetadataReader.ForBean<T> forBean(MetadataBuilder.ForBean<T> builder) {
+        return new MetadataReader.ForBean<>(new Meta.ForClass<>((Class<T>) beanClass), builder);
     }
 }

http://git-wip-us.apache.org/repos/asf/bval/blob/7fab00d5/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java
index 0bbf17d..d9a94a8 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java
@@ -133,11 +133,11 @@ public abstract class ValidationJob<T> {
 
         private Stream<ConstraintD<?>> constraintsFor(Class<?> group) {
             return descriptor.getConstraintDescriptors().stream().<ConstraintD<?>> map(ConstraintD.class::cast)
-                .filter(c -> Stream.of(group).anyMatch(t -> {
+                .filter(c -> {
                     final Set<Class<?>> constraintGroups = c.getGroups();
-                    return constraintGroups.contains(t)
-                        || constraintGroups.contains(Default.class) && c.getDeclaringClass().isAssignableFrom(t);
-                }));
+                    return constraintGroups.contains(group)
+                        || constraintGroups.contains(Default.class) && c.getDeclaringClass().isAssignableFrom(group);
+                });
         }
 
         @SuppressWarnings({ "rawtypes", "unchecked" })

http://git-wip-us.apache.org/repos/asf/bval/blob/7fab00d5/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/CompositeBuilder.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/CompositeBuilder.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/CompositeBuilder.java
index 77f3b60..60419fb 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/CompositeBuilder.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/CompositeBuilder.java
@@ -39,7 +39,6 @@ import java.util.stream.Stream;
 
 import javax.validation.ElementKind;
 import javax.validation.ParameterNameProvider;
-import javax.validation.metadata.Scope;
 
 import org.apache.bval.jsr.ApacheValidatorFactory;
 import org.apache.bval.jsr.groups.GroupConversion;
@@ -71,7 +70,8 @@ public class CompositeBuilder {
         }
 
         <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).collect(Collectors.toList());
+            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 =
@@ -140,8 +140,8 @@ public class CompositeBuilder {
         }
 
         @Override
-        public Map<Scope, Annotation[]> getConstraintsByScope(Meta<E> meta) {
-            return CompositeBuilder.this.getConstraintsByScope(this, meta);
+        public Map<Meta<E>, Annotation[]> getConstraintDeclarationMap(Meta<E> meta) {
+            return CompositeBuilder.this.getConstraintDeclarationMap(this, meta);
         }
 
         @Override
@@ -263,9 +263,9 @@ public class CompositeBuilder {
             .mapToObj(n -> new Meta.ForParameter(parameters[n], parameterNames.get(n))).collect(Collectors.toList());
     }
 
-    protected <E extends AnnotatedElement> Map<Scope, Annotation[]> getConstraintsByScope(
+    protected <E extends AnnotatedElement> Map<Meta<E>, Annotation[]> getConstraintDeclarationMap(
         CompositeBuilder.ForElement<? extends MetadataBuilder.ForElement<E>, E> composite, Meta<E> meta) {
-        return Collections.singletonMap(Scope.LOCAL_ELEMENT, composite.getDeclaredConstraints(meta));
+        return Collections.singletonMap(meta, composite.getDeclaredConstraints(meta));
     }
 
     protected <T> List<Class<?>> getGroupSequence(CompositeBuilder.ForClass<T> composite, Meta<Class<T>> meta) {

http://git-wip-us.apache.org/repos/asf/bval/blob/7fab00d5/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HierarchyBuilder.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HierarchyBuilder.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HierarchyBuilder.java
index 4861c1a..5fe228c 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HierarchyBuilder.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HierarchyBuilder.java
@@ -26,7 +26,6 @@ import java.lang.reflect.Method;
 import java.lang.reflect.Parameter;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.EnumMap;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -37,10 +36,10 @@ 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 javax.validation.metadata.Scope;
 
 import org.apache.bval.jsr.ApacheValidatorFactory;
 import org.apache.bval.jsr.groups.GroupConversion;
@@ -314,20 +313,16 @@ public class HierarchyBuilder extends CompositeBuilder {
     }
 
     @Override
-    protected <E extends AnnotatedElement> Map<Scope, Annotation[]> getConstraintsByScope(
+    protected <E extends AnnotatedElement> Map<Meta<E>, Annotation[]> getConstraintDeclarationMap(
         CompositeBuilder.ForElement<? extends MetadataBuilder.ForElement<E>, E> composite, Meta<E> meta) {
 
-        final Iterator<? extends MetadataBuilder.ForElement<E>> iter = composite.delegates.iterator();
-
-        final Map<Scope, Annotation[]> result = new EnumMap<>(Scope.class);
-        result.put(Scope.LOCAL_ELEMENT, iter.next().getDeclaredConstraints(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);
 
-        if (iter.hasNext()) {
-            final List<Annotation> hierarchyConstraints = new ArrayList<>();
-            iter.forEachRemaining(d -> Collections.addAll(hierarchyConstraints, d.getDeclaredConstraints(meta)));
-            result.put(Scope.HIERARCHY, hierarchyConstraints.toArray(new Annotation[hierarchyConstraints.size()]));
-        }
-        return result;
+        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

http://git-wip-us.apache.org/repos/asf/bval/blob/7fab00d5/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/MetadataBuilder.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/MetadataBuilder.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/MetadataBuilder.java
index ff60df0..c66a80a 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/MetadataBuilder.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/MetadataBuilder.java
@@ -29,8 +29,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import javax.validation.metadata.Scope;
-
 import org.apache.bval.jsr.groups.GroupConversion;
 
 /**
@@ -65,8 +63,8 @@ public final class MetadataBuilder {
 
         Annotation[] getDeclaredConstraints(Meta<E> meta);
 
-        default Map<Scope, Annotation[]> getConstraintsByScope(Meta<E> meta) {
-            return Collections.singletonMap(Scope.LOCAL_ELEMENT, getDeclaredConstraints(meta));
+        default Map<Meta<E>, Annotation[]> getConstraintDeclarationMap(Meta<E> meta) {
+            return Collections.singletonMap(meta, getDeclaredConstraints(meta));
         }
     }
 

http://git-wip-us.apache.org/repos/asf/bval/blob/7fab00d5/bval-jsr/src/main/java/org/apache/bval/jsr/util/AnnotationsManager.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/AnnotationsManager.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/AnnotationsManager.java
index 1995c52..dac1294 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/util/AnnotationsManager.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/AnnotationsManager.java
@@ -29,14 +29,12 @@ import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Function;
-import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -54,9 +52,6 @@ import org.apache.bval.jsr.ConfigurationImpl;
 import org.apache.bval.jsr.ConstraintAnnotationAttributes;
 import org.apache.bval.jsr.ConstraintAnnotationAttributes.Worker;
 import org.apache.bval.jsr.ConstraintCached.ConstraintValidatorInfo;
-import org.apache.bval.jsr.groups.Group;
-import org.apache.bval.jsr.groups.Groups;
-import org.apache.bval.jsr.groups.GroupsComputer;
 import org.apache.bval.jsr.metadata.Meta;
 import org.apache.bval.jsr.xml.AnnotationProxyBuilder;
 import org.apache.bval.util.Exceptions;
@@ -259,32 +254,14 @@ public class AnnotationsManager {
      * @return Annotation[]
      */
     public static Annotation[] getDeclaredConstraints(Meta<?> meta) {
-        final Annotation[] result = getDeclaredConstraints(meta.getHost());
-        final Class<?> dc = meta.getDeclaringClass();
-        if (dc.isInterface()) {
-            final GroupsComputer groupsComputer = new GroupsComputer();
-            // ensure interface group is implied by Default group:
-            Stream.of(result).map(c -> {
-                final Groups groups = groupsComputer.computeGroups(
-                    ConstraintAnnotationAttributes.GROUPS.analyze(c.annotationType()).<Class<?>[]> read(c));
-                if (groups.getGroups().stream().anyMatch(Group::isDefault)) {
-                    final Set<Class<?>> groupClasses = groups.getGroups().stream().map(Group::getGroup)
-                        .collect(Collectors.toCollection(LinkedHashSet::new));
-                    if (groupClasses.add(dc)) {
-                        final AnnotationProxyBuilder<?> proxyBuilder = new AnnotationProxyBuilder<>(c);
-                        proxyBuilder.setGroups(groupClasses.toArray(new Class[groupClasses.size()]));
-                        return proxyBuilder.createAnnotation();
-                    }
-                }
-                return c;
-            }).toArray(n -> result);
-        }
-        return result;
+        return getDeclaredConstraints(meta.getHost());
     }
 
     private static Annotation[] getDeclaredConstraints(AnnotatedElement e) {
         final Annotation[] declaredAnnotations = e.getDeclaredAnnotations();
-
+        if (declaredAnnotations.length == 0) {
+            return declaredAnnotations;
+        }
         // collect constraint explicitly nested into repeatable containers:
         final Map<Class<? extends Annotation>, Annotation[]> repeated = new HashMap<>();
 
@@ -296,18 +273,19 @@ public class AnnotationsManager {
                 repeated.put(annotationType, w.read(a));
             }
         }
-        final Set<Annotation> constraints = Stream.of(declaredAnnotations)
-            .filter((Predicate<Annotation>) a -> a.annotationType().isAnnotationPresent(Constraint.class))
-            .collect(Collectors.toSet());
+        Stream<Annotation> constraints = Stream.of(declaredAnnotations)
+                .filter(a -> a.annotationType().isAnnotationPresent(Constraint.class));
 
-        Exceptions.raiseIf(
-            constraints.stream().map(Annotation::annotationType).filter(t -> t.isAnnotationPresent(Repeatable.class))
-                .map(rct -> rct.getAnnotation(Repeatable.class).value()).anyMatch(repeated::containsKey),
-            ConstraintDeclarationException::new,
-            "Simultaneous declaration of repeatable constraint and associated container on %s", e);
+        if (!repeated.isEmpty()) {
+            constraints = constraints.peek(c -> Exceptions.raiseIf(
+                Optional.of(c.annotationType()).map(t -> t.getAnnotation(Repeatable.class)).map(Repeatable::value)
+                    .filter(repeated::containsKey).isPresent(),
+                ConstraintDeclarationException::new,
+                "Simultaneous declaration of repeatable constraint and associated container on %s", e));
 
-        return Stream.concat(constraints.stream(), repeated.values().stream().flatMap(Stream::of))
-            .toArray(Annotation[]::new);
+            constraints = Stream.concat(constraints, repeated.values().stream().flatMap(Stream::of));
+        }
+        return constraints.toArray(Annotation[]::new);
     }
 
     private final ApacheValidatorFactory validatorFactory;
@@ -328,47 +306,50 @@ public class AnnotationsManager {
     }
 
     public void validateConstraintDefinition(Class<? extends Annotation> type) {
-        if (VALIDATED_CONSTRAINT_TYPES.add(type)) {
-            Exceptions.raiseUnless(type.isAnnotationPresent(Constraint.class), ConstraintDefinitionException::new,
-                "%s is not a validation constraint", type);
+        if (VALIDATED_CONSTRAINT_TYPES.contains(type)) {
+            return;
+        }
+        Exceptions.raiseUnless(type.isAnnotationPresent(Constraint.class), ConstraintDefinitionException::new,
+            "%s is not a validation constraint", type);
 
-            final Set<ValidationTarget> supportedTargets = supportedTargets(type);
+        final Set<ValidationTarget> supportedTargets = supportedTargets(type);
 
-            final Map<String, Method> attributes =
-                Stream.of(Reflection.getDeclaredMethods(type)).filter(m -> m.getParameterCount() == 0)
-                    .collect(Collectors.toMap(Method::getName, Function.identity()));
+        final Map<String, Method> attributes =
+            Stream.of(Reflection.getDeclaredMethods(type)).filter(m -> m.getParameterCount() == 0)
+                .collect(Collectors.toMap(Method::getName, Function.identity()));
 
-            if (supportedTargets.size() > 1
-                && !attributes.containsKey(ConstraintAnnotationAttributes.VALIDATION_APPLIES_TO.getAttributeName())) {
-                Exceptions.raise(ConstraintDefinitionException::new,
-                    "Constraint %s is both generic and cross-parameter but lacks %s attribute", type.getName(),
-                    ConstraintAnnotationAttributes.VALIDATION_APPLIES_TO);
-            }
-            for (ConstraintAnnotationAttributes attr : CONSTRAINT_ATTRIBUTES) {
-                if (attributes.containsKey(attr.getAttributeName())) {
-                    Exceptions.raiseUnless(attr.analyze(type).isValid(), ConstraintDefinitionException::new,
-                        "%s declared invalid type for attribute %s", type, attr);
+        if (supportedTargets.size() > 1
+            && !attributes.containsKey(ConstraintAnnotationAttributes.VALIDATION_APPLIES_TO.getAttributeName())) {
+            Exceptions.raise(ConstraintDefinitionException::new,
+                "Constraint %s is both generic and cross-parameter but lacks %s attribute", type.getName(),
+                ConstraintAnnotationAttributes.VALIDATION_APPLIES_TO);
+        }
+        for (ConstraintAnnotationAttributes attr : CONSTRAINT_ATTRIBUTES) {
+            if (attributes.containsKey(attr.getAttributeName())) {
+                Exceptions.raiseUnless(attr.analyze(type).isValid(), ConstraintDefinitionException::new,
+                    "%s declared invalid type for attribute %s", type, attr);
 
-                    if (!attr.isValidDefaultValue(attributes.get(attr.getAttributeName()).getDefaultValue())) {
+                if (!attr.isValidDefaultValue(attributes.get(attr.getAttributeName()).getDefaultValue())) {
+                    Exceptions.raise(ConstraintDefinitionException::new,
+                        "%s declares invalid default value for attribute %s", type, attr);
+                }
+                if (attr == ConstraintAnnotationAttributes.VALIDATION_APPLIES_TO) {
+                    if (supportedTargets.size() == 1) {
                         Exceptions.raise(ConstraintDefinitionException::new,
-                            "%s declares invalid default value for attribute %s", type, attr);
-                    }
-                    if (attr == ConstraintAnnotationAttributes.VALIDATION_APPLIES_TO) {
-                        if (supportedTargets.size() == 1) {
-                            Exceptions.raise(ConstraintDefinitionException::new,
-                                "Pure %s constraint %s should not declare attribute %s",
-                                supportedTargets.iterator().next(), type, attr);
-                        }
+                            "Pure %s constraint %s should not declare attribute %s",
+                            supportedTargets.iterator().next(), type, attr);
                     }
-                } else if (attr.isMandatory()) {
-                    Exceptions.raise(ConstraintDefinitionException::new, "%s does not declare mandatory attribute %s",
-                        type, attr);
                 }
-                attributes.remove(attr.getAttributeName());
+            } else if (attr.isMandatory()) {
+                Exceptions.raise(ConstraintDefinitionException::new, "%s does not declare mandatory attribute %s",
+                    type, attr);
             }
-            attributes.keySet().forEach(k -> Exceptions.raiseIf(k.startsWith("valid"),
-                ConstraintDefinitionException::new, "Invalid constraint attribute %s", k));
+            attributes.remove(attr.getAttributeName());
         }
+        attributes.keySet().forEach(k -> Exceptions.raiseIf(k.startsWith("valid"),
+            ConstraintDefinitionException::new, "Invalid constraint attribute %s", k));
+
+        VALIDATED_CONSTRAINT_TYPES.add(type);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/bval/blob/7fab00d5/bval-jsr/src/test/java/org/apache/bval/jsr/BeanDescriptorTest.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/test/java/org/apache/bval/jsr/BeanDescriptorTest.java b/bval-jsr/src/test/java/org/apache/bval/jsr/BeanDescriptorTest.java
index 5c949c1..d81f90a 100644
--- a/bval-jsr/src/test/java/org/apache/bval/jsr/BeanDescriptorTest.java
+++ b/bval-jsr/src/test/java/org/apache/bval/jsr/BeanDescriptorTest.java
@@ -42,7 +42,6 @@ import javax.validation.metadata.PropertyDescriptor;
 import javax.validation.metadata.Scope;
 
 import org.apache.bval.jsr.util.TestUtils;
-import org.junit.Ignore;
 import org.junit.Test;
 
 /**
@@ -121,8 +120,6 @@ public class BeanDescriptorTest extends ValidationTestBase {
      * interface group when querying the interface directly.
      */
     @Test
-    // spec does not dictate this
-    @Ignore
     public void testNoImplicitGroupWhenQueryingInterfaceDirectly() {
         Set<ConstraintDescriptor<?>> nameDescriptors =
             validator.getConstraintsForClass(Person.class).getConstraintsForProperty("name").getConstraintDescriptors();


[2/3] bval git commit: TCK: pick up constraints on 'inherited' fields

Posted by mb...@apache.org.
TCK: pick up constraints on 'inherited' fields


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

Branch: refs/heads/bv2
Commit: 69a817dace7640bbf5e6d78471c4812a85edad21
Parents: 7fab00d
Author: Matt Benson <mb...@apache.org>
Authored: Thu Apr 5 12:17:45 2018 -0500
Committer: Matt Benson <mb...@apache.org>
Committed: Thu Apr 5 12:17:45 2018 -0500

----------------------------------------------------------------------
 .../apache/bval/jsr/metadata/HierarchyBuilder.java | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/bval/blob/69a817da/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HierarchyBuilder.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HierarchyBuilder.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HierarchyBuilder.java
index 5fe228c..b449a6b 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HierarchyBuilder.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HierarchyBuilder.java
@@ -95,7 +95,19 @@ public class HierarchyBuilder extends CompositeBuilder {
 
         @Override
         public Map<String, MetadataBuilder.ForContainer<Field>> getFields(Meta<Class<T>> meta) {
-            return delegate.getFields(hierarchyElement);
+            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
@@ -113,6 +125,9 @@ public class HierarchyBuilder extends CompositeBuilder {
         @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<>();
 
             getters.forEach((k, v) -> {


[3/3] bval git commit: handle reflection bug with non-static inner class constructor parameter annotations

Posted by mb...@apache.org.
handle reflection bug with non-static inner class constructor parameter annotations


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

Branch: refs/heads/bv2
Commit: 0dd0106b0f2f234fde618d93aea6ea9d80bda2e4
Parents: 69a817d
Author: Matt Benson <mb...@apache.org>
Authored: Thu Apr 5 12:19:01 2018 -0500
Committer: Matt Benson <mb...@apache.org>
Committed: Thu Apr 5 12:19:01 2018 -0500

----------------------------------------------------------------------
 .../bval/jsr/metadata/ReflectionBuilder.java    |  6 +-
 .../bval/jsr/util/AnnotationsManager.java       | 68 +++++++++++++-------
 2 files changed, 47 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/bval/blob/0dd0106b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ReflectionBuilder.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ReflectionBuilder.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ReflectionBuilder.java
index 0a70b7c..daa531e 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ReflectionBuilder.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ReflectionBuilder.java
@@ -204,7 +204,7 @@ public class ReflectionBuilder {
 
         @Override
         public List<Class<?>> getGroupSequence(Meta<Class<T>> ignored) {
-            final GroupSequence groupSequence = meta.getHost().getAnnotation(GroupSequence.class);
+            final GroupSequence groupSequence = AnnotationsManager.getAnnotation(meta.getHost(), GroupSequence.class);
             return groupSequence == null ? null : Collections.unmodifiableList(Arrays.asList(groupSequence.value()));
         }
     }
@@ -238,12 +238,12 @@ public class ReflectionBuilder {
 
         @Override
         public boolean isCascade(Meta<E> ignored) {
-            return meta.getHost().isAnnotationPresent(Valid.class);
+            return AnnotationsManager.isAnnotationDirectlyPresent(meta.getHost(), Valid.class);
         }
 
         @Override
         public Set<GroupConversion> getGroupConversions(Meta<E> ignored) {
-            return Stream.of(meta.getHost().getDeclaredAnnotationsByType(ConvertGroup.class))
+            return Stream.of(AnnotationsManager.getDeclaredAnnotationsByType(meta.getHost(), ConvertGroup.class))
                 .map(cg -> GroupConversion.from(cg.from()).to(cg.to())).collect(ToUnmodifiable.set());
         }
     }

http://git-wip-us.apache.org/repos/asf/bval/blob/0dd0106b/bval-jsr/src/main/java/org/apache/bval/jsr/util/AnnotationsManager.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/AnnotationsManager.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/AnnotationsManager.java
index dac1294..ead0a3b 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/util/AnnotationsManager.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/AnnotationsManager.java
@@ -21,8 +21,11 @@ package org.apache.bval.jsr.util;
 import java.lang.annotation.Annotation;
 import java.lang.annotation.Repeatable;
 import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Parameter;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.EnumSet;
@@ -56,6 +59,7 @@ import org.apache.bval.jsr.metadata.Meta;
 import org.apache.bval.jsr.xml.AnnotationProxyBuilder;
 import org.apache.bval.util.Exceptions;
 import org.apache.bval.util.Lazy;
+import org.apache.bval.util.ObjectUtils;
 import org.apache.bval.util.StringUtils;
 import org.apache.bval.util.Validate;
 import org.apache.bval.util.reflection.Reflection;
@@ -219,31 +223,19 @@ public class AnnotationsManager {
         return result.optional().map(Collections::unmodifiableMap).orElseGet(Collections::emptyMap);
     }
 
-    /**
-     * Meta-annotation aware.
-     * 
-     * @param e
-     * @param t
-     * @return {@code boolean}
-     * @see AnnotatedElement#isAnnotationPresent(Class)
-     */
-    public static boolean isAnnotationPresent(AnnotatedElement e, Class<? extends Annotation> t) {
-        if (e.isAnnotationPresent(t)) {
-            return true;
-        }
-        return Stream.of(e.getAnnotations()).map(Annotation::annotationType).anyMatch(a -> isAnnotationPresent(a, t));
+    public static boolean isAnnotationDirectlyPresent(AnnotatedElement e, Class<? extends Annotation> t) {
+        return substitute(e).filter(s -> s.isAnnotationPresent(t)).isPresent();
     }
 
-    /**
-     * Get declared annotations with a particular meta-annotation.
-     * 
-     * @param e
-     * @param meta
-     * @return {@link Annotation}[]
-     */
-    public static Annotation[] getDeclared(AnnotatedElement e, Class<? extends Annotation> meta) {
-        return Stream.of(e.getDeclaredAnnotations()).filter(ann -> isAnnotationPresent(ann.annotationType(), meta))
-            .toArray(Annotation[]::new);
+    public static <T extends Annotation> T getAnnotation(AnnotatedElement e, Class<T> annotationClass) {
+        return substitute(e).map(s -> s.getAnnotation(annotationClass)).orElse(null);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T extends Annotation> T[] getDeclaredAnnotationsByType(AnnotatedElement e,
+        Class<T> annotationClass) {
+        return substitute(e).map(s -> s.getDeclaredAnnotationsByType(annotationClass))
+            .orElse((T[]) ObjectUtils.EMPTY_ANNOTATION_ARRAY);
     }
 
     /**
@@ -258,7 +250,9 @@ public class AnnotationsManager {
     }
 
     private static Annotation[] getDeclaredConstraints(AnnotatedElement e) {
-        final Annotation[] declaredAnnotations = e.getDeclaredAnnotations();
+        final Annotation[] declaredAnnotations =
+            substitute(e).map(AnnotatedElement::getDeclaredAnnotations).orElse(ObjectUtils.EMPTY_ANNOTATION_ARRAY);
+        
         if (declaredAnnotations.length == 0) {
             return declaredAnnotations;
         }
@@ -287,6 +281,32 @@ public class AnnotationsManager {
         }
         return constraints.toArray(Annotation[]::new);
     }
+    
+
+    private static Optional<AnnotatedElement> substitute(AnnotatedElement e) {
+        if (e instanceof Parameter) {
+            final Parameter p = (Parameter) e;
+            if (p.getDeclaringExecutable() instanceof Constructor<?>) {
+                final Constructor<?> ctor = (Constructor<?>) p.getDeclaringExecutable();
+                final Class<?> dc = ctor.getDeclaringClass();
+                if (!(dc.getDeclaringClass() == null || Modifier.isStatic(dc.getModifiers()))) {
+                    // found ctor for non-static inner class
+                    final Annotation[][] parameterAnnotations = ctor.getParameterAnnotations();
+                    if (parameterAnnotations.length == ctor.getParameterCount() - 1) {
+                        final Parameter[] parameters = ctor.getParameters();
+                        final int idx = ObjectUtils.indexOf(parameters, p);
+                        if (idx == 0) {
+                            return Optional.empty();
+                        }
+                        return Optional.of(parameters[idx - 1]);
+                    }
+                    Validate.validState(parameterAnnotations.length == ctor.getParameterCount(),
+                            "Cannot make sense of parameter annotations of %s", ctor);
+                }
+            }
+        }
+        return Optional.of(e);
+    }
 
     private final ApacheValidatorFactory validatorFactory;
     private final LRUCache<Class<? extends Annotation>, Composition> compositions;