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/21 21:01:53 UTC
[03/17] bval git commit: BV2: utility classes
BV2: utility classes
Project: http://git-wip-us.apache.org/repos/asf/bval/repo
Commit: http://git-wip-us.apache.org/repos/asf/bval/commit/fad43eb8
Tree: http://git-wip-us.apache.org/repos/asf/bval/tree/fad43eb8
Diff: http://git-wip-us.apache.org/repos/asf/bval/diff/fad43eb8
Branch: refs/heads/bv2
Commit: fad43eb892b66592606fa76d70f67f8d016db373
Parents: 5c09f0d
Author: Matt Benson <mb...@apache.org>
Authored: Wed Feb 21 14:31:22 2018 -0600
Committer: Matt Benson <mb...@apache.org>
Committed: Wed Feb 21 14:44:27 2018 -0600
----------------------------------------------------------------------
.../java/org/apache/bval/util/BValVersion.java | 12 +-
.../java/org/apache/bval/util/Exceptions.java | 125 +++++++
.../main/java/org/apache/bval/util/Lazy.java | 62 ++++
.../main/java/org/apache/bval/util/LazyInt.java | 49 +++
.../java/org/apache/bval/util/ObjectUtils.java | 20 +-
.../org/apache/bval/util/ObjectWrapper.java | 50 +++
.../java/org/apache/bval/util/StringUtils.java | 67 ++--
.../java/org/apache/bval/util/Validate.java | 29 +-
.../apache/bval/util/reflection/Reflection.java | 173 +++++++--
.../apache/bval/util/reflection/TypeUtils.java | 65 ++--
.../bval/jsr/util/AnnotationsManager.java | 359 +++++++++++++++++++
.../org/apache/bval/jsr/util/ClassHelper.java | 10 +-
...ementNodeBuilderCustomizableContextImpl.java | 77 ++++
...nerElementNodeBuilderDefinedContextImpl.java | 65 ++++
.../ContainerElementNodeContextBuilderImpl.java | 85 +++++
.../main/java/org/apache/bval/jsr/util/IOs.java | 11 +-
.../java/org/apache/bval/jsr/util/LRUCache.java | 41 +++
.../LeafNodeBuilderCustomizableContextImpl.java | 23 +-
.../java/org/apache/bval/jsr/util/Methods.java | 45 +++
.../NodeBuilderCustomizableContextImpl.java | 55 ++-
.../jsr/util/NodeBuilderDefinedContextImpl.java | 32 +-
.../bval/jsr/util/NodeContextBuilderImpl.java | 52 +--
.../java/org/apache/bval/jsr/util/NodeImpl.java | 118 +++---
.../java/org/apache/bval/jsr/util/PathImpl.java | 91 +++--
.../apache/bval/jsr/util/PathNavigation.java | 102 ++++--
.../java/org/apache/bval/jsr/util/Proxies.java | 2 +-
.../apache/bval/jsr/util/ToUnmodifiable.java | 34 ++
27 files changed, 1503 insertions(+), 351 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/bval/blob/fad43eb8/bval-core/src/main/java/org/apache/bval/util/BValVersion.java
----------------------------------------------------------------------
diff --git a/bval-core/src/main/java/org/apache/bval/util/BValVersion.java b/bval-core/src/main/java/org/apache/bval/util/BValVersion.java
index b0c451f..13d1fa3 100644
--- a/bval-core/src/main/java/org/apache/bval/util/BValVersion.java
+++ b/bval-core/src/main/java/org/apache/bval/util/BValVersion.java
@@ -54,21 +54,17 @@ public class BValVersion {
static {
Properties revisionProps = new Properties();
- try {
- InputStream in = BValVersion.class.getResourceAsStream("/META-INF/org.apache.bval.revision.properties");
+ try (InputStream in = BValVersion.class.getResourceAsStream("/META-INF/org.apache.bval.revision.properties")) {
if (in != null) {
- try {
- revisionProps.load(in);
- } finally {
- in.close();
- }
+ revisionProps.load(in);
}
} catch (IOException ioe) {
}
String vers = revisionProps.getProperty("project.version");
- if (vers == null || "".equals(vers.trim()))
+ if (vers == null || "".equals(vers.trim())) {
vers = "0.0.0";
+ }
VERSION_NUMBER = vers;
StringTokenizer tok = new StringTokenizer(VERSION_NUMBER, ".-");
http://git-wip-us.apache.org/repos/asf/bval/blob/fad43eb8/bval-core/src/main/java/org/apache/bval/util/Exceptions.java
----------------------------------------------------------------------
diff --git a/bval-core/src/main/java/org/apache/bval/util/Exceptions.java b/bval-core/src/main/java/org/apache/bval/util/Exceptions.java
new file mode 100644
index 0000000..9487cde
--- /dev/null
+++ b/bval-core/src/main/java/org/apache/bval/util/Exceptions.java
@@ -0,0 +1,125 @@
+/*
+ * 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.util;
+
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+/**
+ * Utility class for the creation and throwing of Exceptions.
+ */
+public class Exceptions {
+
+ public static <E extends Exception> E create(Function<? super String, ? extends E> fn, String format,
+ Object... args) {
+ return create(fn, () -> String.format(format, args));
+ }
+
+ public static <E extends Exception, C extends Throwable> E create(
+ BiFunction<? super String, ? super C, ? extends E> fn, C cause, String format, Object... args) {
+ return create(fn, cause, () -> String.format(format, args));
+ }
+
+ public static <E extends Exception> E create(Function<? super String, ? extends E> fn, Supplier<String> message) {
+ return elideStackTrace(fn.apply(message.get()));
+ }
+
+ public static <E extends Exception, C extends Throwable> E create(
+ BiFunction<? super String, ? super C, ? extends E> fn, C cause, Supplier<String> message) {
+ return elideStackTrace(fn.apply(message.get(), cause));
+ }
+
+ public static <E extends Exception, R> R raise(Function<? super String, ? extends E> fn, String format,
+ Object... args) throws E {
+ throw create(fn, format, args);
+ }
+
+ public static <E extends Exception> void raiseIf(boolean condition, Function<? super String, ? extends E> fn,
+ String format, Object... args) throws E {
+ if (condition) {
+ raise(fn, format, args);
+ }
+ }
+
+ public static <E extends Exception> void raiseUnless(boolean condition, Function<? super String, ? extends E> fn,
+ String format, Object... args) throws E {
+ raiseIf(!condition, fn, format, args);
+ }
+
+ public static <E extends Exception, R> R raise(Function<? super String, ? extends E> fn, Supplier<String> message)
+ throws E {
+ throw create(fn, message);
+ }
+
+ public static <E extends Exception> void raiseIf(boolean condition, Function<? super String, ? extends E> fn,
+ Supplier<String> message) throws E {
+ if (condition) {
+ raise(fn, message);
+ }
+ }
+
+ public static <E extends Exception> void raiseUnless(boolean condition, Function<? super String, ? extends E> fn,
+ Supplier<String> message) throws E {
+ raiseIf(!condition, fn, message);
+ }
+
+ public static <E extends Exception, C extends Throwable, R> R raise(
+ BiFunction<? super String, ? super C, ? extends E> fn, C cause, String format, Object... args) throws E {
+ throw create(fn, cause, format, args);
+ }
+
+ public static <E extends Exception, C extends Throwable> void raiseIf(boolean condition,
+ BiFunction<? super String, ? super C, ? extends E> fn, C cause, String format, Object... args) throws E {
+ if (condition) {
+ raise(fn, cause, format, args);
+ }
+ }
+
+ public static <E extends Exception, C extends Throwable> void raiseUnless(boolean condition,
+ BiFunction<? super String, ? super C, ? extends E> fn, C cause, String format, Object... args) throws E {
+ raiseIf(!condition, fn, cause, format, args);
+ }
+
+ public static <E extends Exception, C extends Throwable, R> R raise(
+ BiFunction<? super String, ? super C, ? extends E> fn, C cause, Supplier<String> message) throws E {
+ throw create(fn, cause, message);
+ }
+
+ public static <E extends Exception, C extends Throwable> void raiseIf(boolean condition,
+ BiFunction<? super String, ? super C, ? extends E> fn, C cause, Supplier<String> message) throws E {
+ if (condition) {
+ raise(fn, cause, message);
+ }
+ }
+
+ public static <E extends Exception, C extends Throwable> void raiseUnless(boolean condition,
+ BiFunction<? super String, ? super C, ? extends E> fn, C cause, Supplier<String> message) throws E {
+ raiseIf(!condition, fn, cause, message);
+ }
+
+ private static <T extends Throwable> T elideStackTrace(T t) {
+ final StackTraceElement[] stackTrace = t.fillInStackTrace().getStackTrace();
+ t.setStackTrace(Stream.of(stackTrace).filter(e -> !Exceptions.class.getName().equals(e.getClassName()))
+ .toArray(StackTraceElement[]::new));
+ return t;
+ }
+
+ private Exceptions() {
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/fad43eb8/bval-core/src/main/java/org/apache/bval/util/Lazy.java
----------------------------------------------------------------------
diff --git a/bval-core/src/main/java/org/apache/bval/util/Lazy.java b/bval-core/src/main/java/org/apache/bval/util/Lazy.java
new file mode 100644
index 0000000..4796de3
--- /dev/null
+++ b/bval-core/src/main/java/org/apache/bval/util/Lazy.java
@@ -0,0 +1,62 @@
+/*
+ * 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.util;
+
+import java.util.Optional;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * @since 2.0
+ *
+ * @param <T>
+ */
+public class Lazy<T> implements Supplier<T> {
+ private T value;
+ private volatile Supplier<T> init;
+
+ public Lazy(Supplier<T> init) {
+ reset(init);
+ }
+
+ public Lazy<T> reset(Supplier<T> init) {
+ this.init = Validate.notNull(init);
+ return this;
+ }
+
+ @Override
+ public T get() {
+ if (init != null) {
+ synchronized (this) {
+ if (init != null) {
+ value = init.get();
+ init = null;
+ }
+ }
+ }
+ return value;
+ }
+
+ public Optional<T> optional() {
+ return Optional.ofNullable(value);
+ }
+
+ public <U> Consumer<U> consumer(BiConsumer<? super T, ? super U> delegate) {
+ return u -> delegate.accept(get(), u);
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/fad43eb8/bval-core/src/main/java/org/apache/bval/util/LazyInt.java
----------------------------------------------------------------------
diff --git a/bval-core/src/main/java/org/apache/bval/util/LazyInt.java b/bval-core/src/main/java/org/apache/bval/util/LazyInt.java
new file mode 100644
index 0000000..44e09dd
--- /dev/null
+++ b/bval-core/src/main/java/org/apache/bval/util/LazyInt.java
@@ -0,0 +1,49 @@
+/*
+ * 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.util;
+
+import java.util.OptionalInt;
+import java.util.function.IntSupplier;
+
+/**
+ * @since 2.0
+ */
+public class LazyInt implements IntSupplier {
+ private int value;
+ private IntSupplier init;
+
+ public LazyInt(IntSupplier init) {
+ this.init = Validate.notNull(init);
+ }
+
+ @Override
+ public int getAsInt() {
+ if (init != null) {
+ synchronized (this) {
+ if (init != null) {
+ value = init.getAsInt();
+ init = null;
+ }
+ }
+ }
+ return value;
+ }
+
+ public synchronized OptionalInt optional() {
+ return init == null ? OptionalInt.of(value) : OptionalInt.empty();
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/fad43eb8/bval-core/src/main/java/org/apache/bval/util/ObjectUtils.java
----------------------------------------------------------------------
diff --git a/bval-core/src/main/java/org/apache/bval/util/ObjectUtils.java b/bval-core/src/main/java/org/apache/bval/util/ObjectUtils.java
index 0464eeb..b7f2fac 100644
--- a/bval-core/src/main/java/org/apache/bval/util/ObjectUtils.java
+++ b/bval-core/src/main/java/org/apache/bval/util/ObjectUtils.java
@@ -18,6 +18,8 @@ package org.apache.bval.util;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
public final class ObjectUtils {
public static final Class<?>[] EMPTY_CLASS_ARRAY = new Class[0];
@@ -44,7 +46,7 @@ public final class ObjectUtils {
* @return {@code object} if it is not {@code null}, defaultValue otherwise
*/
public static <T> T defaultIfNull(final T object, final T defaultValue) {
- return object != null ? object : defaultValue;
+ return object == null ? defaultValue : object;
}
public static <T> boolean isNotEmpty(final T[] array) {
@@ -68,29 +70,19 @@ public final class ObjectUtils {
if (array == null) {
return false;
}
- for (Object o : array) {
- if (o.equals(objectToFind)) {
- return true;
- }
- }
- return false;
+ return Stream.of(array).anyMatch(Predicate.isEqual(objectToFind));
}
public static <T> T[] arrayAdd(T[] array, T objectToAdd) {
- Class<?> type;
- if (array != null) {
- type = array.getClass().getComponentType();
- } else if (objectToAdd != null) {
- type = objectToAdd.getClass();
- } else {
+ if (array == null && objectToAdd == null) {
throw new IllegalArgumentException("Arguments cannot both be null");
}
final int arrayLength = Array.getLength(array);
+ @SuppressWarnings("unchecked")
T[] newArray = (T[]) Array.newInstance(array.getClass().getComponentType(), arrayLength + 1);
System.arraycopy(array, 0, newArray, 0, arrayLength);
newArray[newArray.length - 1] = objectToAdd;
return newArray;
-
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/fad43eb8/bval-core/src/main/java/org/apache/bval/util/ObjectWrapper.java
----------------------------------------------------------------------
diff --git a/bval-core/src/main/java/org/apache/bval/util/ObjectWrapper.java b/bval-core/src/main/java/org/apache/bval/util/ObjectWrapper.java
new file mode 100644
index 0000000..8483745
--- /dev/null
+++ b/bval-core/src/main/java/org/apache/bval/util/ObjectWrapper.java
@@ -0,0 +1,50 @@
+/*
+ * 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.util;
+
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+public class ObjectWrapper<T> implements Consumer<T>, Supplier<T> {
+ private T value;
+
+ public ObjectWrapper() {
+ this(null);
+ }
+
+ public ObjectWrapper(T value) {
+ super();
+ this.value = value;
+ }
+
+ @Override
+ public void accept(T value) {
+ this.value = value;
+ }
+
+ @Override
+ public T get() {
+ return value;
+ }
+
+ public Optional<T> optional() {
+ return Optional.ofNullable(value);
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/fad43eb8/bval-core/src/main/java/org/apache/bval/util/StringUtils.java
----------------------------------------------------------------------
diff --git a/bval-core/src/main/java/org/apache/bval/util/StringUtils.java b/bval-core/src/main/java/org/apache/bval/util/StringUtils.java
index f7add27..6b9c25d 100644
--- a/bval-core/src/main/java/org/apache/bval/util/StringUtils.java
+++ b/bval-core/src/main/java/org/apache/bval/util/StringUtils.java
@@ -17,8 +17,6 @@
package org.apache.bval.util;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
import java.util.List;
public final class StringUtils {
@@ -93,49 +91,24 @@ public final class StringUtils {
return true;
}
- public static String join(Collection<?> values, String joinToken) {
- if (values == null) {
- return null;
- }
- if (values.size() == 0) {
- return "";
- }
- if (values.size() == 1) {
- return values.iterator().next().toString();
- }
- if (joinToken == null) {
- joinToken = "null"; // backward compat with commons-lang StringUtils...
- }
-
- StringBuilder sb = new StringBuilder(values.size() * (16 + joinToken.length()));
- Iterator<?> it = values.iterator();
- sb.append(it.next());
- while (it.hasNext()) {
- sb.append(joinToken).append(it.next());
- }
- return sb.toString();
- }
-
- public static String joinArray(Object[] values, String joinToken) {
- if (values == null) {
- return null;
- }
- if (values.length == 0) {
- return "";
- }
- if (values.length == 1) {
- return values[0].toString();
- }
- if (joinToken == null) {
- joinToken = "null"; // backward compat with commons-lang StringUtils...
- }
-
- StringBuilder sb = new StringBuilder(values.length * (16 + joinToken.length()));
- sb.append(values[0]);
- for (int i = 1; i < values.length; i++) {
- sb.append(joinToken).append(values[i]);
- }
- return sb.toString();
+ /**
+ * Taken from commons-lang3.
+ * <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p>
+ *
+ * <pre>
+ * StringUtils.isNotBlank(null) = false
+ * StringUtils.isNotBlank("") = false
+ * StringUtils.isNotBlank(" ") = false
+ * StringUtils.isNotBlank("bob") = true
+ * StringUtils.isNotBlank(" bob ") = true
+ * </pre>
+ *
+ * @param cs the CharSequence to check, may be null
+ * @return {@code true} if the CharSequence is
+ * not empty and not null and not whitespace
+ */
+ public static boolean isNotBlank(final CharSequence cs) {
+ return !isBlank(cs);
}
/**
@@ -149,12 +122,12 @@ public final class StringUtils {
* <p>Splits the provided text into an array, separator is whitespace.
*/
public static String[] split(String str, Character token) {
- if (str == null || str.length() == 0) {
+ if (str == null || str.isEmpty()) {
return ObjectUtils.EMPTY_STRING_ARRAY;
}
// split on token
- List<String> ret = new ArrayList<String>();
+ List<String> ret = new ArrayList<>();
StringBuilder sb = new StringBuilder(str.length());
for (int pos = 0; pos < str.length(); pos++) {
char c = str.charAt(pos);
http://git-wip-us.apache.org/repos/asf/bval/blob/fad43eb8/bval-core/src/main/java/org/apache/bval/util/Validate.java
----------------------------------------------------------------------
diff --git a/bval-core/src/main/java/org/apache/bval/util/Validate.java b/bval-core/src/main/java/org/apache/bval/util/Validate.java
index f0e0611..042dc1b 100644
--- a/bval-core/src/main/java/org/apache/bval/util/Validate.java
+++ b/bval-core/src/main/java/org/apache/bval/util/Validate.java
@@ -16,9 +16,10 @@
*/
package org.apache.bval.util;
+import java.util.function.Function;
+
/**
- * Some used Validate from commons.
- *
+ * Some used validations from commons.
*/
public final class Validate {
private Validate() {
@@ -29,16 +30,30 @@ public final class Validate {
}
public static <T> T notNull(final T object, final String message, final Object... values) {
- if (object == null) {
- throw new NullPointerException(String.format(message, values));
- }
+ return notNull(object, NullPointerException::new, message, values);
+ }
+
+ public static <E extends Exception, T> T notNull(final T object, Function<? super String, ? extends E> fn,
+ final String message, final Object... values) throws E {
+ Exceptions.raiseIf(object == null, fn, message, values);
return object;
}
public static void isTrue(final boolean expression, final String message, final Object... values) {
- if (expression == false) {
- throw new IllegalArgumentException(String.format(message, values));
+ Exceptions.raiseUnless(expression, IllegalArgumentException::new, message, values);
+ }
+
+ public static <T> T[] noNullElements(final T[] array, final String message, final Object... values) {
+ Validate.notNull(array);
+
+ for (int i = 0; i < array.length; i++) {
+ Exceptions.raiseIf(array[i] == null, IllegalArgumentException::new, message,
+ ObjectUtils.arrayAdd(values, Integer.valueOf(i)));
}
+ return array;
}
+ public static void validState(final boolean expression, final String message, final Object... values) {
+ Exceptions.raiseUnless(expression, IllegalStateException::new, message, values);
+ }
}
http://git-wip-us.apache.org/repos/asf/bval/blob/fad43eb8/bval-core/src/main/java/org/apache/bval/util/reflection/Reflection.java
----------------------------------------------------------------------
diff --git a/bval-core/src/main/java/org/apache/bval/util/reflection/Reflection.java b/bval-core/src/main/java/org/apache/bval/util/reflection/Reflection.java
index 674cf94..221a277 100644
--- a/bval-core/src/main/java/org/apache/bval/util/reflection/Reflection.java
+++ b/bval-core/src/main/java/org/apache/bval/util/reflection/Reflection.java
@@ -24,8 +24,16 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
import org.apache.commons.weaver.privilizer.Privilizing;
@@ -33,36 +41,44 @@ import org.apache.commons.weaver.privilizer.Privilizing;
* Security-agnostic "blueprint" class for reflection-related operations. Intended for use by Apache BVal code.
*/
public class Reflection {
+ /**
+ * Inclusivity literals for {@link #hierarchy(Class, Interfaces)}.
+ * Taken from commons-lang3.
+ */
+ public enum Interfaces {
+ INCLUDE, EXCLUDE
+ }
+
private static final Object[][] NATIVE_CODES = new Object[][]{
- {byte.class, "byte", "B"},
- {char.class, "char", "C"},
- {double.class, "double", "D"},
- {float.class, "float", "F"},
- {int.class, "int", "I"},
- {long.class, "long", "J"},
- {short.class, "short", "S"},
- {boolean.class, "boolean", "Z"},
- {void.class, "void", "V"}
+ { byte.class, "byte", "B" },
+ { char.class, "char", "C" },
+ { double.class, "double", "D" },
+ { float.class, "float", "F" },
+ { int.class, "int", "I" },
+ { long.class, "long", "J" },
+ { short.class, "short", "S" },
+ { boolean.class, "boolean", "Z" },
+ { void.class, "void", "V" }
};
/**
* Maps primitive {@code Class}es to their corresponding wrapper {@code Class}.
*/
- private static final Map<Class<?>, Class<?>> PRIMITIVE_WRAPPER_MAP = new HashMap<Class<?>, Class<?>>();
+ private static final Map<Class<?>, Class<?>> PRIMITIVE_WRAPPER_MAP;
static {
- PRIMITIVE_WRAPPER_MAP.put(Boolean.TYPE, Boolean.class);
- PRIMITIVE_WRAPPER_MAP.put(Byte.TYPE, Byte.class);
- PRIMITIVE_WRAPPER_MAP.put(Character.TYPE, Character.class);
- PRIMITIVE_WRAPPER_MAP.put(Short.TYPE, Short.class);
- PRIMITIVE_WRAPPER_MAP.put(Integer.TYPE, Integer.class);
- PRIMITIVE_WRAPPER_MAP.put(Long.TYPE, Long.class);
- PRIMITIVE_WRAPPER_MAP.put(Double.TYPE, Double.class);
- PRIMITIVE_WRAPPER_MAP.put(Float.TYPE, Float.class);
- PRIMITIVE_WRAPPER_MAP.put(Void.TYPE, Void.TYPE);
+ final Map<Class<?>, Class<?>> m = new HashMap<>();
+ m.put(Boolean.TYPE, Boolean.class);
+ m.put(Byte.TYPE, Byte.class);
+ m.put(Character.TYPE, Character.class);
+ m.put(Short.TYPE, Short.class);
+ m.put(Integer.TYPE, Integer.class);
+ m.put(Long.TYPE, Long.class);
+ m.put(Double.TYPE, Double.class);
+ m.put(Float.TYPE, Float.class);
+ m.put(Void.TYPE, Void.TYPE);
+ PRIMITIVE_WRAPPER_MAP = Collections.unmodifiableMap(m);
}
-
-
/**
* <p>Converts the specified primitive Class object to its corresponding
* wrapper Class object.</p>
@@ -129,8 +145,7 @@ public class Reflection {
return cl == null ? clazz.getClassLoader() : cl;
}
- public static Class<?> toClass(String className) throws ClassNotFoundException
- {
+ public static Class<?> toClass(String className) throws ClassNotFoundException {
ClassLoader cl = getClassLoader(Reflection.class);
return toClass(className, cl);
}
@@ -142,7 +157,7 @@ public class Reflection {
*
* @throws RuntimeException on load error
*/
- public static Class toClass(String className, ClassLoader loader) throws ClassNotFoundException {
+ public static Class<?> toClass(String className, ClassLoader loader) throws ClassNotFoundException {
return toClass(className, false, loader);
}
@@ -153,7 +168,7 @@ public class Reflection {
*
* @throws RuntimeException on load error
*/
- public static Class toClass(String className, boolean resolve, ClassLoader loader) throws ClassNotFoundException {
+ public static Class<?> toClass(String className, boolean resolve, ClassLoader loader) throws ClassNotFoundException {
if (className == null) {
throw new NullPointerException("className == null");
}
@@ -171,7 +186,7 @@ public class Reflection {
for (int i = 0; !primitive && (i < NATIVE_CODES.length); i++) {
if (NATIVE_CODES[i][1].equals(className)) {
if (dims == 0) {
- return (Class) NATIVE_CODES[i][0];
+ return (Class<?>) NATIVE_CODES[i][0];
}
className = (String) NATIVE_CODES[i][2];
primitive = true;
@@ -296,6 +311,22 @@ public class Reflection {
}
/**
+ * Perform a search against the class hierarchy.
+ * @param clazz
+ * @param search
+ * @return T or {@code null}
+ */
+ public static <T> T find(final Class<?> clazz, Function<Class<?>, T> search) {
+ for (Class<?> t : hierarchy(clazz, Interfaces.INCLUDE)) {
+ final T value = search.apply(t);
+ if (value != null) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+ /**
* Construct a new instance of {@code cls} using its default constructor.
* @param cls
* @return T
@@ -333,4 +364,94 @@ public class Reflection {
return true;
}
+ /**
+ * Get an {@link Iterable} that can iterate over a class hierarchy in ascending (subclass to superclass) order.
+ * Taken from commons-lang3.
+ *
+ * @param type the type to get the class hierarchy from
+ * @param interfacesBehavior switch indicating whether to include or exclude interfaces
+ * @return Iterable an Iterable over the class hierarchy of the given class
+ */
+ public static Iterable<Class<?>> hierarchy(final Class<?> type, final Interfaces interfacesBehavior) {
+ if (type == null) {
+ return Collections.emptySet();
+ }
+ final Iterable<Class<?>> classes = new Iterable<Class<?>>() {
+
+ @Override
+ public Iterator<Class<?>> iterator() {
+ return new Iterator<Class<?>>() {
+ Optional<Class<?>> next;
+ {
+ next = Optional.of(type);
+ }
+
+ @Override
+ public boolean hasNext() {
+ return next.isPresent();
+ }
+
+ @Override
+ public Class<?> next() {
+ final Class<?> result = next.orElseThrow(NoSuchElementException::new);
+ next = Optional.ofNullable(result.getSuperclass());
+ return result;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ };
+ if (interfacesBehavior != Interfaces.INCLUDE) {
+ return classes;
+ }
+ return new Iterable<Class<?>>() {
+
+ @Override
+ 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();
+
+ @Override
+ public boolean hasNext() {
+ return interfaces.hasNext() || wrapped.hasNext();
+ }
+
+ @Override
+ public Class<?> next() {
+ if (interfaces.hasNext()) {
+ final Class<?> nextInterface = interfaces.next();
+ seenInterfaces.add(nextInterface);
+ return nextInterface;
+ }
+ final Class<?> nextSuperclass = wrapped.next();
+ final Set<Class<?>> currentInterfaces = new LinkedHashSet<>();
+ walkInterfaces(currentInterfaces, nextSuperclass);
+ interfaces = currentInterfaces.iterator();
+ return nextSuperclass;
+ }
+
+ private void walkInterfaces(final Set<Class<?>> addTo, final Class<?> c) {
+ for (final Class<?> iface : c.getInterfaces()) {
+ if (!seenInterfaces.contains(iface)) {
+ addTo.add(iface);
+ }
+ walkInterfaces(addTo, iface);
+ }
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ };
+ }
}
http://git-wip-us.apache.org/repos/asf/bval/blob/fad43eb8/bval-core/src/main/java/org/apache/bval/util/reflection/TypeUtils.java
----------------------------------------------------------------------
diff --git a/bval-core/src/main/java/org/apache/bval/util/reflection/TypeUtils.java b/bval-core/src/main/java/org/apache/bval/util/reflection/TypeUtils.java
index 4734906..b8b044d 100644
--- a/bval-core/src/main/java/org/apache/bval/util/reflection/TypeUtils.java
+++ b/bval-core/src/main/java/org/apache/bval/util/reflection/TypeUtils.java
@@ -28,8 +28,11 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
+import java.util.stream.Stream;
+import org.apache.bval.util.ObjectUtils;
import org.apache.bval.util.Validate;
/**
@@ -148,13 +151,7 @@ public class TypeUtils {
*/
@Override
public int hashCode() {
- int result = 71 << 4;
- result |= raw.hashCode();
- result <<= 4;
- result |= useOwner == null ? 0 : useOwner.hashCode();
- result <<= 8;
- result |= Arrays.hashCode(typeArguments);
- return result;
+ return Objects.hash(raw, useOwner, typeArguments);
}
}
@@ -162,7 +159,8 @@ public class TypeUtils {
* WildcardType implementation class.
*/
private static final class WildcardTypeImpl implements WildcardType {
- private static final Type[] EMPTY_BOUNDS = new Type[0];
+ private static final Type[] EMPTY_UPPER_BOUNDS = { Object.class };
+ private static final Type[] EMPTY_LOWER_BOUNDS = new Type[0];
private final Type[] upperBounds;
private final Type[] lowerBounds;
@@ -173,8 +171,8 @@ public class TypeUtils {
* @param lowerBounds of this type
*/
private WildcardTypeImpl(final Type[] upperBounds, final Type[] lowerBounds) {
- this.upperBounds = upperBounds != null ? upperBounds : EMPTY_BOUNDS;
- this.lowerBounds = lowerBounds != null ? lowerBounds : EMPTY_BOUNDS;
+ this.upperBounds = ObjectUtils.isEmpty(upperBounds) ? EMPTY_UPPER_BOUNDS : upperBounds;
+ this.lowerBounds = lowerBounds == null ? EMPTY_LOWER_BOUNDS : lowerBounds;
}
/**
@@ -214,11 +212,7 @@ public class TypeUtils {
*/
@Override
public int hashCode() {
- int result = 73 << 8;
- result |= Arrays.hashCode(upperBounds);
- result <<= 8;
- result |= Arrays.hashCode(lowerBounds);
- return result;
+ return Objects.hash(upperBounds, lowerBounds);
}
}
@@ -320,19 +314,13 @@ public class TypeUtils {
if (type instanceof TypeVariable<?>) {
// if any of the bounds are assignable to the class, then the
// type is assignable to the class.
- for (final Type bound : ((TypeVariable<?>) type).getBounds()) {
- if (isAssignable(bound, toClass)) {
- return true;
- }
- }
-
- return false;
+ return Stream.of(((TypeVariable<?>) type).getBounds()).anyMatch(bound -> isAssignable(bound, toClass));
}
// the only classes to which a generic array type can be assigned
// are class Object and array classes
if (type instanceof GenericArrayType) {
- return toClass.equals(Object.class)
+ return Object.class.equals(toClass)
|| toClass.isArray()
&& isAssignable(((GenericArrayType) type).getGenericComponentType(), toClass
.getComponentType());
@@ -554,25 +542,15 @@ public class TypeUtils {
if (type instanceof WildcardType) {
// so long as one of the upper bounds is assignable, it's good
- for (final Type bound : getImplicitUpperBounds((WildcardType) type)) {
- if (isAssignable(bound, toGenericArrayType)) {
- return true;
- }
- }
-
- return false;
+ return Stream.of(getImplicitUpperBounds((WildcardType) type))
+ .anyMatch(bound -> isAssignable(bound, toGenericArrayType));
}
if (type instanceof TypeVariable<?>) {
// probably should remove the following logic and just return false.
// type variables cannot specify arrays as bounds.
- for (final Type bound : getImplicitBounds((TypeVariable<?>) type)) {
- if (isAssignable(bound, toGenericArrayType)) {
- return true;
- }
- }
-
- return false;
+ return Stream.of(getImplicitBounds((TypeVariable<?>) type))
+ .anyMatch(bound -> isAssignable(bound, toGenericArrayType));
}
if (type instanceof ParameterizedType) {
@@ -871,8 +849,7 @@ public class TypeUtils {
getRawType(parameterizedOwnerType), subtypeVarAssigns);
} else {
// no owner, prep the type variable assignments map
- typeVarAssigns = subtypeVarAssigns == null ? new HashMap<TypeVariable<?>, Type>()
- : new HashMap<TypeVariable<?>, Type>(subtypeVarAssigns);
+ typeVarAssigns = subtypeVarAssigns == null ? new HashMap<>() : new HashMap<>(subtypeVarAssigns);
}
// get the subject parameterized type's arguments
@@ -917,7 +894,7 @@ public class TypeUtils {
if (toClass.isPrimitive()) {
// dealing with widening here. No type arguments to be
// harvested with these two types.
- return new HashMap<TypeVariable<?>, Type>();
+ return new HashMap<>();
}
// work with wrapper the wrapper class instead of the primitive
@@ -925,8 +902,8 @@ public class TypeUtils {
}
// create a copy of the incoming map, or an empty one if it's null
- final HashMap<TypeVariable<?>, Type> typeVarAssigns = subtypeVarAssigns == null ? new HashMap<TypeVariable<?>, Type>()
- : new HashMap<TypeVariable<?>, Type>(subtypeVarAssigns);
+ final Map<TypeVariable<?>, Type> typeVarAssigns =
+ subtypeVarAssigns == null ? new HashMap<>() : new HashMap<>(subtypeVarAssigns);
// has target class been reached?
if (toClass.equals(cls)) {
@@ -1030,7 +1007,7 @@ public class TypeUtils {
return bounds;
}
- final Set<Type> types = new HashSet<Type>(bounds.length);
+ final Set<Type> types = new HashSet<>(bounds.length);
for (final Type type1 : bounds) {
boolean subtypeFound = false;
@@ -1243,7 +1220,7 @@ public class TypeUtils {
if (p.getOwnerType() == null) {
parameterizedTypeArguments = typeArguments;
} else {
- parameterizedTypeArguments = new HashMap<TypeVariable<?>, Type>(typeArguments);
+ parameterizedTypeArguments = new HashMap<>(typeArguments);
parameterizedTypeArguments.putAll(TypeUtils.getTypeArguments(p));
}
final Type[] args = p.getActualTypeArguments();
http://git-wip-us.apache.org/repos/asf/bval/blob/fad43eb8/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
new file mode 100644
index 0000000..b53b513
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/AnnotationsManager.java
@@ -0,0 +1,359 @@
+/*
+ * 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.util;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Repeatable;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+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;
+import javax.validation.constraintvalidation.ValidationTarget;
+
+import org.apache.bval.jsr.ApacheValidatorFactory;
+import org.apache.bval.jsr.ConfigurationImpl;
+import org.apache.bval.jsr.ConstraintAnnotationAttributes;
+import org.apache.bval.jsr.ConstraintCached.ConstraintValidatorInfo;
+import org.apache.bval.jsr.groups.Group;
+import org.apache.bval.jsr.groups.Groups;
+import org.apache.bval.jsr.groups.GroupsComputer;
+import org.apache.bval.jsr.metadata.Metas;
+import org.apache.bval.jsr.xml.AnnotationProxyBuilder;
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.Lazy;
+import org.apache.bval.util.StringUtils;
+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;
+
+/**
+ * Manages (constraint) annotations according to the BV spec.
+ *
+ * @since 2.0
+ */
+@Privilizing(@CallTo(Reflection.class))
+public class AnnotationsManager {
+ private static final class OverriddenAnnotationSpecifier {
+ final Class<? extends Annotation> annotationType;
+ final boolean impliesSingleComposingConstraint;
+ final int constraintIndex;
+
+ OverriddenAnnotationSpecifier(OverridesAttribute annotation) {
+ this(annotation.constraint(), annotation.constraintIndex());
+ }
+
+ OverriddenAnnotationSpecifier(Class<? extends Annotation> annotationType, int constraintIndex) {
+ super();
+ this.annotationType = annotationType;
+ this.impliesSingleComposingConstraint = constraintIndex < 0;
+ this.constraintIndex = Math.max(constraintIndex, 0);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj == null || !obj.getClass().equals(getClass())) {
+ return false;
+ }
+ final OverriddenAnnotationSpecifier other = (OverriddenAnnotationSpecifier) obj;
+ return Objects.equals(annotationType, other.annotationType) && constraintIndex == other.constraintIndex;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(annotationType, constraintIndex);
+ }
+ }
+
+ private static class Composition {
+ final Lazy<Map<OverriddenAnnotationSpecifier, Map<String, String>>> overrides = new Lazy<>(HashMap::new);
+ final Annotation[] components;
+
+ Composition(Class<? extends Annotation> annotationType) {
+ // TODO detect recursion
+ components = getDeclaredConstraints(annotationType);
+
+ if (!isComposed()) {
+ return;
+ }
+ final Map<Class<? extends Annotation>, AtomicInteger> constraintCounts = new HashMap<>();
+ for (Annotation a : components) {
+ constraintCounts.computeIfAbsent(a.annotationType(), k -> new AtomicInteger()).incrementAndGet();
+ }
+ // create a map of overridden constraints to overridden attributes:
+ for (Method m : Reflection.getDeclaredMethods(annotationType)) {
+ final String from = m.getName();
+ for (OverridesAttribute overridesAttribute : m.getDeclaredAnnotationsByType(OverridesAttribute.class)) {
+ final String to =
+ Optional.of(overridesAttribute.name()).filter(StringUtils::isNotBlank).orElse(from);
+
+ final OverriddenAnnotationSpecifier spec = new OverriddenAnnotationSpecifier(overridesAttribute);
+ final int count = constraintCounts.get(spec.annotationType).get();
+
+ if (spec.impliesSingleComposingConstraint) {
+ Exceptions.raiseUnless(count == 1, ConstraintDefinitionException::new,
+ "Expected a single composing %s constraint", spec.annotationType);
+ } else {
+ Exceptions.raiseUnless(count > spec.constraintIndex, ConstraintDefinitionException::new,
+ "Expected at least %s composing %s constraints", spec.constraintIndex + 1,
+ spec.annotationType);
+ }
+ final Map<String, String> attributeMapping =
+ overrides.get().computeIfAbsent(spec, k -> new HashMap<>());
+
+ Exceptions.raiseIf(attributeMapping.containsKey(to), ConstraintDefinitionException::new,
+ "Attempt to override %s#%s() index %d from multiple sources", overridesAttribute.constraint(),
+ to, overridesAttribute.constraintIndex());
+
+ attributeMapping.put(to, from);
+ }
+ }
+ }
+
+ boolean isComposed() {
+ return components.length > 0;
+ }
+
+ Annotation[] getComponents(Annotation source) {
+ final Class<?>[] groups =
+ ConstraintAnnotationAttributes.GROUPS.analyze(source.annotationType()).read(source);
+
+ 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 -> {
+ final int index =
+ constraintCounts.computeIfAbsent(c.annotationType(), k -> new AtomicInteger()).getAndIncrement();
+
+ final AnnotationProxyBuilder<Annotation> proxyBuilder = new AnnotationProxyBuilder<>(c);
+
+ proxyBuilder.setGroups(groups);
+ proxyBuilder.setPayload(payload);
+ constraintTarget.ifPresent(proxyBuilder::setValidationAppliesTo);
+
+ overrides.optional().map(o -> o.get(new OverriddenAnnotationSpecifier(c.annotationType(), index)))
+ .ifPresent(m -> {
+ final Map<String, Object> sourceAttributes = readAttributes(source);
+ m.forEach((k, v) -> proxyBuilder.setValue(k, sourceAttributes.get(v)));
+ });
+ return proxyBuilder.isChanged() ? proxyBuilder.createAnnotation() : c;
+ }).toArray(Annotation[]::new);
+ }
+ }
+
+ public static Map<String, Object> readAttributes(Annotation a) {
+ final Lazy<Map<String, Object>> result = new Lazy<>(LinkedHashMap::new);
+
+ Stream.of(Reflection.getDeclaredMethods(a.annotationType())).filter(m -> m.getParameterCount() == 0)
+ .forEach(m -> {
+ final boolean mustUnset = Reflection.setAccessible(m, true);
+ try {
+ result.get().put(m.getName(), m.invoke(a));
+ } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+ Exceptions.raise(ValidationException::new, e, "Caught exception reading attributes of %s", a);
+ } finally {
+ if (mustUnset) {
+ Reflection.setAccessible(m, false);
+ }
+ }
+ });
+ return result.optional().map(Collections::unmodifiableMap).orElseGet(Collections::emptyMap);
+ }
+
+ /**
+ * Meta-annotation aware.
+ *
+ * @param e
+ * @param t
+ * @return {@code boolean}
+ * @see AnnotatedElement#isAnnotationPresent(Class)
+ */
+ public static boolean isAnnotationPresent(AnnotatedElement e, Class<? extends Annotation> t) {
+ if (e.isAnnotationPresent(t)) {
+ return true;
+ }
+ return Stream.of(e.getAnnotations()).map(Annotation::annotationType).anyMatch(a -> isAnnotationPresent(a, t));
+ }
+
+ /**
+ * Get declared annotations with a particular meta-annotation.
+ *
+ * @param e
+ * @param meta
+ * @return {@link Annotation}[]
+ */
+ public static Annotation[] getDeclared(AnnotatedElement e, Class<? extends Annotation> meta) {
+ return Stream.of(e.getDeclaredAnnotations()).filter(ann -> isAnnotationPresent(ann.annotationType(), meta))
+ .toArray(Annotation[]::new);
+ }
+
+ /**
+ * Accounts for {@link Constraint} meta-annotation AND {@link Repeatable}
+ * constraint annotations.
+ *
+ * @param meta
+ * @return Annotation[]
+ */
+ public static Annotation[] getDeclaredConstraints(Metas<?> meta) {
+ final Annotation[] result = getDeclaredConstraints(meta.getHost());
+ final Class<?> dc = meta.getDeclaringClass();
+ if (dc.isInterface()) {
+ final GroupsComputer groupsComputer = new GroupsComputer();
+ // ensure interface group is implied by Default group:
+ Stream.of(result).map(c -> {
+ final Groups groups = groupsComputer
+ .computeGroups(ConstraintAnnotationAttributes.GROUPS.analyze(c.annotationType()).read(c));
+ if (groups.getGroups().stream().anyMatch(Group::isDefault)) {
+ final Set<Class<?>> groupClasses = groups.getGroups().stream().map(Group::getGroup)
+ .collect(Collectors.toCollection(LinkedHashSet::new));
+ if (groupClasses.add(dc)) {
+ final AnnotationProxyBuilder<?> proxyBuilder = new AnnotationProxyBuilder<>(c);
+ proxyBuilder.setGroups(groupClasses.toArray(new Class[groupClasses.size()]));
+ return proxyBuilder.createAnnotation();
+ }
+ }
+ return c;
+ }).toArray(n -> result);
+ }
+ return result;
+ }
+
+ private static Annotation[] getDeclaredConstraints(AnnotatedElement e) {
+ return Stream.of(e.getDeclaredAnnotations()).flatMap((Function<Annotation, Stream<Annotation>>) a -> {
+ final ConstraintAnnotationAttributes.Worker<? extends Annotation> analyzer =
+ ConstraintAnnotationAttributes.VALUE.analyze(a.annotationType());
+ if (analyzer.isValid()) {
+ return Stream.of(analyzer.<Annotation[]> read(a));
+ }
+ return Stream.of(a);
+ }).filter(a -> a.annotationType().isAnnotationPresent(Constraint.class)).toArray(Annotation[]::new);
+ }
+
+ public static boolean declaresAttribute(Class<? extends Annotation> annotationType, String name) {
+ try {
+ annotationType.getDeclaredMethod(name);
+ return true;
+ } catch (NoSuchMethodException | SecurityException e) {
+ return false;
+ }
+ }
+
+ private final ApacheValidatorFactory validatorFactory;
+ private final LRUCache<Class<? extends Annotation>, Composition> compositions;
+
+ public AnnotationsManager(ApacheValidatorFactory validatorFactory) {
+ super();
+ this.validatorFactory = Validate.notNull(validatorFactory);
+ final String cacheSize =
+ validatorFactory.getProperties().get(ConfigurationImpl.Properties.CONSTRAINTS_CACHE_SIZE);
+ try {
+ compositions = new LRUCache<>(Integer.parseInt(cacheSize));
+ } catch (NumberFormatException e) {
+ throw Exceptions.create(IllegalStateException::new, e,
+ "Cannot parse value %s for configuration property %s", cacheSize,
+ ConfigurationImpl.Properties.CONSTRAINTS_CACHE_SIZE);
+ }
+ }
+
+ /**
+ * Retrieve the composing constraints for the specified constraint
+ * {@link Annotation}.
+ *
+ * @param a
+ * @return {@link Annotation}[]
+ */
+ public Annotation[] getComposingConstraints(Annotation a) {
+ return getComposition(a.annotationType()).getComponents(a);
+ }
+
+ /**
+ * Learn whether {@code a} is composed.
+ *
+ * @param a
+ * @return {@code boolean}
+ */
+ public boolean isComposed(Annotation a) {
+ return getComposition(a.annotationType()).isComposed();
+ }
+
+ /**
+ * Get the supported targets for {@code constraintType}.
+ *
+ * @param constraintType
+ * @return {@link Set} of {@link ValidationTarget}
+ */
+ public <A extends Annotation> Set<ValidationTarget> supportedTargets(Class<A> constraintType) {
+ final Set<ConstraintValidatorInfo<A>> constraintValidatorInfo =
+ validatorFactory.getConstraintsCache().getConstraintValidatorInfo(constraintType);
+ final Stream<Set<ValidationTarget>> s;
+ if (constraintValidatorInfo.isEmpty()) {
+ // must be for composition:
+ s = Stream.of(new Composition(constraintType).components).map(Annotation::annotationType)
+ .map(this::supportedTargets);
+ } else {
+ s = constraintValidatorInfo.stream().map(ConstraintValidatorInfo::getSupportedTargets);
+ }
+ return s.flatMap(Collection::stream)
+ .collect(Collectors.toCollection(() -> EnumSet.noneOf(ValidationTarget.class)));
+ }
+
+ private Composition getComposition(Class<? extends Annotation> annotationType) {
+ return compositions.computeIfAbsent(annotationType, ct -> {
+ final Set<ValidationTarget> composedTargets = supportedTargets(annotationType);
+ final Composition result = new Composition(annotationType);
+ Stream.of(result.components).map(Annotation::annotationType).forEach(at -> {
+ final Set<ValidationTarget> composingTargets = supportedTargets(at);
+ Exceptions.raiseIf(Collections.disjoint(composingTargets, composedTargets),
+ ConstraintDefinitionException::new,
+ "Attempt to compose %s of %s but validator types are incompatible", annotationType.getName(),
+ at.getName());
+ });
+ return result;
+ });
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/fad43eb8/bval-jsr/src/main/java/org/apache/bval/jsr/util/ClassHelper.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/ClassHelper.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/ClassHelper.java
index 9d3bd85..73c82a6 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/util/ClassHelper.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/ClassHelper.java
@@ -20,7 +20,11 @@ package org.apache.bval.jsr.util;
import java.io.Serializable;
import java.security.AccessController;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
* Common operations on classes that do not require an {@link AccessController}.
@@ -28,6 +32,7 @@ import java.util.List;
* @author Carlos Vara
*/
public class ClassHelper {
+ private static final Set<Class<?>> IGNORED_TYPES = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(null,Object.class,Serializable.class,Cloneable.class)));
private ClassHelper() {
// No instances please
@@ -42,10 +47,7 @@ public class ClassHelper {
* @param clazz
*/
public static List<Class<?>> fillFullClassHierarchyAsList(List<Class<?>> allClasses, Class<?> clazz) {
- if (clazz == null || clazz == Object.class || clazz == Serializable.class || clazz == Cloneable.class) {
- return allClasses;
- }
- if (allClasses.contains(clazz)) {
+ if (IGNORED_TYPES.contains(clazz) || allClasses.contains(clazz)) {
return allClasses;
}
allClasses.add(clazz);
http://git-wip-us.apache.org/repos/asf/bval/blob/fad43eb8/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeBuilderCustomizableContextImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeBuilderCustomizableContextImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeBuilderCustomizableContextImpl.java
new file mode 100644
index 0000000..c0cff10
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeBuilderCustomizableContextImpl.java
@@ -0,0 +1,77 @@
+/*
+ * 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.util;
+
+import javax.validation.ConstraintValidatorContext;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.ContainerElementNodeBuilderCustomizableContext;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.ContainerElementNodeContextBuilder;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeBuilderCustomizableContext;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext;
+
+import org.apache.bval.jsr.job.ConstraintValidatorContextImpl;
+
+public class ContainerElementNodeBuilderCustomizableContextImpl
+ implements ContainerElementNodeBuilderCustomizableContext {
+ private final ConstraintValidatorContextImpl<?> context;
+ private final String template;
+ private final PathImpl path;
+ private NodeImpl node;
+
+ public ContainerElementNodeBuilderCustomizableContextImpl(ConstraintValidatorContextImpl<?> context, String template,
+ PathImpl path, String name, Class<?> containerType, Integer typeArgumentIndex) {
+ super();
+ this.context = context;
+ this.path = path;
+ this.template = template;
+ this.node = new NodeImpl.ContainerElementNodeImpl(name, containerType, typeArgumentIndex);
+ }
+
+ @Override
+ public ContainerElementNodeContextBuilder inIterable() {
+ node.setInIterable(true);
+ return new ContainerElementNodeContextBuilderImpl(context, template, path, node);
+ }
+
+ @Override
+ public NodeBuilderCustomizableContext addPropertyNode(String name) {
+ path.addNode(node);
+ return new NodeBuilderCustomizableContextImpl(context, template, path, name);
+ }
+
+ @Override
+ public LeafNodeBuilderCustomizableContext addBeanNode() {
+ path.addNode(node);
+ return new LeafNodeBuilderCustomizableContextImpl(context, template, path);
+ }
+
+ @Override
+ public ContainerElementNodeBuilderCustomizableContext addContainerElementNode(String name, Class<?> containerType,
+ Integer typeArgumentIndex) {
+ path.addNode(node);
+ node = new NodeImpl.ContainerElementNodeImpl(name, containerType, typeArgumentIndex);
+ return this;
+ }
+
+ @Override
+ public ConstraintValidatorContext addConstraintViolation() {
+ context.addError(template, path);
+ return context;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/fad43eb8/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeBuilderDefinedContextImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeBuilderDefinedContextImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeBuilderDefinedContextImpl.java
new file mode 100644
index 0000000..6077d87
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeBuilderDefinedContextImpl.java
@@ -0,0 +1,65 @@
+/*
+ * 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.util;
+
+import javax.validation.ConstraintValidatorContext;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.ContainerElementNodeBuilderCustomizableContext;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.ContainerElementNodeBuilderDefinedContext;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeBuilderCustomizableContext;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext;
+
+import org.apache.bval.jsr.job.ConstraintValidatorContextImpl;
+
+public class ContainerElementNodeBuilderDefinedContextImpl implements ContainerElementNodeBuilderDefinedContext {
+ private final ConstraintValidatorContextImpl<?> context;
+ private final String template;
+ private final PathImpl path;
+
+ ContainerElementNodeBuilderDefinedContextImpl(ConstraintValidatorContextImpl<?> context, String template,
+ PathImpl path) {
+ super();
+ this.context = context;
+ this.template = template;
+ this.path = path;
+ }
+
+ @Override
+ public NodeBuilderCustomizableContext addPropertyNode(String name) {
+ return new NodeBuilderCustomizableContextImpl(context, template, path, name);
+ }
+
+ @Override
+ public LeafNodeBuilderCustomizableContext addBeanNode() {
+ return new LeafNodeBuilderCustomizableContextImpl(context, template, path);
+ }
+
+ @Override
+ public ContainerElementNodeBuilderCustomizableContext addContainerElementNode(String name, Class<?> containerType,
+ Integer typeArgumentIndex) {
+ return new ContainerElementNodeBuilderCustomizableContextImpl(context, name, path, name, containerType,
+ typeArgumentIndex);
+ }
+
+ @Override
+ public ConstraintValidatorContext addConstraintViolation() {
+ context.addError(template, path);
+ return context;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/fad43eb8/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeContextBuilderImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeContextBuilderImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeContextBuilderImpl.java
new file mode 100644
index 0000000..f05ef76
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/ContainerElementNodeContextBuilderImpl.java
@@ -0,0 +1,85 @@
+/*
+ * 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.util;
+
+import javax.validation.ConstraintValidatorContext;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.ContainerElementNodeBuilderCustomizableContext;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.ContainerElementNodeBuilderDefinedContext;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.ContainerElementNodeContextBuilder;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeBuilderCustomizableContext;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext;
+
+import org.apache.bval.jsr.job.ConstraintValidatorContextImpl;
+
+public class ContainerElementNodeContextBuilderImpl implements ContainerElementNodeContextBuilder {
+ private final ConstraintValidatorContextImpl<?> context;
+ private final String template;
+ private final PathImpl path;
+ private final NodeImpl node;
+
+ ContainerElementNodeContextBuilderImpl(ConstraintValidatorContextImpl<?> context, String template,
+ PathImpl path, NodeImpl node) {
+ super();
+ this.context = context;
+ this.template = template;
+ this.path = path;
+ this.node = node;
+ }
+
+ @Override
+ public ContainerElementNodeBuilderDefinedContext atKey(Object key) {
+ node.setKey(key);
+ path.addNode(node);
+ return new ContainerElementNodeBuilderDefinedContextImpl(context, template, path);
+ }
+
+ @Override
+ public ContainerElementNodeBuilderDefinedContext atIndex(Integer index) {
+ node.setIndex(index);
+ path.addNode(node);
+ return new ContainerElementNodeBuilderDefinedContextImpl(context, template, path);
+ }
+
+ @Override
+ public NodeBuilderCustomizableContext addPropertyNode(String name) {
+ path.addNode(node);
+ return new NodeBuilderCustomizableContextImpl(context, name, path, name);
+ }
+
+ @Override
+ public LeafNodeBuilderCustomizableContext addBeanNode() {
+ path.addNode(node);
+ return new LeafNodeBuilderCustomizableContextImpl(context, template, path);
+ }
+
+ @Override
+ public ContainerElementNodeBuilderCustomizableContext addContainerElementNode(String name, Class<?> containerType,
+ Integer typeArgumentIndex) {
+ path.addNode(node);
+ return new ContainerElementNodeBuilderCustomizableContextImpl(context, template, path, name, containerType,
+ typeArgumentIndex);
+ }
+
+ @Override
+ public ConstraintValidatorContext addConstraintViolation() {
+ context.addError(template, path);
+ return context;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/fad43eb8/bval-jsr/src/main/java/org/apache/bval/jsr/util/IOs.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/IOs.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/IOs.java
index 611a9d6..57f7cf4 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/util/IOs.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/IOs.java
@@ -33,25 +33,20 @@ public class IOs {
if (stream == null) {
return null;
}
-
- // force ByteArrayOutputStream since we close the stream ATM
- /*if (stream.markSupported()) {
- return stream;
- } else {*/
- try {
+ try (InputStream in = stream) {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final byte[] buffer = new byte[1024];
int length;
- while ((length = stream.read(buffer)) != -1) {
+ while ((length = in.read(buffer)) != -1) {
baos.write(buffer, 0, length);
}
return new ByteArrayInputStream(baos.toByteArray());
} catch (final IOException e) {
throw new RuntimeException(e);
}
- /*}*/
}
+ //TODO see if needed
public static void closeQuietly(Closeable closeable) {
if (closeable != null) {
try {
http://git-wip-us.apache.org/repos/asf/bval/blob/fad43eb8/bval-jsr/src/main/java/org/apache/bval/jsr/util/LRUCache.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/LRUCache.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/LRUCache.java
new file mode 100644
index 0000000..48fcd7d
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/LRUCache.java
@@ -0,0 +1,41 @@
+/*
+ * 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.util;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class LRUCache<K, V> extends LinkedHashMap<K, V> {
+ private static final long serialVersionUID = 1L;
+
+ private final int maximumCapacity;
+
+ public LRUCache(int maximumCapacity) {
+ super(16, 0.75f, true);
+ if (maximumCapacity < 1) {
+ throw new IllegalArgumentException("maximumCapacity must be > 0");
+ }
+ this.maximumCapacity = maximumCapacity;
+ }
+
+ @Override
+ protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
+ return super.removeEldestEntry(eldest) || size() >= maximumCapacity;
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/fad43eb8/bval-jsr/src/main/java/org/apache/bval/jsr/util/LeafNodeBuilderCustomizableContextImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/LeafNodeBuilderCustomizableContextImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/LeafNodeBuilderCustomizableContextImpl.java
index efa9aeb..99305be 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/util/LeafNodeBuilderCustomizableContextImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/LeafNodeBuilderCustomizableContextImpl.java
@@ -18,9 +18,10 @@
*/
package org.apache.bval.jsr.util;
-import org.apache.bval.jsr.ConstraintValidatorContextImpl;
+import org.apache.bval.jsr.job.ConstraintValidatorContextImpl;
import javax.validation.ConstraintValidatorContext;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeBuilderCustomizableContext;
import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeBuilderDefinedContext;
import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeContextBuilder;
@@ -43,8 +44,7 @@ public class LeafNodeBuilderCustomizableContextImpl
}
@Override
- public LeafNodeBuilderDefinedContext atIndex(
- Integer index) {
+ public LeafNodeBuilderDefinedContext atIndex(Integer index) {
node.setIndex(index);
return definedContext;
}
@@ -55,16 +55,16 @@ public class LeafNodeBuilderCustomizableContextImpl
}
}
- private final ConstraintValidatorContextImpl context;
+ private final ConstraintValidatorContextImpl<?> context;
private final PathImpl path;
private final String template;
private final NodeImpl node;
- public LeafNodeBuilderCustomizableContextImpl(final ConstraintValidatorContextImpl parent, String messageTemplate,
- PathImpl propertyPath) {
- context = parent;
- template = messageTemplate;
- path = propertyPath;
+ public LeafNodeBuilderCustomizableContextImpl(final ConstraintValidatorContextImpl<?> context, String template,
+ PathImpl path) {
+ this.context = context;
+ this.template = template;
+ this.path = path;
node = new NodeImpl.BeanNodeImpl();
}
@@ -81,4 +81,9 @@ public class LeafNodeBuilderCustomizableContextImpl
return context;
}
+ @Override
+ public LeafNodeBuilderCustomizableContext inContainer(Class<?> containerType, Integer typeArgumentIndex) {
+ node.inContainer(containerType, typeArgumentIndex);
+ return this;
+ }
}
http://git-wip-us.apache.org/repos/asf/bval/blob/fad43eb8/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
new file mode 100644
index 0000000..9f98311
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/Methods.java
@@ -0,0 +1,45 @@
+/*
+ * 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.util;
+
+import java.beans.Introspector;
+import java.lang.reflect.Method;
+
+import org.apache.bval.util.Validate;
+
+public final class Methods {
+ public static boolean isGetter(Method m) {
+ if (m.getParameterCount() > 0) {
+ return false;
+ }
+ // TODO look for capital letter after verb?
+ if (Boolean.TYPE.equals(m.getReturnType()) && m.getName().startsWith("is")) {
+ return true;
+ }
+ return !Void.TYPE.equals(m.getReturnType()) && m.getName().startsWith("get");
+ }
+
+ public static String propertyName(Method getter) {
+ Validate.isTrue(isGetter(getter), "%s is not a getter", getter);
+ final String name = getter.getName();
+ final String suffix = name.startsWith("is") ? name.substring(2) : name.substring(3);
+ return Introspector.decapitalize(suffix);
+ }
+
+ private Methods() {
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/fad43eb8/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeBuilderCustomizableContextImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeBuilderCustomizableContextImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeBuilderCustomizableContextImpl.java
index ca058fc..6ec977c 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeBuilderCustomizableContextImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeBuilderCustomizableContextImpl.java
@@ -18,38 +18,40 @@
*/
package org.apache.bval.jsr.util;
-import org.apache.bval.jsr.ConstraintValidatorContextImpl;
-
import javax.validation.ConstraintValidatorContext;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.ContainerElementNodeBuilderCustomizableContext;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext;
import javax.validation.ElementKind;
+import org.apache.bval.jsr.job.ConstraintValidatorContextImpl;
+
/**
* Description: implementation of {@link javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext}.<br/>
*/
public final class NodeBuilderCustomizableContextImpl
implements ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext {
- private final ConstraintValidatorContextImpl parent;
- private final String messageTemplate;
- private final PathImpl propertyPath;
+ private final ConstraintValidatorContextImpl<?> context;
+ private final String template;
+ private final PathImpl path;
private NodeImpl node;
/**
* Create a new NodeBuilderCustomizableContextImpl instance.
- * @param contextImpl
+ * @param context
* @param template
* @param path
* @param name
*/
- public NodeBuilderCustomizableContextImpl(ConstraintValidatorContextImpl contextImpl, String template, PathImpl path,
+ public NodeBuilderCustomizableContextImpl(ConstraintValidatorContextImpl<?> context, String template, PathImpl path,
String name) {
- parent = contextImpl;
- messageTemplate = template;
- propertyPath = path;
+ this.context = context;
+ this.template = template;
+ this.path = path;
- if (propertyPath.isRootPath() || propertyPath.getLeafNode().getKind() != null) {
+ if (path.isRootPath() || path.getLeafNode().getKind() != null) {
node = new NodeImpl.PropertyNodeImpl(name);
} else {
- node = propertyPath.removeLeafNode();
+ node = path.removeLeafNode();
node.setName(name);
node.setKind(ElementKind.PROPERTY); // enforce it
}
@@ -61,7 +63,7 @@ public final class NodeBuilderCustomizableContextImpl
@Override
public ConstraintValidatorContext.ConstraintViolationBuilder.NodeContextBuilder inIterable() {
node.setInIterable(true);
- return new NodeContextBuilderImpl(parent, messageTemplate, propertyPath, node);
+ return new NodeContextBuilderImpl(context, template, path, node);
}
/**
@@ -75,15 +77,15 @@ public final class NodeBuilderCustomizableContextImpl
@Override
public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext addPropertyNode(
String name) {
- propertyPath.addNode(node);
+ path.addNode(node);
node = new NodeImpl.PropertyNodeImpl(name);
return this;
}
@Override
public ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeBuilderCustomizableContext addBeanNode() {
- propertyPath.addNode(node);
- return new LeafNodeBuilderCustomizableContextImpl(parent, messageTemplate, propertyPath);
+ path.addNode(node);
+ return new LeafNodeBuilderCustomizableContextImpl(context, template, path);
}
/**
@@ -91,10 +93,25 @@ public final class NodeBuilderCustomizableContextImpl
*/
@Override
public ConstraintValidatorContext addConstraintViolation() {
- propertyPath.addNode(node);
+ path.addNode(node);
node = null;
- parent.addError(messageTemplate, propertyPath);
- return parent;
+ context.addError(template, path);
+ return context;
+ }
+
+ @Override
+ public NodeBuilderCustomizableContext inContainer(Class<?> containerClass, Integer typeArgumentIndex) {
+ path.getLeafNode().inContainer(containerClass, typeArgumentIndex);
+ return this;
+ }
+
+ @Override
+ public ContainerElementNodeBuilderCustomizableContext addContainerElementNode(String name, Class<?> containerType,
+ Integer typeArgumentIndex) {
+ path.addNode(node);
+ node = new NodeImpl.ContainerElementNodeImpl(name, containerType, typeArgumentIndex);
+ return new ContainerElementNodeBuilderCustomizableContextImpl(context, template, path, name, containerType,
+ typeArgumentIndex);
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/fad43eb8/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeBuilderDefinedContextImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeBuilderDefinedContextImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeBuilderDefinedContextImpl.java
index 5ce20b5..f695e84 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeBuilderDefinedContextImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeBuilderDefinedContextImpl.java
@@ -18,18 +18,19 @@
*/
package org.apache.bval.jsr.util;
-import org.apache.bval.jsr.ConstraintValidatorContextImpl;
-
import javax.validation.ConstraintValidatorContext;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.ContainerElementNodeBuilderCustomizableContext;
+
+import org.apache.bval.jsr.job.ConstraintValidatorContextImpl;
/**
* Description: Implementation of {@link NodeBuilderDefinedContext}.<br/>
*/
public final class NodeBuilderDefinedContextImpl
implements ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderDefinedContext {
- private final ConstraintValidatorContextImpl parent;
- private final String messageTemplate;
- private final PathImpl propertyPath;
+ private final ConstraintValidatorContextImpl context;
+ private final String template;
+ private final PathImpl path;
/**
* Create a new NodeBuilderDefinedContextImpl instance.
@@ -38,9 +39,9 @@ public final class NodeBuilderDefinedContextImpl
* @param path
*/
public NodeBuilderDefinedContextImpl(ConstraintValidatorContextImpl contextImpl, String template, PathImpl path) {
- parent = contextImpl;
- messageTemplate = template;
- propertyPath = path;
+ this.context = contextImpl;
+ this.template = template;
+ this.path = path;
}
/**
@@ -54,12 +55,12 @@ public final class NodeBuilderDefinedContextImpl
@Override
public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext addPropertyNode(
String name) {
- return new NodeBuilderCustomizableContextImpl(parent, messageTemplate, propertyPath, name);
+ return new NodeBuilderCustomizableContextImpl(context, template, path, name);
}
@Override
public ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeBuilderCustomizableContext addBeanNode() {
- return new LeafNodeBuilderCustomizableContextImpl(parent, messageTemplate, propertyPath);
+ return new LeafNodeBuilderCustomizableContextImpl(context, template, path);
}
/**
@@ -67,7 +68,14 @@ public final class NodeBuilderDefinedContextImpl
*/
@Override
public ConstraintValidatorContext addConstraintViolation() {
- parent.addError(messageTemplate, propertyPath);
- return parent;
+ context.addError(template, path);
+ return context;
+ }
+
+ @Override
+ public ContainerElementNodeBuilderCustomizableContext addContainerElementNode(String name, Class<?> containerType,
+ Integer typeArgumentIndex) {
+ return new ContainerElementNodeBuilderCustomizableContextImpl(context, template, path, name, containerType,
+ typeArgumentIndex);
}
}