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/03/31 15:58:56 UTC

[2/2] bval git commit: separate constraint filtering by group for purposes of validation vs. metadata inspection (ConstraintFinder)

separate constraint filtering by group for purposes of validation vs. metadata inspection (ConstraintFinder)


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

Branch: refs/heads/bv2
Commit: d7210b030deedc6bc609673037beff496d621e85
Parents: 65fd64b
Author: Matt Benson <mb...@apache.org>
Authored: Sat Mar 31 10:58:46 2018 -0500
Committer: Matt Benson <mb...@apache.org>
Committed: Sat Mar 31 10:58:46 2018 -0500

----------------------------------------------------------------------
 .../apache/bval/jsr/ApacheFactoryContext.java   |  6 +-
 .../apache/bval/jsr/ApacheValidatorFactory.java | 18 +++--
 .../apache/bval/jsr/descriptor/ComposedD.java   |  6 +-
 .../apache/bval/jsr/descriptor/ElementD.java    |  5 +-
 .../org/apache/bval/jsr/descriptor/Finder.java  | 78 +++++++++++++++-----
 .../bval/jsr/descriptor/MetadataReader.java     |  4 +
 .../apache/bval/jsr/groups/GroupsComputer.java  | 55 ++++++++------
 .../org/apache/bval/jsr/job/ValidationJob.java  | 19 ++---
 .../bval/jsr/util/AnnotationsManager.java       |  4 +-
 9 files changed, 133 insertions(+), 62 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/bval/blob/d7210b03/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java
index 7093ad9..1dcc0d3 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java
@@ -30,7 +30,6 @@ import javax.validation.valueextraction.ValueExtractor;
 import org.apache.bval.jsr.descriptor.DescriptorManager;
 import org.apache.bval.jsr.groups.GroupsComputer;
 import org.apache.bval.jsr.valueextraction.ValueExtractors;
-import org.apache.bval.util.Lazy;
 import org.apache.bval.util.reflection.Reflection;
 import org.apache.commons.weaver.privilizer.Privilizing;
 import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
@@ -40,7 +39,6 @@ import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
  */
 @Privilizing(@CallTo(Reflection.class))
 public class ApacheFactoryContext implements ValidatorContext {
-    private final Lazy<GroupsComputer> groupsComputer = new Lazy<>(GroupsComputer::new);
     private final ApacheValidatorFactory factory;
     private final ValueExtractors valueExtractors;
 
@@ -172,12 +170,12 @@ public class ApacheFactoryContext implements ValidatorContext {
     }
 
     public DescriptorManager getDescriptorManager() {
-        // TODO handle context customizations
+        // TODO implementation-specific feature to handle context-local descriptor customizations
         return factory.getDescriptorManager();
     }
 
     public GroupsComputer getGroupsComputer() {
-        return groupsComputer.get();
+        return factory.getGroupsComputer();
     }
 
     public ConstraintCached getConstraintsCache() {

http://git-wip-us.apache.org/repos/asf/bval/blob/d7210b03/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java
index 5e5118f..de1ce3f 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java
@@ -39,6 +39,7 @@ import javax.validation.spi.ConfigurationState;
 import javax.validation.valueextraction.ValueExtractor;
 
 import org.apache.bval.jsr.descriptor.DescriptorManager;
+import org.apache.bval.jsr.groups.GroupsComputer;
 import org.apache.bval.jsr.metadata.MetadataBuilder;
 import org.apache.bval.jsr.metadata.MetadataBuilder.ForBean;
 import org.apache.bval.jsr.metadata.MetadataBuilders;
@@ -47,6 +48,7 @@ import org.apache.bval.jsr.util.AnnotationsManager;
 import org.apache.bval.jsr.valueextraction.ValueExtractors;
 import org.apache.bval.jsr.valueextraction.ValueExtractors.OnDuplicateContainerElementKey;
 import org.apache.bval.util.CloseableAble;
+import org.apache.bval.util.Lazy;
 import org.apache.bval.util.reflection.Reflection;
 import org.apache.commons.weaver.privilizer.Privilizing;
 import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
@@ -93,11 +95,7 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
         return result;
     }
 
-    private MessageInterpolator messageResolver;
-    private TraversableResolver traversableResolver;
-    private ConstraintValidatorFactory constraintValidatorFactory;
-    private ParameterNameProvider parameterNameProvider;
-    private ClockProvider clockProvider;
+    private final Lazy<GroupsComputer> groupsComputer = new Lazy<>(GroupsComputer::new);
     private final Map<String, String> properties;
     private final AnnotationsManager annotationsManager;
     private final DescriptorManager descriptorManager = new DescriptorManager(this);
@@ -107,6 +105,12 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
     private final ParticipantFactory participantFactory;
     private final ValueExtractors valueExtractors;
 
+    private MessageInterpolator messageResolver;
+    private TraversableResolver traversableResolver;
+    private ConstraintValidatorFactory constraintValidatorFactory;
+    private ParameterNameProvider parameterNameProvider;
+    private ClockProvider clockProvider;
+
     /**
      * Create a new ApacheValidatorFactory instance.
      */
@@ -355,6 +359,10 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
         return metadataBuilders;
     }
 
+    public GroupsComputer getGroupsComputer() {
+        return groupsComputer.get();
+    }
+
     private void loadAndVerifyUserCustomizations(ConfigurationState configuration) {
         @SuppressWarnings({ "unchecked", "rawtypes" })
         final BiConsumer<Class<?>, ForBean<?>> addBuilder = (t, b) -> {

http://git-wip-us.apache.org/repos/asf/bval/blob/d7210b03/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComposedD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComposedD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComposedD.java
index 6d3b004..321d425 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComposedD.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComposedD.java
@@ -32,6 +32,7 @@ import javax.validation.metadata.ElementDescriptor;
 import javax.validation.metadata.GroupConversionDescriptor;
 import javax.validation.metadata.PropertyDescriptor;
 
+import org.apache.bval.jsr.groups.GroupsComputer;
 import org.apache.bval.jsr.util.ToUnmodifiable;
 import org.apache.bval.util.Validate;
 
@@ -118,6 +119,9 @@ public abstract class ComposedD<D extends ElementD<?, ?>> implements ElementDesc
 
     @Override
     public ConstraintFinder findConstraints() {
-        return new Finder(this);
+        final GroupsComputer groupsComputer =
+            unwrap(this, ElementD.class).findFirst().orElseThrow(IllegalStateException::new).groupsComputer;
+
+        return new Finder(groupsComputer, this);
     }
 }

http://git-wip-us.apache.org/repos/asf/bval/blob/d7210b03/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ElementD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ElementD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ElementD.java
index b1afa9b..e7c81c6 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ElementD.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ElementD.java
@@ -29,6 +29,7 @@ import java.util.Set;
 import javax.validation.metadata.ConstraintDescriptor;
 import javax.validation.metadata.ElementDescriptor;
 
+import org.apache.bval.jsr.groups.GroupsComputer;
 import org.apache.bval.jsr.metadata.Meta;
 import org.apache.bval.util.Validate;
 import org.apache.bval.util.reflection.TypeUtils;
@@ -72,6 +73,7 @@ public abstract class ElementD<E extends AnnotatedElement, R extends MetadataRea
     }
 
     protected final Type genericType;
+    final GroupsComputer groupsComputer;
 
     private final Meta<E> meta;
     private final Set<ConstraintD<?>> constraints;
@@ -82,6 +84,7 @@ public abstract class ElementD<E extends AnnotatedElement, R extends MetadataRea
         this.meta = reader.meta;
         this.genericType = reader.meta.getType();
         this.constraints = reader.getConstraints();
+        this.groupsComputer = reader.getValidatorFactory().getGroupsComputer();
     }
 
     @Override
@@ -97,7 +100,7 @@ public abstract class ElementD<E extends AnnotatedElement, R extends MetadataRea
 
     @Override
     public final ConstraintFinder findConstraints() {
-        return new Finder(this);
+        return new Finder(groupsComputer, this);
     }
 
     public final ElementType getElementType() {

http://git-wip-us.apache.org/repos/asf/bval/blob/d7210b03/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/Finder.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/Finder.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/Finder.java
index c01e069..ad5d541 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/Finder.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/Finder.java
@@ -19,41 +19,57 @@
 package org.apache.bval.jsr.descriptor;
 
 import java.lang.annotation.ElementType;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.EnumSet;
+import java.util.LinkedHashSet;
 import java.util.Objects;
 import java.util.Set;
 import java.util.function.Predicate;
-import java.util.function.Supplier;
+import java.util.function.UnaryOperator;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import javax.validation.GroupDefinitionException;
+import javax.validation.GroupSequence;
 import javax.validation.groups.Default;
 import javax.validation.metadata.ConstraintDescriptor;
 import javax.validation.metadata.ElementDescriptor;
 import javax.validation.metadata.ElementDescriptor.ConstraintFinder;
 import javax.validation.metadata.Scope;
 
+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.util.ToUnmodifiable;
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.Lazy;
 import org.apache.bval.util.Validate;
 
-class Finder implements ConstraintFinder, Supplier<Stream<ConstraintD<?>>> {
-    private Predicate<ConstraintD<?>> groups = c -> true;
-    private Predicate<ConstraintD<?>> scope;
-    private Predicate<ConstraintD<?>> elements;
+class Finder implements ConstraintFinder {
+    private static Stream<Group> allGroups(Groups groups) {
+        return Stream.concat(groups.getGroups().stream(), groups.getSequences().stream().flatMap(Collection::stream));
+    }
+
+    private volatile Predicate<ConstraintD<?>> groups = c -> true;
+    private volatile Predicate<ConstraintD<?>> scope;
+    private volatile Predicate<ConstraintD<?>> elements;
 
+    private final GroupsComputer groupsComputer;
     private final ElementDescriptor owner;
+    private final Lazy<Groups> getDefaultSequence = new Lazy<>(this::computeDefaultSequence);
+    private final Lazy<Class<?>> beanClass;
 
-    Finder(ElementDescriptor owner) {
+    Finder(GroupsComputer groupsComputer, ElementDescriptor owner) {
+        this.groupsComputer = Validate.notNull(groupsComputer, "groupsComputer");
         this.owner = Validate.notNull(owner, "owner");
+        this.beanClass = new Lazy<>(() -> firstAtomicElementDescriptor().getBean().getElementClass());
     }
 
     @Override
     public ConstraintFinder unorderedAndMatchingGroups(Class<?>... groups) {
-        this.groups = c -> Stream.of(groups).anyMatch(t -> {
-            final Set<Class<?>> constraintGroups = c.getGroups();
-            return constraintGroups.contains(t)
-                || constraintGroups.contains(Default.class) && c.getDeclaringClass().isAssignableFrom(t);
-        });
+        final Set<Class<?>> allGroups = computeAll(groups);
+        this.groups = c -> !Collections.disjoint(allGroups, c.getGroups());
         return this;
     }
 
@@ -73,12 +89,7 @@ class Finder implements ConstraintFinder, Supplier<Stream<ConstraintD<?>>> {
 
     @Override
     public Set<ConstraintDescriptor<?>> getConstraintDescriptors() {
-        return get().collect(ToUnmodifiable.set());
-    }
-
-    @Override
-    public Stream<ConstraintD<?>> get() {
-        return getConstraints().filter(filter());
+        return getConstraints().filter(filter()).collect(ToUnmodifiable.set());
     }
 
     @Override
@@ -100,4 +111,37 @@ class Finder implements ConstraintFinder, Supplier<Stream<ConstraintD<?>>> {
         }
         return result;
     }
+
+    private ElementD<?,?> firstAtomicElementDescriptor() {
+        return ComposedD.unwrap(owner, ElementD.class).findFirst().orElseThrow(IllegalStateException::new);
+    }
+
+    private Groups computeDefaultSequence() {
+        final ElementD<?, ?> element = firstAtomicElementDescriptor();
+        Collection<Class<?>> redef = element.getGroupSequence();
+        if (redef == null) {
+            return GroupsComputer.DEFAULT_GROUPS;
+        }
+        final Class<?> t = this.beanClass.get();
+        if (redef.contains(Default.class)) {
+            Exceptions.raise(GroupDefinitionException::new, "%s for %s cannot include %s.class",
+                GroupSequence.class.getSimpleName(), t, Default.class.getSimpleName());
+        }
+        redef = redef.stream()
+                .map(substituteDefaultGroup())
+            .collect(Collectors.toCollection(LinkedHashSet::new));
+
+        return groupsComputer.computeGroups(redef);
+    }
+
+    private Set<Class<?>> computeAll(Class<?>[] groups) {
+        final Groups preliminaryGroups = groupsComputer.computeGroups(Stream.of(groups).map(substituteDefaultGroup()));
+        return allGroups(preliminaryGroups)
+            .flatMap(g -> g.isDefault() ? allGroups(getDefaultSequence.get()) : Stream.of(g)).map(Group::getGroup)
+            .collect(Collectors.toCollection(LinkedHashSet::new));
+    }
+
+    private UnaryOperator<Class<?>> substituteDefaultGroup() {
+        return t -> t.isAssignableFrom(beanClass.get()) ? Default.class : t;
+    }
 }

http://git-wip-us.apache.org/repos/asf/bval/blob/d7210b03/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 5f54279..e5e4db6 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
@@ -79,6 +79,10 @@ class MetadataReader {
                 .flatMap(e -> describe(e.getValue(), e.getKey(), meta)).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));
         }

http://git-wip-us.apache.org/repos/asf/bval/blob/d7210b03/bval-jsr/src/main/java/org/apache/bval/jsr/groups/GroupsComputer.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/groups/GroupsComputer.java b/bval-jsr/src/main/java/org/apache/bval/jsr/groups/GroupsComputer.java
index 30a47cd..3a895d4 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/groups/GroupsComputer.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/groups/GroupsComputer.java
@@ -24,10 +24,10 @@ import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import javax.validation.GroupDefinitionException;
 import javax.validation.GroupSequence;
@@ -50,7 +50,7 @@ public class GroupsComputer {
      * The default group array used in case any of the validate methods is
      * called without a group.
      */
-    private static final Groups DEFAULT_GROUPS;
+    public static final Groups DEFAULT_GROUPS;
     static {
         DEFAULT_GROUPS = new Groups();
         for (Class<?> g : DEFAULT_GROUP) {
@@ -82,7 +82,7 @@ public class GroupsComputer {
      * @return {@link Groups}
      */
     public final Groups computeCascadingGroups(Set<GroupConversionDescriptor> groupConversions, Class<?> group) {
-        final Groups preliminaryResult = computeGroups(group);
+        final Groups preliminaryResult = computeGroups(Stream.of(group));
 
         final Map<Class<?>, Class<?>> gcMap = groupConversions.stream()
             .collect(Collectors.toMap(GroupConversionDescriptor::getFrom, GroupConversionDescriptor::getTo));
@@ -91,9 +91,8 @@ public class GroupsComputer {
 
         // conversion of a simple (non-sequence) group:
         if (simpleGroup && gcMap.containsKey(group)) {
-            return computeGroups(gcMap.get(group));
+            return computeGroups(Stream.of(gcMap.get(group)));
         }
-
         final Groups result = new Groups();
 
         if (simpleGroup) {
@@ -107,7 +106,7 @@ public class GroupsComputer {
                 for (Group gg : seq) {
                     final Class<?> c = gg.getGroup();
                     if (gcMap.containsKey(c)) {
-                        final Groups convertedGroupExpansion = computeGroups(gcMap.get(c));
+                        final Groups convertedGroupExpansion = computeGroups(Stream.of(gcMap.get(c)));
                         if (convertedGroupExpansion.getSequences().isEmpty()) {
                             converted.add(gg);
                         } else {
@@ -123,35 +122,49 @@ public class GroupsComputer {
     }
 
     /**
-     * Main compute implementation.
+     * Compute groups from a {@link Collection}.
      * 
      * @param groups
      * @return {@link Groups}
      */
-    protected Groups computeGroups(Collection<Class<?>> groups) {
+    public Groups computeGroups(Collection<Class<?>> groups) {
         Validate.notNull(groups, "groups");
 
         if (groups.isEmpty() || Arrays.asList(DEFAULT_GROUP).equals(new ArrayList<>(groups))) {
             return DEFAULT_GROUPS;
         }
-        Exceptions.raiseIf(groups.stream().anyMatch(Objects::isNull), IllegalArgumentException::new,
-            "Null group specified");
+        return computeGroups(groups.stream());
+    }
+
+    /**
+     * Compute groups from a {@link Stream}.
+     * 
+     * @param groups
+     * @return {@link Groups}
+     */
+    public Groups computeGroups(Stream<Class<?>> groups) {
+        final Groups result = new Groups();
 
-        groups.forEach(g -> Exceptions.raiseUnless(g.isInterface(), ValidationException::new,
-            "A group must be an interface. %s is not.", g));
+        groups.peek(g -> {
+            Exceptions.raiseIf(g == null, IllegalArgumentException::new, "Null group specified");
 
-        final Groups chain = new Groups();
-        for (Class<?> clazz : groups) {
-            final GroupSequence anno = clazz.getAnnotation(GroupSequence.class);
+            Exceptions.raiseUnless(g.isInterface(), ValidationException::new,
+                "A group must be an interface. %s is not.", g);
+
+        }).forEach(g -> {
+            final GroupSequence anno = g.getAnnotation(GroupSequence.class);
             if (anno == null) {
-                chain.insertGroup(new Group(clazz));
-                insertInheritedGroups(clazz, chain);
-                continue;
+                result.insertGroup(new Group(g));
+                insertInheritedGroups(g, result);
+            } else {
+                result.insertSequence(
+                    resolvedSequences.computeIfAbsent(g, gg -> resolveSequence(gg, anno, new HashSet<>())));
             }
-            chain.insertSequence(
-                resolvedSequences.computeIfAbsent(clazz, g -> resolveSequence(g, anno, new HashSet<>())));
+        });
+        if (Arrays.asList(DEFAULT_GROUP).equals(result.getGroups()) && result.getSequences().isEmpty()) {
+            return DEFAULT_GROUPS;
         }
-        return chain;
+        return result;
     }
 
     private void insertInheritedGroups(Class<?> clazz, Groups chain) {

http://git-wip-us.apache.org/repos/asf/bval/blob/d7210b03/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 6542717..e161879 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
@@ -32,7 +32,6 @@ import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ConcurrentSkipListSet;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
-import java.util.function.Supplier;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 import java.util.stream.Stream;
@@ -49,7 +48,6 @@ import javax.validation.constraintvalidation.ValidationTarget;
 import javax.validation.groups.Default;
 import javax.validation.metadata.CascadableDescriptor;
 import javax.validation.metadata.ContainerDescriptor;
-import javax.validation.metadata.ElementDescriptor.ConstraintFinder;
 import javax.validation.metadata.PropertyDescriptor;
 import javax.validation.metadata.ValidateUnwrappedValue;
 import javax.validation.valueextraction.ValueExtractor;
@@ -113,7 +111,7 @@ public abstract class ValidationJob<T> {
         abstract Object getBean();
 
         void validateDescriptorConstraints(Class<?> group, Consumer<ConstraintViolation<T>> sink) {
-            constraintsFrom(descriptor.findConstraints().unorderedAndMatchingGroups(group))
+            constraintsFor(group)
                 .forEach(c -> unwrap(c.getValueUnwrapping()).forEach(f -> f.validate(c, sink)));
         }
 
@@ -133,14 +131,13 @@ public abstract class ValidationJob<T> {
             return Stream.of(this);
         }
 
-        @SuppressWarnings("unchecked")
-        private Stream<ConstraintD<?>> constraintsFrom(ConstraintFinder finder) {
-            // our ConstraintFinder implementation is a Stream supplier; reference without exposing it beyond its
-            // package:
-            if (finder instanceof Supplier<?>) {
-                return (Stream<ConstraintD<?>>) ((Supplier<?>) finder).get();
-            }
-            return finder.getConstraintDescriptors().stream().map(ConstraintD.class::cast);
+        private Stream<ConstraintD<?>> constraintsFor(Class<?> group) {
+            return descriptor.getConstraintDescriptors().stream().<ConstraintD<?>> map(ConstraintD.class::cast)
+                .filter(c -> Stream.of(group).anyMatch(t -> {
+                    final Set<Class<?>> constraintGroups = c.getGroups();
+                    return constraintGroups.contains(t)
+                        || constraintGroups.contains(Default.class) && c.getDeclaringClass().isAssignableFrom(t);
+                }));
         }
 
         @SuppressWarnings({ "rawtypes", "unchecked" })

http://git-wip-us.apache.org/repos/asf/bval/blob/d7210b03/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 a7262d0..3b41ec9 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
@@ -241,8 +241,8 @@ public class AnnotationsManager {
             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()).read(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));