Repository: bval Updated Branches: refs/heads/bv2 8689861e0 -> 4c1e1e0b3
more TCK satisfaction Project: http://git-wip-us.apache.org/repos/asf/bval/repo Commit: http://git-wip-us.apache.org/repos/asf/bval/commit/4c1e1e0b Tree: http://git-wip-us.apache.org/repos/asf/bval/tree/4c1e1e0b Diff: http://git-wip-us.apache.org/repos/asf/bval/diff/4c1e1e0b Branch: refs/heads/bv2 Commit: 4c1e1e0b34151d1a3101959a74ce15e26fec1801 Parents: 8689861 Author: Matt Benson <mben...@apache.org> Authored: Tue Mar 6 11:04:45 2018 -0600 Committer: Matt Benson <mben...@apache.org> Committed: Tue Mar 6 11:04:45 2018 -0600 ---------------------------------------------------------------------- .../apache/bval/jsr/descriptor/PropertyD.java | 8 +- .../apache/bval/jsr/job/ValidateProperty.java | 10 +-- .../bval/jsr/job/ValidateReturnValue.java | 2 +- .../org/apache/bval/jsr/job/ValidationJob.java | 43 ++++++++-- .../bval/jsr/metadata/ContainerElementKey.java | 51 +++++++----- .../jsr/metadata/ContainerElementKeyTest.java | 86 ++++++++++++++++++++ 6 files changed, 161 insertions(+), 39 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/bval/blob/4c1e1e0b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/PropertyD.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/PropertyD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/PropertyD.java index c7c2eff..54a69f0 100644 --- a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/PropertyD.java +++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/PropertyD.java @@ -20,14 +20,13 @@ import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.function.Supplier; import java.util.stream.Stream; import javax.validation.metadata.PropertyDescriptor; import org.apache.bval.jsr.GraphContext; import org.apache.bval.jsr.util.Methods; -import org.apache.bval.jsr.util.NodeImpl; +import org.apache.bval.jsr.util.PathImpl; import org.apache.bval.util.reflection.Reflection; import org.apache.commons.weaver.privilizer.Privilizing; import org.apache.commons.weaver.privilizer.Privilizing.CallTo; @@ -97,9 +96,10 @@ public abstract class PropertyD<E extends AnnotatedElement> extends CascadableCo @Override protected Stream<GraphContext> readImpl(GraphContext context) throws Exception { - final Supplier<NodeImpl> propertyNode = () -> new NodeImpl.PropertyNodeImpl(getPropertyName()); final Object value = getValue(context.getValue()); - return Stream.of(context.child(propertyNode.get(), value)); + final PathImpl p = PathImpl.copy(context.getPath()); + p.addProperty(getPropertyName()); + return Stream.of(context.child(p, value)); } public abstract Object getValue(Object parent) throws Exception; http://git-wip-us.apache.org/repos/asf/bval/blob/4c1e1e0b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateProperty.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateProperty.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateProperty.java index e3ec306..fa7e0f5 100644 --- a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateProperty.java +++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateProperty.java @@ -20,14 +20,15 @@ package org.apache.bval.jsr.job; import java.lang.reflect.Array; import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.Consumer; -import java.util.function.Predicate; import javax.validation.ConstraintViolation; import javax.validation.Path; @@ -231,12 +232,11 @@ public final class ValidateProperty<T> extends ValidationJob<T> { if (containerElements.size() == 1) { element = containerElements.iterator().next(); } else { - final Predicate<ContainerElementKey> wellKnown = - k -> k.represents(MAP_VALUE) || k.represents(ITERABLE_ELEMENT); + final Collection<TypeVariable<?>> wellKnown = Arrays.asList(MAP_VALUE, ITERABLE_ELEMENT); final Optional<ContainerElementTypeD> found = - containerElements.stream().map(ContainerElementTypeD.class::cast) - .filter(d -> d.getKey().getAssignableKeys().stream().anyMatch(wellKnown)).findFirst(); + containerElements.stream().<ContainerElementTypeD> map(ContainerElementTypeD.class::cast) + .filter(d -> wellKnown.stream().anyMatch(d.getKey()::represents)).findFirst(); if (!found.isPresent()) { return null; http://git-wip-us.apache.org/repos/asf/bval/blob/4c1e1e0b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java index 21126a6..eedb27c 100644 --- a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java +++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java @@ -111,7 +111,7 @@ public abstract class ValidateReturnValue<E extends Executable, T> extends Valid @Override protected Frame<?> computeBaseFrame() { - final PathImpl path = PathImpl.create(); + final PathImpl path = createBasePath(); path.addNode(new NodeImpl.ReturnValueNodeImpl()); return new SproutFrame<ReturnValueD<?, ?>>((ReturnValueD<?, ?>) describe().getReturnValueDescriptor(), http://git-wip-us.apache.org/repos/asf/bval/blob/4c1e1e0b/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 88fd40c..070bdc6 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 @@ -21,6 +21,8 @@ package org.apache.bval.jsr.job; import java.lang.reflect.Array; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; +import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.LinkedHashSet; @@ -33,6 +35,7 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentSkipListSet; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -55,9 +58,9 @@ import org.apache.bval.jsr.ApacheFactoryContext; import org.apache.bval.jsr.ConstraintViolationImpl; import org.apache.bval.jsr.GraphContext; import org.apache.bval.jsr.descriptor.BeanD; -import org.apache.bval.jsr.descriptor.CascadableContainerD; import org.apache.bval.jsr.descriptor.ComposedD; import org.apache.bval.jsr.descriptor.ConstraintD; +import org.apache.bval.jsr.descriptor.ContainerElementTypeD; import org.apache.bval.jsr.descriptor.ElementD; import org.apache.bval.jsr.descriptor.PropertyD; import org.apache.bval.jsr.groups.Group; @@ -68,6 +71,7 @@ import org.apache.bval.jsr.util.Proxies; import org.apache.bval.util.Exceptions; import org.apache.bval.util.Lazy; import org.apache.bval.util.ObjectUtils; +import org.apache.bval.util.ObjectWrapper; import org.apache.bval.util.Validate; import org.apache.bval.util.reflection.TypeUtils; @@ -239,9 +243,12 @@ public abstract class ValidationJob<T> { final TraversableResolver traversableResolver = validatorContext.getTraversableResolver(); final Stream<PropertyD<?>> reachableProperties = - properties.filter(d -> traversableResolver.isReachable(context.getValue(), - new NodeImpl.PropertyNodeImpl(d.getPropertyName()), getRootBeanClass(), context.getPath(), - d.getElementType())); + properties.filter(d -> { + final PathImpl p = PathImpl.copy(context.getPath()); + p.addProperty(d.getPropertyName()); + return traversableResolver.isReachable(context.getValue(), p.removeLeafNode(), getRootBeanClass(), + p, d.getElementType()); + }); return reachableProperties.flatMap( d -> d.read(context).filter(context -> !context.isRecursive()).map(child -> propertyFrame(d, child))) @@ -262,14 +269,32 @@ public abstract class ValidationJob<T> { @Override void recurse(Class<?> group, Consumer<ConstraintViolation<T>> sink) { @SuppressWarnings({ "unchecked", "rawtypes" }) - final Stream<CascadableContainerD<?, ?>> containerElements = - descriptor.getConstrainedContainerElementTypes().stream() - .flatMap(d -> ComposedD.unwrap(d, (Class) CascadableContainerD.class)); + final Stream<ContainerElementTypeD> containerElements = + descriptor.getConstrainedContainerElementTypes().stream() + .flatMap(d -> ComposedD.unwrap(d, (Class) ContainerElementTypeD.class)); + + final ObjectWrapper<Boolean> effectiveCascade = + new ObjectWrapper<>(Boolean.valueOf(descriptor.isCascaded())); - containerElements.flatMap(d -> d.read(context).map(child -> new SproutFrame<>(this, d, child))) + // cascade legacy containers the old way by filtering them out here: + + final Collection<TypeVariable<?>> wellKnown = Arrays.asList(ITERABLE_ELEMENT, MAP_VALUE); + + final Predicate<? super ContainerElementTypeD> isNotLegacyContainer = d -> { + final boolean cascadedLegacyContainer = + d.isCascaded() && wellKnown.stream().anyMatch(d.getKey()::represents); + + if (cascadedLegacyContainer) { + effectiveCascade.accept(Boolean.TRUE); + } + return !cascadedLegacyContainer; + }; + + containerElements.filter(isNotLegacyContainer) + .flatMap(d -> d.read(context).map(child -> new SproutFrame<>(this, d, child))) .forEach(f -> f.process(group, sink)); - if (!descriptor.isCascaded()) { + if (!effectiveCascade.get().booleanValue()) { return; } if (descriptor instanceof PropertyDescriptor) { http://git-wip-us.apache.org/repos/asf/bval/blob/4c1e1e0b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ContainerElementKey.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ContainerElementKey.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ContainerElementKey.java index 322a4ef..59cc90e 100644 --- a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ContainerElementKey.java +++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ContainerElementKey.java @@ -27,6 +27,7 @@ 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; @@ -143,30 +144,40 @@ public class ContainerElementKey implements Comparable<ContainerElementKey> { public Set<ContainerElementKey> getAssignableKeys() { final Lazy<Set<ContainerElementKey>> result = new Lazy<>(LinkedHashSet::new); - - if (typeArgumentIndex != null) { - final TypeVariable<?> var = containerClass.getTypeParameters()[typeArgumentIndex.intValue()]; - - Stream - .concat(Stream.of(containerClass.getAnnotatedSuperclass()), - Stream.of(containerClass.getAnnotatedInterfaces())) - .filter(AnnotatedParameterizedType.class::isInstance).map(AnnotatedParameterizedType.class::cast) - .forEach(t -> { - final AnnotatedType[] args = t.getAnnotatedActualTypeArguments(); - - for (int i = 0; i < args.length; i++) { - if (args[i].getType().equals(var)) { - result.get().add(new ContainerElementKey(t, Integer.valueOf(i))); - } - } - }); - } + hierarchy(result.consumer(Set::add)); return result.optional().map(Collections::unmodifiableSet).orElseGet(Collections::emptySet); } public boolean represents(TypeVariable<?> var) { - return Optional.ofNullable(typeArgumentIndex) - .map(index -> getContainerClass().getTypeParameters()[index.intValue()]).filter(var::equals).isPresent(); + 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) { + if (typeArgumentIndex == null) { + return; + } + final TypeVariable<?> 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++) { + if (args[i].getType().equals(var)) { + round.get().add(new ContainerElementKey(t, Integer.valueOf(i))); + } + } + }); + + round.optional().ifPresent(s -> { + s.forEach(sink); + s.forEach(k -> k.hierarchy(sink)); + }); } private String containerClassName() { http://git-wip-us.apache.org/repos/asf/bval/blob/4c1e1e0b/bval-jsr/src/test/java/org/apache/bval/jsr/metadata/ContainerElementKeyTest.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/test/java/org/apache/bval/jsr/metadata/ContainerElementKeyTest.java b/bval-jsr/src/test/java/org/apache/bval/jsr/metadata/ContainerElementKeyTest.java new file mode 100644 index 0000000..b33b928 --- /dev/null +++ b/bval-jsr/src/test/java/org/apache/bval/jsr/metadata/ContainerElementKeyTest.java @@ -0,0 +1,86 @@ +/* + * 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 org.junit.Assert.*; + +import java.lang.reflect.Field; +import java.lang.reflect.TypeVariable; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; + +public class ContainerElementKeyTest { + public static abstract class HasList { + public List<String> strings; + } + + private Field stringsField; + + @Before + public void setup() throws Exception { + stringsField = HasList.class.getField("strings"); + } + + @Test + public void testBasic() { + final ContainerElementKey containerElementKey = + new ContainerElementKey(stringsField.getAnnotatedType(), Integer.valueOf(0)); + + assertEquals(List.class, containerElementKey.getContainerClass()); + assertEquals(0, containerElementKey.getTypeArgumentIndex().intValue()); + assertEquals(String.class, containerElementKey.getAnnotatedType().getType()); + } + + @Test + public void testAssignableKeys() { + final ContainerElementKey containerElementKey = + new ContainerElementKey(stringsField.getAnnotatedType(), Integer.valueOf(0)); + + final Iterator<ContainerElementKey> iterator = containerElementKey.getAssignableKeys().iterator(); + { + assertTrue(iterator.hasNext()); + final ContainerElementKey assignableKey = iterator.next(); + assertEquals(Collection.class, assignableKey.getContainerClass()); + assertEquals(0, assignableKey.getTypeArgumentIndex().intValue()); + assertTrue(assignableKey.getAnnotatedType().getType() instanceof TypeVariable<?>); + } + { + assertTrue(iterator.hasNext()); + final ContainerElementKey assignableKey = iterator.next(); + assertEquals(Iterable.class, assignableKey.getContainerClass()); + assertEquals(0, assignableKey.getTypeArgumentIndex().intValue()); + assertTrue(assignableKey.getAnnotatedType().getType() instanceof TypeVariable<?>); + } + assertFalse(iterator.hasNext()); + } + + @Test + public void testTypeVariableInheritance() { + final ContainerElementKey containerElementKey = + new ContainerElementKey(stringsField.getAnnotatedType(), Integer.valueOf(0)); + + assertTrue(containerElementKey.represents(List.class.getTypeParameters()[0])); + assertTrue(containerElementKey.represents(Collection.class.getTypeParameters()[0])); + assertTrue(containerElementKey.represents(Iterable.class.getTypeParameters()[0])); + } +}