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/02/27 23:45:15 UTC
[1/4] bval git commit: default method
Repository: bval
Updated Branches:
refs/heads/bv2 0e874301a -> faec747db
default method
Project: http://git-wip-us.apache.org/repos/asf/bval/repo
Commit: http://git-wip-us.apache.org/repos/asf/bval/commit/09152bc1
Tree: http://git-wip-us.apache.org/repos/asf/bval/tree/09152bc1
Diff: http://git-wip-us.apache.org/repos/asf/bval/diff/09152bc1
Branch: refs/heads/bv2
Commit: 09152bc18bfee450f9a8af783933f7ae692f3aa8
Parents: 0e87430
Author: Matt Benson <mb...@apache.org>
Authored: Mon Feb 26 13:31:39 2018 -0600
Committer: Matt Benson <mb...@apache.org>
Committed: Mon Feb 26 13:31:39 2018 -0600
----------------------------------------------------------------------
.../org/apache/bval/constraints/FrenchZipcodeValidator.java | 5 -----
1 file changed, 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/bval/blob/09152bc1/bval-jsr/src/test/java/org/apache/bval/constraints/FrenchZipcodeValidator.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/test/java/org/apache/bval/constraints/FrenchZipcodeValidator.java b/bval-jsr/src/test/java/org/apache/bval/constraints/FrenchZipcodeValidator.java
index 542882c..d6384f1 100644
--- a/bval-jsr/src/test/java/org/apache/bval/constraints/FrenchZipcodeValidator.java
+++ b/bval-jsr/src/test/java/org/apache/bval/constraints/FrenchZipcodeValidator.java
@@ -26,11 +26,6 @@ import javax.validation.ConstraintValidatorContext;
*/
public class FrenchZipcodeValidator implements ConstraintValidator<FrenchZipCode, Object> {
@Override
- public void initialize(FrenchZipCode constraintAnnotation) {
- // do nothing
- }
-
- @Override
public boolean isValid(Object object, ConstraintValidatorContext validationContext) {
return null != object;
}
[4/4] bval git commit: initial BVal 2 implementation of method
inheritance rules
Posted by mb...@apache.org.
initial BVal 2 implementation of method inheritance rules
Project: http://git-wip-us.apache.org/repos/asf/bval/repo
Commit: http://git-wip-us.apache.org/repos/asf/bval/commit/faec747d
Tree: http://git-wip-us.apache.org/repos/asf/bval/tree/faec747d
Diff: http://git-wip-us.apache.org/repos/asf/bval/diff/faec747d
Branch: refs/heads/bv2
Commit: faec747db9653ac9cce3c253ffa09a9d89d0adf7
Parents: f2acb64
Author: Matt Benson <mb...@apache.org>
Authored: Tue Feb 27 17:44:59 2018 -0600
Committer: Matt Benson <mb...@apache.org>
Committed: Tue Feb 27 17:44:59 2018 -0600
----------------------------------------------------------------------
.../bval/jsr/descriptor/DescriptorManager.java | 7 +-
.../bval/jsr/descriptor/MetadataReader.java | 25 +-
.../bval/jsr/metadata/CompositeBuilder.java | 134 +++++++--
.../bval/jsr/metadata/HierarchyBuilder.java | 291 +++++++++++++++----
.../org/apache/bval/jsr/metadata/Liskov.java | 197 +++++++++++++
.../java/org/apache/bval/jsr/metadata/Meta.java | 25 +-
.../java/org/apache/bval/jsr/util/Methods.java | 10 +
7 files changed, 595 insertions(+), 94 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/bval/blob/faec747d/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 01a1b5c..12c9a55 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
@@ -68,9 +68,10 @@ public class DescriptorManager {
private MetadataBuilder.ForBean builder(Class<?> beanClass) {
final MetadataBuilder.ForBean primaryBuilder =
- new HierarchyBuilder(reflectionBuilder::forBean).forBean(beanClass);
+ new HierarchyBuilder(validatorFactory, reflectionBuilder::forBean).forBean(beanClass);
- final MetadataBuilder.ForBean customBuilder = new HierarchyBuilder(this::customBuilder).forBean(beanClass);
+ final MetadataBuilder.ForBean customBuilder =
+ new HierarchyBuilder(validatorFactory, this::customBuilder).forBean(beanClass);
return customBuilder.isEmpty() ? primaryBuilder : DualBuilder.forBean(primaryBuilder, customBuilder);
}
@@ -86,6 +87,6 @@ public class DescriptorManager {
return customBuilders.get(0);
}
return customBuilders.stream()
- .collect(CompositeBuilder.with(AnnotationBehaviorMergeStrategy.consensus()).compose());
+ .collect(CompositeBuilder.with(validatorFactory, AnnotationBehaviorMergeStrategy.consensus()).compose());
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/faec747d/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 77cf9fc..2e9a31f 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
@@ -39,9 +39,12 @@ import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
+import javax.validation.ConstraintDeclarationException;
import javax.validation.GroupDefinitionException;
import javax.validation.GroupSequence;
import javax.validation.ParameterNameProvider;
+import javax.validation.Valid;
+import javax.validation.groups.ConvertGroup;
import javax.validation.groups.Default;
import javax.validation.metadata.PropertyDescriptor;
import javax.validation.metadata.Scope;
@@ -100,10 +103,8 @@ class MetadataReader {
});
beanBuilder.getGetters(meta).forEach((g, builder) -> {
- final Method getter = Reflection.find(meta.getHost(), t -> {
- return Stream.of(Reflection.getDeclaredMethods(t)).filter(Methods::isGetter)
- .filter(m -> g.equals(Methods.propertyName(m))).findFirst().orElse(null);
- });
+ final Method getter = Methods.getter(meta.getHost(), g);
+
Exceptions.raiseIf(getter == null, IllegalStateException::new,
"Getter method for property %s not found", g);
@@ -199,7 +200,21 @@ class MetadataReader {
}
Set<GroupConversion> getGroupConversions() {
- return builder.getGroupConversions(meta);
+ final Set<GroupConversion> groupConversions = builder.getGroupConversions(meta);
+ Exceptions.raiseUnless(groupConversions.isEmpty() || isCascaded(), ConstraintDeclarationException::new,
+ "@%s declared without @%s on %s", ConvertGroup.class.getSimpleName(), Valid.class.getSimpleName(),
+ meta.describeHost());
+
+ Exceptions.raiseIf(
+ groupConversions.stream().map(GroupConversion::getFrom).distinct().count() < groupConversions.size(),
+ ConstraintDeclarationException::new, "%s has duplicate 'from' group conversions", meta.describeHost());
+
+ groupConversions.stream().map(GroupConversion::getFrom)
+ .forEach(f -> Exceptions.raiseIf(f.isAnnotationPresent(GroupSequence.class),
+ ConstraintDeclarationException::new,
+ "Invalid group conversion declared on %s from group sequence %s", meta.describeHost(), f));
+
+ return groupConversions;
}
Set<ContainerElementTypeD> getContainerElementTypes(CascadableContainerD<?, ?> parent) {
http://git-wip-us.apache.org/repos/asf/bval/blob/faec747d/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 3aed1d0..56dd1f8 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
@@ -30,17 +30,24 @@ 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 javax.validation.metadata.Scope;
+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 {
@@ -60,14 +67,17 @@ public class CompositeBuilder {
}
<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).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(mappedDelegates);
+ 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));
}
@@ -88,22 +98,34 @@ public class CompositeBuilder {
@Override
public Map<String, MetadataBuilder.ForContainer<Field>> getFields(Meta<Class<?>> meta) {
- return merge(b -> b.getFields(meta), CompositeBuilder.ForContainer::new);
+ return merge(b -> b.getFields(meta), (f, l) -> {
+ final Field fld = Reflection.find(meta.getHost(), t -> Reflection.getDeclaredField(t, f));
+ Exceptions.raiseIf(fld == null, 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<?>> meta) {
- return merge(b -> b.getGetters(meta), CompositeBuilder.ForContainer::new);
+ return merge(b -> b.getGetters(meta), (g, l) -> {
+ final Method getter = Methods.getter(meta.getHost(), g);
+ Exceptions.raiseIf(getter == null, 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<?>>> getConstructors(Meta<Class<?>> meta) {
- return merge(b -> b.getConstructors(meta), CompositeBuilder.ForExecutable::new);
+ return merge(b -> b.getConstructors(meta),
+ d -> new CompositeBuilder.ForExecutable<>(d, ParameterNameProvider::getParameterNames));
}
@Override
public Map<Signature, MetadataBuilder.ForExecutable<Method>> getMethods(Meta<Class<?>> meta) {
- return merge(b -> b.getMethods(meta), CompositeBuilder.ForExecutable::new);
+ return merge(b -> b.getMethods(meta),
+ d -> new CompositeBuilder.ForExecutable<>(d, ParameterNameProvider::getParameterNames));
}
}
@@ -138,7 +160,7 @@ public class CompositeBuilder {
}
}
- private class ForContainer<DELEGATE extends MetadataBuilder.ForContainer<E>, E extends AnnotatedElement>
+ class ForContainer<DELEGATE extends MetadataBuilder.ForContainer<E>, E extends AnnotatedElement>
extends CompositeBuilder.ForElement<DELEGATE, E> implements MetadataBuilder.ForContainer<E> {
ForContainer(List<DELEGATE> delegates) {
@@ -146,34 +168,68 @@ public class CompositeBuilder {
}
@Override
- public final boolean isCascade(Meta<E> meta) {
+ public boolean isCascade(Meta<E> meta) {
return delegates.stream().anyMatch(d -> d.isCascade(meta));
}
@Override
- public final Set<GroupConversion> getGroupConversions(Meta<E> meta) {
+ public Set<GroupConversion> getGroupConversions(Meta<E> meta) {
return delegates.stream().map(d -> d.getGroupConversions(meta)).flatMap(Collection::stream)
.collect(ToUnmodifiable.set());
}
@Override
- public final Map<ContainerElementKey, MetadataBuilder.ForContainer<AnnotatedType>> getContainerElementTypes(
+ public Map<ContainerElementKey, MetadataBuilder.ForContainer<AnnotatedType>> getContainerElementTypes(
Meta<E> meta) {
- return merge(b -> b.getContainerElementTypes(meta), CompositeBuilder.ForContainer::new);
+ return merge(b -> b.getContainerElementTypes(meta),
+ (k, l) -> forContainer(l, new Meta.ForContainerElement(meta, k), ElementKind.CONTAINER_ELEMENT));
}
}
- private class ForExecutable<DELEGATE extends MetadataBuilder.ForExecutable<E>, E extends Executable>
+ class ForReturnValue<E extends Executable> implements MetadataBuilder.ForContainer<E> {
+ private final MetadataBuilder.ForContainer<E> delegate;
+
+ ForReturnValue(MetadataBuilder.ForContainer<E> delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public Annotation[] getDeclaredConstraints(Meta<E> meta) {
+ return delegate.getDeclaredConstraints(meta);
+ }
+
+ @Override
+ public boolean isCascade(Meta<E> meta) {
+ return delegate.isCascade(meta);
+ }
+
+ @Override
+ public Set<GroupConversion> getGroupConversions(Meta<E> meta) {
+ return delegate.getGroupConversions(meta);
+ }
+
+ @Override
+ public Map<ContainerElementKey, MetadataBuilder.ForContainer<AnnotatedType>> getContainerElementTypes(
+ Meta<E> meta) {
+ return delegate.getContainerElementTypes(meta);
+ }
+ }
+
+ class ForExecutable<DELEGATE extends MetadataBuilder.ForExecutable<E>, E extends Executable>
extends Delegator<DELEGATE> implements MetadataBuilder.ForExecutable<E> {
- ForExecutable(List<DELEGATE> delegates) {
+ 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 new CompositeBuilder.ForContainer<>(
- delegates.stream().map(d -> d.getReturnValue(meta)).collect(Collectors.toList()));
+ public ForReturnValue<E> getReturnValue(Meta<E> meta) {
+ return new ForReturnValue<>(CompositeBuilder.this.forContainer(
+ delegates.stream().map(d -> d.getReturnValue(meta)).collect(Collectors.toList()), meta,
+ ElementKind.RETURN_VALUE));
}
@Override
@@ -185,35 +241,53 @@ public class CompositeBuilder {
Validate.validState(parameterCounts.size() == 1, "Mismatched parameter counts: %s", parameterCounts);
final int parameterCount = parameterCounts.iterator().next().intValue();
- return IntStream.range(0, parameterCount)
- .mapToObj(n -> new CompositeBuilder.ForContainer<>(
- parameterLists.stream().map(l -> l.get(n)).collect(Collectors.toList())))
- .collect(ToUnmodifiable.list());
+ 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 new CompositeBuilder.ForElement<MetadataBuilder.ForElement<E>, E>(
- delegates.stream().map(d -> d.getCrossParameter(meta)).collect(Collectors.toList()));
+ return forCrossParameter(
+ delegates.stream().map(d -> d.getCrossParameter(meta)).collect(Collectors.toList()), meta);
}
}
- public static CompositeBuilder with(AnnotationBehaviorMergeStrategy annotationBehaviorStrategy) {
- return new CompositeBuilder(annotationBehaviorStrategy);
+ public static CompositeBuilder with(ApacheValidatorFactory validatorFactory,
+ AnnotationBehaviorMergeStrategy annotationBehaviorStrategy) {
+ return new CompositeBuilder(validatorFactory, annotationBehaviorStrategy);
}
private final AnnotationBehaviorMergeStrategy annotationBehaviorStrategy;
+ protected final ApacheValidatorFactory validatorFactory;
- CompositeBuilder(AnnotationBehaviorMergeStrategy annotationBehaviorMergeStrategy) {
+ CompositeBuilder(ApacheValidatorFactory validatorFactory,
+ AnnotationBehaviorMergeStrategy annotationBehaviorMergeStrategy) {
super();
this.annotationBehaviorStrategy =
Validate.notNull(annotationBehaviorMergeStrategy, "annotationBehaviorMergeStrategy");
+ this.validatorFactory = Validate.notNull(validatorFactory, "validatorFactory");
}
public Collector<MetadataBuilder.ForBean, ?, MetadataBuilder.ForBean> compose() {
return Collectors.collectingAndThen(Collectors.toList(), CompositeBuilder.ForBean::new);
}
+ 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());
+
+ Exceptions.raiseUnless(parameterNames.size() == parameters.length, 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<Scope, Annotation[]> getConstraintsByScope(
CompositeBuilder.ForElement<? extends MetadataBuilder.ForElement<E>, E> composite, Meta<E> meta) {
return Collections.singletonMap(Scope.LOCAL_ELEMENT, composite.getDeclaredConstraints(meta));
@@ -226,4 +300,14 @@ public class CompositeBuilder {
"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);
+ }
}
http://git-wip-us.apache.org/repos/asf/bval/blob/faec747d/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 9cac057..a900501 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
@@ -18,21 +18,35 @@ 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.EnumMap;
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.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+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;
+import org.apache.bval.jsr.util.Methods;
+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;
@@ -41,78 +55,217 @@ import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
@Privilizing(@CallTo(Reflection.class))
public class HierarchyBuilder extends CompositeBuilder {
- private static abstract class HierarchyDelegate<T> {
+ static abstract class HierarchyDelegate<E extends AnnotatedElement, T> {
final T delegate;
+ final Meta<E> hierarchyElement;
- HierarchyDelegate(T delegate) {
+ HierarchyDelegate(T delegate, Meta<E> hierarchyElement) {
super();
this.delegate = Validate.notNull(delegate, "delegate");
+ this.hierarchyElement = Validate.notNull(hierarchyElement, "hierarchyElement");
}
- static class ForBean extends HierarchyDelegate<MetadataBuilder.ForBean> implements MetadataBuilder.ForBean {
- final Meta<Class<?>> hierarchyType;
+ Meta<E> getHierarchyElement() {
+ return hierarchyElement;
+ }
+ }
- ForBean(MetadataBuilder.ForBean delegate, Class<?> hierarchyType) {
- super(delegate);
- this.hierarchyType = new Meta.ForClass(hierarchyType);
- }
+ static abstract class ElementDelegate<E extends AnnotatedElement, T extends MetadataBuilder.ForElement<E>>
+ extends HierarchyDelegate<E, T> implements MetadataBuilder.ForElement<E> {
- @Override
- public MetadataBuilder.ForClass getClass(Meta<Class<?>> meta) {
- return new HierarchyDelegate.ForClass(delegate.getClass(hierarchyType), hierarchyType);
- }
+ ElementDelegate(T delegate, Meta<E> hierarchyElement) {
+ super(delegate, hierarchyElement);
+ }
+
+ Annotation[] getDeclaredConstraints() {
+ return delegate.getDeclaredConstraints(hierarchyElement);
+ }
- @Override
- public Map<String, MetadataBuilder.ForContainer<Field>> getFields(Meta<Class<?>> meta) {
- return delegate.getFields(hierarchyType);
- }
+ @Override
+ public final Annotation[] getDeclaredConstraints(Meta<E> meta) {
+ return getDeclaredConstraints();
+ }
+ }
- @Override
- public Map<String, MetadataBuilder.ForContainer<Method>> getGetters(Meta<Class<?>> meta) {
- return delegate.getGetters(hierarchyType);
- }
+ private class BeanDelegate extends HierarchyDelegate<Class<?>, MetadataBuilder.ForBean>
+ implements MetadataBuilder.ForBean {
- @SuppressWarnings("unlikely-arg-type")
- @Override
- public Map<Signature, MetadataBuilder.ForExecutable<Constructor<?>>> getConstructors(Meta<Class<?>> meta) {
- // suppress hierarchical ctors:
- return hierarchyType.equals(meta.getHost()) ? delegate.getConstructors(hierarchyType)
- : Collections.emptyMap();
- }
+ BeanDelegate(MetadataBuilder.ForBean delegate, Class<?> hierarchyType) {
+ super(delegate, new Meta.ForClass(hierarchyType));
+ }
- @Override
- public Map<Signature, MetadataBuilder.ForExecutable<Method>> getMethods(Meta<Class<?>> meta) {
- final Map<Signature, MetadataBuilder.ForExecutable<Method>> m = delegate.getMethods(hierarchyType);
+ @Override
+ public MetadataBuilder.ForClass getClass(Meta<Class<?>> meta) {
+ return new ClassDelegate(delegate.getClass(hierarchyElement), hierarchyElement);
+ }
- return m;
- }
+ @Override
+ public Map<String, MetadataBuilder.ForContainer<Field>> getFields(Meta<Class<?>> meta) {
+ return delegate.getFields(hierarchyElement);
+ }
+
+ @Override
+ public Map<Signature, MetadataBuilder.ForExecutable<Constructor<?>>> getConstructors(Meta<Class<?>> meta) {
+ // ignore hierarchical ctors:
+ return hierarchyElement.equals(meta) ? delegate.getConstructors(hierarchyElement) : Collections.emptyMap();
}
- static class ForClass extends HierarchyDelegate<MetadataBuilder.ForClass> implements MetadataBuilder.ForClass {
+ @Override
+ public Map<String, MetadataBuilder.ForContainer<Method>> getGetters(Meta<Class<?>> meta) {
+ final Map<String, MetadataBuilder.ForContainer<Method>> getters = delegate.getGetters(hierarchyElement);
+ final Map<String, MetadataBuilder.ForContainer<Method>> result = new LinkedHashMap<>();
- final Meta<Class<?>> hierarchyType;
+ getters.forEach((k, v) -> {
+ final Method getter = Methods.getter(hierarchyElement.getHost(), k);
- ForClass(MetadataBuilder.ForClass delegate, Meta<Class<?>> hierarchyType) {
- super(delegate);
- this.hierarchyType = hierarchyType;
- }
+ Exceptions.raiseIf(getter == null, IllegalStateException::new,
+ "delegate builder specified unknown getter");
- @Override
- public Annotation[] getDeclaredConstraints(Meta<Class<?>> meta) {
- return delegate.getDeclaredConstraints(hierarchyType);
+ result.put(k, new ContainerDelegate<Method>(v, new Meta.ForMethod(getter)));
+ });
+ return result;
+ }
+
+ @Override
+ public Map<Signature, MetadataBuilder.ForExecutable<Method>> getMethods(Meta<Class<?>> 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<>();
+ methods
+ .forEach((k, v) -> result.put(k,
+ new ExecutableDelegate<>(v, new Meta.ForMethod(
+ Reflection.getDeclaredMethod(hierarchyElement.getHost(), k.getName(), k.getParameterTypes())),
+ ParameterNameProvider::getParameterNames)));
+ return result;
+ }
+ }
+
+ private class ClassDelegate extends ElementDelegate<Class<?>, MetadataBuilder.ForClass>
+ implements MetadataBuilder.ForClass {
+
+ ClassDelegate(MetadataBuilder.ForClass delegate, Meta<Class<?>> hierarchyType) {
+ super(delegate, hierarchyType);
+ }
+
+ @Override
+ public List<Class<?>> getGroupSequence(Meta<Class<?>> meta) {
+ return delegate.getGroupSequence(hierarchyElement);
+ }
+ }
+
+ 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<>();
- @Override
- public List<Class<?>> getGroupSequence(Meta<Class<?>> meta) {
- return delegate.getGroupSequence(hierarchyType);
+ containerElementTypes.forEach((k, v) -> {
+ result.put(k, new ContainerDelegate<>(v, new Meta.ForContainerElement(hierarchyElement, k)));
+ });
+ return result;
+ }
+ }
+
+ 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);
+
+ Exceptions.raiseUnless(metaParameters.size() == parameterDelegates.size(), 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);
+ }
+ }
+
+ 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(Function<Class<?>, MetadataBuilder.ForBean> getBeanBuilder) {
- super(AnnotationBehaviorMergeStrategy.first());
+ public HierarchyBuilder(ApacheValidatorFactory validatorFactory,
+ Function<Class<?>, MetadataBuilder.ForBean> getBeanBuilder) {
+ super(validatorFactory, AnnotationBehaviorMergeStrategy.first());
this.getBeanBuilder = Validate.notNull(getBeanBuilder, "getBeanBuilder function was null");
}
@@ -126,16 +279,13 @@ public class HierarchyBuilder extends CompositeBuilder {
*/
delegates.add(Optional.of(beanClass).map(getBeanBuilder).orElseGet(() -> EmptyBuilder.instance().forBean()));
- // iterate the hierarchy, skipping the first (i.e. beanClass handled
- // above)
+ // iterate the hierarchy, skipping the first (i.e. beanClass handled above)
final Iterator<Class<?>> hierarchy = Reflection.hierarchy(beanClass, Interfaces.INCLUDE).iterator();
hierarchy.next();
- // skip Object.class; skip null/empty hierarchy builders, mapping others
- // to HierarchyDelegate
- hierarchy
- .forEachRemaining(t -> Optional.of(t).filter(Predicate.isEqual(Object.class).negate()).map(getBeanBuilder)
- .filter(b -> !b.isEmpty()).map(b -> new HierarchyDelegate.ForBean(b, t)).ifPresent(delegates::add));
+ // skip Object.class; skip null/empty hierarchy builders, mapping others to BeanDelegate
+ hierarchy.forEachRemaining(t -> Optional.of(t).filter(Predicate.isEqual(Object.class).negate())
+ .map(getBeanBuilder).filter(b -> !b.isEmpty()).map(b -> new BeanDelegate(b, t)).ifPresent(delegates::add));
// if we have nothing but empty builders (which should only happen for
// absent custom metadata), return empty:
@@ -166,4 +316,39 @@ public class HierarchyBuilder extends CompositeBuilder {
protected List<Class<?>> getGroupSequence(CompositeBuilder.ForClass composite, Meta<Class<?>> 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);
+ }
}
http://git-wip-us.apache.org/repos/asf/bval/blob/faec747d/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/Liskov.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/Liskov.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/Liskov.java
new file mode 100644
index 0000000..74bd8da
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/Liskov.java
@@ -0,0 +1,197 @@
+/*
+ * 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.EnumSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+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 org.apache.bval.jsr.metadata.HierarchyBuilder.ContainerDelegate;
+import org.apache.bval.jsr.metadata.HierarchyBuilder.HierarchyDelegate;
+import org.apache.bval.jsr.metadata.HierarchyBuilder.ElementDelegate;
+import org.apache.bval.util.Exceptions;
+import org.apache.commons.lang3.Validate;
+
+class Liskov {
+ //@formatter:off
+ private enum ValidationElement {
+ constraints, cascades, groupConversions;
+ }
+
+ 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.toSet());
+
+ 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(List<? extends ContainerDelegate<?>> delegates, ElementKind elementKind) {
+ if (Validate.notNull(delegates, "delegates").isEmpty()) {
+ return;
+ }
+ if (elementKind == ElementKind.CONTAINER_ELEMENT) {
+ elementKind = getContainer(delegates.get(0).getHierarchyElement());
+ }
+ switch (Validate.notNull(elementKind, "elementKind")) {
+ case PROPERTY:
+ break;
+ case RETURN_VALUE:
+ noRedeclarationOfReturnValueCascading(delegates);
+ break;
+ case PARAMETER:
+ noStrengtheningOfPreconditions(delegates, detectConstraints(), detectCascading(), detectGroupConversion());
+ break;
+ default:
+ Exceptions.raise(IllegalArgumentException::new, "Cannot validate %s.%s as %s",
+ ElementKind.class.getSimpleName(), elementKind, ContainerDelegate.class.getSimpleName());
+ }
+ }
+
+ static void validateCrossParameterHierarchy(List<? extends ElementDelegate<?, ?>> delegates) {
+ if (Validate.notNull(delegates, "delegates").isEmpty()) {
+ return;
+ }
+ noStrengtheningOfPreconditions(delegates, detectConstraints());
+ }
+
+ private static ElementKind getContainer(Meta<?> meta) {
+ Meta<?> m = meta;
+ while (m.getElementType() == ElementType.TYPE_USE) {
+ m = ((Meta.ForContainerElement) m).getParent();
+ }
+ switch (m.getElementType()) {
+ case METHOD:
+ return ElementKind.RETURN_VALUE;
+ case PARAMETER:
+ return ElementKind.PARAMETER;
+ default:
+ return ElementKind.PROPERTY;
+ }
+ }
+
+ private static void noRedeclarationOfReturnValueCascading(List<? extends ContainerDelegate<?>> delegates) {
+ final Set<Meta<?>> markedForCascade = delegates.stream().filter(ContainerDelegate::isCascade)
+ .map(HierarchyDelegate::getHierarchyElement).collect(Collectors.toCollection(LinkedHashSet::new));
+
+ Exceptions.raiseIf(markedForCascade.size() > 1, ConstraintDeclarationException::new,
+ "Multiple return values marked @%s in same hierarchy: %s", Valid.class.getSimpleName(), markedForCascade);
+ }
+
+ @SafeVarargs
+ private static <D extends ElementDelegate<?, ?>> void noStrengtheningOfPreconditions(List<? extends D> delegates,
+ Function<? super D, ValidationElement>... detectors) {
+
+ final Map<Meta<?>, Set<ValidationElement>> detectedValidationElements = new LinkedHashMap<>();
+ delegates.forEach(d -> {
+ detectedValidationElements.put(d.getHierarchyElement(),
+ 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;
+ }
+ for (StrengtheningIssue s : StrengtheningIssue.values()) {
+ s.check(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 Liskov() {
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/faec747d/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/Meta.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/Meta.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/Meta.java
index dbcaeeb..ece48b0 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/Meta.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/Meta.java
@@ -196,8 +196,8 @@ public abstract class Meta<E extends AnnotatedElement> {
}
@Override
- public String toString() {
- return String.format("%s(%s of %s)", getStringPrefix(), getName(), getHost());
+ public String describeHost() {
+ return String.format("%s of %s", getName(), getHost());
}
}
@@ -233,6 +233,11 @@ public abstract class Meta<E extends AnnotatedElement> {
public String getName() {
return name;
}
+
+ @Override
+ public String describeHost() {
+ return String.format("%s of %s", getName(), getHost().getDeclaringExecutable());
+ }
}
public static class ForContainerElement extends Meta<AnnotatedType> {
@@ -271,8 +276,12 @@ public abstract class Meta<E extends AnnotatedElement> {
}
@Override
- public String toString() {
- return String.format("%s(%s of %s)", getStringPrefix(), key, getHost());
+ public String describeHost() {
+ return String.format("%s of %s", key, parent);
+ }
+
+ public Meta<?> getParent() {
+ return parent;
}
}
@@ -311,12 +320,12 @@ public abstract class Meta<E extends AnnotatedElement> {
}
@Override
- public String toString() {
- return String.format("%s(%s)", getStringPrefix(), host);
+ public final String toString() {
+ return String.format("%s.%s(%s)", Meta.class.getSimpleName(), getClass().getSimpleName(), describeHost());
}
- protected String getStringPrefix() {
- return Meta.class.getSimpleName() + '.' + getClass().getSimpleName();
+ public String describeHost() {
+ return host.toString();
}
@Override
http://git-wip-us.apache.org/repos/asf/bval/blob/faec747d/bval-jsr/src/main/java/org/apache/bval/jsr/util/Methods.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/Methods.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/Methods.java
index 9f98311..4b5ce45 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/util/Methods.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/Methods.java
@@ -18,9 +18,14 @@ package org.apache.bval.jsr.util;
import java.beans.Introspector;
import java.lang.reflect.Method;
+import java.util.stream.Stream;
import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.Reflection;
+import org.apache.commons.weaver.privilizer.Privilizing;
+import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
+@Privilizing(@CallTo(Reflection.class))
public final class Methods {
public static boolean isGetter(Method m) {
if (m.getParameterCount() > 0) {
@@ -40,6 +45,11 @@ public final class Methods {
return Introspector.decapitalize(suffix);
}
+ public static Method getter(Class<?> clazz, String property) {
+ return Reflection.find(clazz, t -> Stream.of(Reflection.getDeclaredMethods(t)).filter(Methods::isGetter)
+ .filter(m -> property.equals(Methods.propertyName(m))).findFirst().orElse(null));
+ }
+
private Methods() {
}
}
[3/4] bval git commit: cleanup
Posted by mb...@apache.org.
cleanup
Project: http://git-wip-us.apache.org/repos/asf/bval/repo
Commit: http://git-wip-us.apache.org/repos/asf/bval/commit/f2acb643
Tree: http://git-wip-us.apache.org/repos/asf/bval/tree/f2acb643
Diff: http://git-wip-us.apache.org/repos/asf/bval/diff/f2acb643
Branch: refs/heads/bv2
Commit: f2acb643662ebace2e5ffd371ffbace8140c424d
Parents: fe4c1d6
Author: Matt Benson <mb...@apache.org>
Authored: Tue Feb 27 17:43:57 2018 -0600
Committer: Matt Benson <mb...@apache.org>
Committed: Tue Feb 27 17:43:57 2018 -0600
----------------------------------------------------------------------
.../main/java/org/apache/bval/util/reflection/Reflection.java | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/bval/blob/f2acb643/bval-jsr/src/main/java/org/apache/bval/util/reflection/Reflection.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/util/reflection/Reflection.java b/bval-jsr/src/main/java/org/apache/bval/util/reflection/Reflection.java
index 33ff739..2c8b7b6 100644
--- a/bval-jsr/src/main/java/org/apache/bval/util/reflection/Reflection.java
+++ b/bval-jsr/src/main/java/org/apache/bval/util/reflection/Reflection.java
@@ -379,10 +379,7 @@ public class Reflection {
@Override
public Iterator<Class<?>> iterator() {
return new Iterator<Class<?>>() {
- Optional<Class<?>> next;
- {
- next = Optional.of(type);
- }
+ Optional<Class<?>> next = Optional.of(type);
@Override
public boolean hasNext() {
@@ -412,7 +409,7 @@ public class Reflection {
public Iterator<Class<?>> iterator() {
final Set<Class<?>> seenInterfaces = new HashSet<Class<?>>();
final Iterator<Class<?>> wrapped = classes.iterator();
-
+
return new Iterator<Class<?>>() {
Iterator<Class<?>> interfaces = Collections.emptyIterator();
[2/4] bval git commit: ws
Posted by mb...@apache.org.
ws
Project: http://git-wip-us.apache.org/repos/asf/bval/repo
Commit: http://git-wip-us.apache.org/repos/asf/bval/commit/fe4c1d6c
Tree: http://git-wip-us.apache.org/repos/asf/bval/tree/fe4c1d6c
Diff: http://git-wip-us.apache.org/repos/asf/bval/diff/fe4c1d6c
Branch: refs/heads/bv2
Commit: fe4c1d6ce8b583b3b24ea53e7c2e0d19219aaf4c
Parents: 09152bc
Author: Matt Benson <mb...@apache.org>
Authored: Mon Feb 26 13:31:51 2018 -0600
Committer: Matt Benson <mb...@apache.org>
Committed: Mon Feb 26 13:31:51 2018 -0600
----------------------------------------------------------------------
.../src/main/java/org/apache/bval/util/reflection/Reflection.java | 2 --
1 file changed, 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/bval/blob/fe4c1d6c/bval-jsr/src/main/java/org/apache/bval/util/reflection/Reflection.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/util/reflection/Reflection.java b/bval-jsr/src/main/java/org/apache/bval/util/reflection/Reflection.java
index 79e88fb..33ff739 100644
--- a/bval-jsr/src/main/java/org/apache/bval/util/reflection/Reflection.java
+++ b/bval-jsr/src/main/java/org/apache/bval/util/reflection/Reflection.java
@@ -212,11 +212,9 @@ public class Reflection {
if (loader == null) {
loader = Thread.currentThread().getContextClassLoader();
}
-
return Class.forName(className, resolve, loader);
}
-
/**
* Convenient point for {@link Privilizing} {@link System#getProperty(String)}.
* @param name