Repository: bval Updated Branches: refs/heads/bv2 00a882f72 -> 339ada646
some cleanups Project: http://git-wip-us.apache.org/repos/asf/bval/repo Commit: http://git-wip-us.apache.org/repos/asf/bval/commit/339ada64 Tree: http://git-wip-us.apache.org/repos/asf/bval/tree/339ada64 Diff: http://git-wip-us.apache.org/repos/asf/bval/diff/339ada64 Branch: refs/heads/bv2 Commit: 339ada64661c0865a8f04322b274174b531beccb Parents: 00a882f Author: Matt Benson <[email protected]> Authored: Wed Mar 21 18:11:38 2018 -0500 Committer: Matt Benson <[email protected]> Committed: Wed Mar 21 18:11:38 2018 -0500 ---------------------------------------------------------------------- .../bval/jsr/descriptor/MetadataReader.java | 29 ++++---- .../apache/bval/jsr/job/ValidateParameters.java | 4 +- .../org/apache/bval/jsr/job/ValidationJob.java | 5 +- .../bval/jsr/metadata/ReflectionBuilder.java | 3 +- .../bval/jsr/util/AnnotationsManager.java | 6 -- .../java/org/apache/bval/jsr/util/Methods.java | 3 +- .../apache/bval/jsr/xml/AnnotationProxy.java | 74 +++++++++++++++++++- .../bval/jsr/xml/AnnotationProxyBuilder.java | 1 + .../java/org/apache/bval/util/ObjectUtils.java | 39 +++++++++++ .../java/org/apache/bval/util/StringUtils.java | 44 +++++++++++- 10 files changed, 180 insertions(+), 28 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/bval/blob/339ada64/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 9dba122..83055a9 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 @@ -210,19 +210,22 @@ class MetadataReader { Set<GroupConversion> getGroupConversions() { 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)); - + if (!groupConversions.isEmpty()) { + Exceptions.raiseUnless(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; } http://git-wip-us.apache.org/repos/asf/bval/blob/339ada64/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateParameters.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateParameters.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateParameters.java index 5e7dc79..c80937f 100644 --- a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateParameters.java +++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateParameters.java @@ -49,13 +49,11 @@ public abstract class ValidateParameters<E extends Executable, T> extends Valida public static class ForMethod<T> extends ValidateParameters<Method, T> { - private final T object; - ForMethod(ApacheFactoryContext validatorContext, T object, Method executable, Object[] parameterValues, Class<?>[] groups) { super(validatorContext, object, Validate.notNull(executable, IllegalArgumentException::new, "null method"), parameterValues, groups, new Meta.ForMethod(executable)); - this.object = Validate.notNull(object, IllegalArgumentException::new, "object"); + Validate.notNull(object, IllegalArgumentException::new, "object"); } @Override http://git-wip-us.apache.org/repos/asf/bval/blob/339ada64/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 3c74ce0..b8f22c1 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 @@ -514,8 +514,9 @@ public abstract class ValidationJob<T> { private boolean each(Stream<Class<?>> groupSequence, BiConsumer<Class<?>, Consumer<ConstraintViolation<T>>> closure, Consumer<ConstraintViolation<T>> sink) { final Lazy<Set<ConstraintViolation<T>>> sequenceViolations = new Lazy<>(LinkedHashSet::new); - for (Class<?> g : (Iterable<Class<?>>) () -> groupSequence.iterator()) { - closure.accept(g, sequenceViolations.consumer(Set::add)); + final Consumer<ConstraintViolation<T>> addSequenceViolation = sequenceViolations.consumer(Set::add); + for (Class<?> g : (Iterable<Class<?>>) groupSequence::iterator) { + closure.accept(g, addSequenceViolation); if (sequenceViolations.optional().isPresent()) { sequenceViolations.get().forEach(sink); return false; http://git-wip-us.apache.org/repos/asf/bval/blob/339ada64/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 ea396a0..08b2b1d 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 @@ -24,6 +24,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.lang.reflect.Parameter; import java.util.ArrayList; import java.util.Arrays; @@ -81,7 +82,7 @@ public class ReflectionBuilder { if (declaredFields.length == 0) { return Collections.emptyMap(); } - return Stream.of(declaredFields).collect( + return Stream.of(declaredFields).filter(f -> !Modifier.isStatic(f.getModifiers())).collect( Collectors.toMap(Field::getName, f -> new ReflectionBuilder.ForContainer<>(new Meta.ForField(f)))); } http://git-wip-us.apache.org/repos/asf/bval/blob/339ada64/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 4436bb7..ea2cac5 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 @@ -40,7 +40,6 @@ import java.util.stream.Stream; import javax.validation.Constraint; import javax.validation.ConstraintDefinitionException; -import javax.validation.ConstraintTarget; import javax.validation.OverridesAttribute; import javax.validation.Payload; import javax.validation.ValidationException; @@ -160,10 +159,6 @@ public class AnnotationsManager { final Class<? extends Payload>[] payload = ConstraintAnnotationAttributes.PAYLOAD.analyze(source.annotationType()).read(source); - final Optional<ConstraintTarget> constraintTarget = - Optional.of(source.annotationType()).map(ConstraintAnnotationAttributes.VALIDATION_APPLIES_TO::analyze) - .filter(ConstraintAnnotationAttributes.Worker::isValid).map(w -> w.read(source)); - final Map<Class<? extends Annotation>, AtomicInteger> constraintCounts = new HashMap<>(); return Stream.of(components).map(c -> { @@ -174,7 +169,6 @@ public class AnnotationsManager { proxyBuilder.setGroups(groups); proxyBuilder.setPayload(payload); - constraintTarget.ifPresent(proxyBuilder::setValidationAppliesTo); overrides.optional().map(o -> o.get(new OverriddenAnnotationSpecifier(c.annotationType(), index))) .ifPresent(m -> { http://git-wip-us.apache.org/repos/asf/bval/blob/339ada64/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 4b5ce45..ce83c73 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,6 +18,7 @@ package org.apache.bval.jsr.util; import java.beans.Introspector; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.stream.Stream; import org.apache.bval.util.Validate; @@ -28,7 +29,7 @@ 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) { + if (Modifier.isStatic(m.getModifiers()) || m.getParameterCount() > 0) { return false; } // TODO look for capital letter after verb? http://git-wip-us.apache.org/repos/asf/bval/blob/339ada64/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxy.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxy.java b/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxy.java index 96a2b46..13678ac 100644 --- a/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxy.java +++ b/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxy.java @@ -19,14 +19,20 @@ package org.apache.bval.jsr.xml; import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.Arrays; import java.util.SortedMap; import java.util.TreeMap; import java.util.stream.Collectors; import javax.validation.Valid; +import org.apache.bval.jsr.metadata.Signature; import org.apache.bval.util.Exceptions; +import org.apache.bval.util.ObjectUtils; +import org.apache.bval.util.StringUtils; +import org.apache.bval.util.reflection.Reflection; /** * Description: <br/> @@ -37,6 +43,8 @@ class AnnotationProxy implements Annotation, InvocationHandler, Serializable { /** Serialization version */ private static final long serialVersionUID = 1L; + + private Signature EQUALS = new Signature("equals", Object.class); private final Class<? extends Annotation> annotationType; private final SortedMap<String, Object> values; @@ -74,6 +82,9 @@ class AnnotationProxy implements Annotation, InvocationHandler, Serializable { if (values.containsKey(method.getName())) { return values.get(method.getName()); } + if (EQUALS.equals(Signature.of(method))) { + return equalTo(args[0]); + } return method.invoke(this, args); } @@ -90,7 +101,68 @@ class AnnotationProxy implements Annotation, InvocationHandler, Serializable { */ @Override public String toString() { - return values.entrySet().stream().map(e -> String.format("%s=%s", e.getKey(), e.getValue())) + return values.entrySet().stream() + .map(e -> String.format("%s=%s", e.getKey(), StringUtils.valueOf(e.getValue()))) .collect(Collectors.joining(", ", String.format("@%s(", annotationType().getName()), ")")); } + + @Override + public int hashCode() { + return values.entrySet().stream().mapToInt(e -> { + return (127 * e.getKey().hashCode()) ^ ObjectUtils.hashCode(e.getValue()); + }).sum(); + } + + private boolean equalTo(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Annotation) { + final Annotation other = (Annotation) obj; + return other.annotationType().equals(annotationType) + && values.entrySet().stream().allMatch(e -> memberEquals(other, e.getKey(), e.getValue())); + } + return false; + } + + private boolean memberEquals(Annotation other, String name, Object value) { + final Method member = Reflection.getDeclaredMethod(annotationType, name); + final Object otherValue; + try { + otherValue = member.invoke(other); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new IllegalStateException(e); + } + Exceptions.raiseIf(otherValue == null || !otherValue.getClass().equals(value.getClass()), + IllegalStateException::new, "Unexpected value %s for member %s of %s", otherValue, name, other); + + if (value instanceof Object[]) { + return Arrays.equals((Object[]) value, (Object[]) otherValue); + } + if (value instanceof byte[]) { + return Arrays.equals((byte[]) value, (byte[]) otherValue); + } + if (value instanceof short[]) { + return Arrays.equals((short[]) value, (short[]) otherValue); + } + if (value instanceof int[]) { + return Arrays.equals((int[]) value, (int[]) otherValue); + } + if (value instanceof char[]) { + return Arrays.equals((char[]) value, (char[]) otherValue); + } + if (value instanceof long[]) { + return Arrays.equals((long[]) value, (long[]) otherValue); + } + if (value instanceof float[]) { + return Arrays.equals((float[]) value, (float[]) otherValue); + } + if (value instanceof double[]) { + return Arrays.equals((double[]) value, (double[]) otherValue); + } + if (value instanceof boolean[]) { + return Arrays.equals((boolean[]) value, (boolean[]) otherValue); + } + return value.equals(otherValue); + } } http://git-wip-us.apache.org/repos/asf/bval/blob/339ada64/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxyBuilder.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxyBuilder.java b/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxyBuilder.java index 02383cb..fa6dab6 100644 --- a/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxyBuilder.java +++ b/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxyBuilder.java @@ -214,6 +214,7 @@ public final class AnnotationProxyBuilder<A extends Annotation> { public boolean setValidationAppliesTo(ConstraintTarget constraintTarget) { return setValue(ConstraintAnnotationAttributes.VALIDATION_APPLIES_TO.getAttributeName(), constraintTarget); } + public boolean isChanged() { return changed; } http://git-wip-us.apache.org/repos/asf/bval/blob/339ada64/bval-jsr/src/main/java/org/apache/bval/util/ObjectUtils.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/util/ObjectUtils.java b/bval-jsr/src/main/java/org/apache/bval/util/ObjectUtils.java index 1c5a728..2ccf90d 100644 --- a/bval-jsr/src/main/java/org/apache/bval/util/ObjectUtils.java +++ b/bval-jsr/src/main/java/org/apache/bval/util/ObjectUtils.java @@ -18,6 +18,7 @@ package org.apache.bval.util; import java.lang.annotation.Annotation; import java.lang.reflect.Array; +import java.util.Arrays; import java.util.Objects; import java.util.function.Predicate; import java.util.stream.Stream; @@ -95,4 +96,42 @@ public final class ObjectUtils { return newArray; } + + /** + * Get hashcode of {@code o}, taking into account array values. + * @param o + * @return {@code int} + * @see Arrays + * @see Objects#hashCode(Object) + */ + public static int hashCode(Object o) { + if (o instanceof Object[]) { + return Arrays.hashCode((Object[]) o); + } + if (o instanceof byte[]) { + return Arrays.hashCode((byte[]) o); + } + if (o instanceof short[]) { + return Arrays.hashCode((short[]) o); + } + if (o instanceof int[]) { + return Arrays.hashCode((int[]) o); + } + if (o instanceof char[]) { + return Arrays.hashCode((char[]) o); + } + if (o instanceof long[]) { + return Arrays.hashCode((long[]) o); + } + if (o instanceof float[]) { + return Arrays.hashCode((float[]) o); + } + if (o instanceof double[]) { + return Arrays.hashCode((double[]) o); + } + if (o instanceof boolean[]) { + return Arrays.hashCode((boolean[]) o); + } + return Objects.hashCode(o); + } } http://git-wip-us.apache.org/repos/asf/bval/blob/339ada64/bval-jsr/src/main/java/org/apache/bval/util/StringUtils.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/util/StringUtils.java b/bval-jsr/src/main/java/org/apache/bval/util/StringUtils.java index 6b9c25d..3328a2c 100644 --- a/bval-jsr/src/main/java/org/apache/bval/util/StringUtils.java +++ b/bval-jsr/src/main/java/org/apache/bval/util/StringUtils.java @@ -17,6 +17,7 @@ package org.apache.bval.util; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; public final class StringUtils { @@ -113,6 +114,8 @@ public final class StringUtils { /** * <p>Splits the provided text into an array, separator is whitespace. + * @param str + * @return {@link String}[] */ public static String[] split(String str) { return split(str, null); @@ -120,12 +123,14 @@ public final class StringUtils { /** * <p>Splits the provided text into an array, separator is whitespace. + * @param str + * @param token + * @return {@link String}[] */ public static String[] split(String str, Character token) { if (str == null || str.isEmpty()) { return ObjectUtils.EMPTY_STRING_ARRAY; } - // split on token List<String> ret = new ArrayList<>(); StringBuilder sb = new StringBuilder(str.length()); @@ -146,4 +151,41 @@ public final class StringUtils { return ret.toArray(new String[ret.size()]); } + /** + * Return a {@link String} representation of {@code o}, accounting for array types. + * @param o + * @return {@link String} + * @see Arrays + * @see String#valueOf(Object) + */ + public static String valueOf(Object o) { + if (o instanceof Object[]) { + return Arrays.toString((Object[]) o); + } + if (o instanceof byte[]) { + return Arrays.toString((byte[]) o); + } + if (o instanceof short[]) { + return Arrays.toString((short[]) o); + } + if (o instanceof int[]) { + return Arrays.toString((int[]) o); + } + if (o instanceof char[]) { + return Arrays.toString((char[]) o); + } + if (o instanceof long[]) { + return Arrays.toString((long[]) o); + } + if (o instanceof float[]) { + return Arrays.toString((float[]) o); + } + if (o instanceof double[]) { + return Arrays.toString((double[]) o); + } + if (o instanceof boolean[]) { + return Arrays.toString((boolean[]) o); + } + return String.valueOf(o); + } } \ No newline at end of file
