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 20:25:04 UTC
[08/11] bval git commit: implement BV 2.0 against existing BVal unit
tests
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintViolationImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintViolationImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintViolationImpl.java
index c367b8e..91ae20d 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintViolationImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintViolationImpl.java
@@ -20,15 +20,20 @@ import javax.validation.ConstraintViolation;
import javax.validation.Path;
import javax.validation.ValidationException;
import javax.validation.metadata.ConstraintDescriptor;
+
+import org.apache.bval.util.Exceptions;
+
import java.io.Serializable;
import java.lang.annotation.ElementType;
import java.util.Arrays;
+import java.util.Objects;
/**
* Description: Describe a constraint validation defect.<br/>
- * From rootBean and propertyPath, it is possible to rebuild the context of the failure
+ * From rootBean and propertyPath, it is possible to rebuild the context of the
+ * failure
*/
-class ConstraintViolationImpl<T> implements ConstraintViolation<T>, Serializable {
+public class ConstraintViolationImpl<T> implements ConstraintViolation<T>, Serializable {
/** Serialization version */
private static final long serialVersionUID = 1L;
@@ -49,8 +54,11 @@ class ConstraintViolationImpl<T> implements ConstraintViolation<T>, Serializable
/**
* Create a new ConstraintViolationImpl instance.
- * @param messageTemplate - message reason (raw message)
- * @param message - interpolated message (locale specific)
+ *
+ * @param messageTemplate
+ * - message reason (raw message)
+ * @param message
+ * - interpolated message (locale specific)
* @param rootBean
* @param leafBean
* @param propertyPath
@@ -79,8 +87,8 @@ class ConstraintViolationImpl<T> implements ConstraintViolation<T>, Serializable
}
/**
- * {@inheritDoc}
- * former name getInterpolatedMessage()
+ * {@inheritDoc} former name getInterpolatedMessage()
+ *
* @return The interpolated error message for this constraint violation.
*/
@Override
@@ -98,6 +106,7 @@ class ConstraintViolationImpl<T> implements ConstraintViolation<T>, Serializable
/**
* {@inheritDoc}
+ *
* @return Root bean being validated
*/
@Override
@@ -133,6 +142,7 @@ class ConstraintViolationImpl<T> implements ConstraintViolation<T>, Serializable
/**
* {@inheritDoc}
+ *
* @return The value failing to pass the constraint
*/
@Override
@@ -142,8 +152,9 @@ class ConstraintViolationImpl<T> implements ConstraintViolation<T>, Serializable
/**
* {@inheritDoc}
- * @return the property path to the value from <code>rootBean</code>
- * Null if the value is the rootBean itself
+ *
+ * @return the property path to the value from <code>rootBean</code> Null if
+ * the value is the rootBean itself
*/
@Override
public Path getPropertyPath() {
@@ -160,10 +171,8 @@ class ConstraintViolationImpl<T> implements ConstraintViolation<T>, Serializable
@Override
public <U> U unwrap(Class<U> type) {
- if (type.isInstance(this)) {
- return type.cast(this);
- }
- throw new ValidationException("Type " + type + " is not supported");
+ Exceptions.raiseUnless(type.isInstance(this), ValidationException::new, "Type %s is not supported", type);
+ return type.cast(this);
}
/**
@@ -171,45 +180,28 @@ class ConstraintViolationImpl<T> implements ConstraintViolation<T>, Serializable
*/
@Override
public String toString() {
- return "ConstraintViolationImpl{" + "rootBean=" + rootBean + ", propertyPath='" + propertyPath + '\''
- + ", message='" + message + '\'' + ", leafBean=" + leafBean + ", value=" + value + '}';
+ return String.format("%s{rootBean=%s, propertyPath='%s', message='%s', leafBean=%s, value=%s}",
+ ConstraintViolationImpl.class.getSimpleName(), rootBean, propertyPath, message, leafBean, value);
}
@Override
public boolean equals(Object o) {
- if (this == o)
+ if (this == o) {
return true;
- if (o == null || getClass() != o.getClass())
+ }
+ if (o == null || !getClass().equals(o.getClass())) {
return false;
+ }
- ConstraintViolationImpl that = (ConstraintViolationImpl) o;
-
- if (constraintDescriptor != null ? !constraintDescriptor.equals(that.constraintDescriptor)
- : that.constraintDescriptor != null)
- return false;
- if (elementType != that.elementType)
- return false;
- if (leafBean != null ? !leafBean.equals(that.leafBean) : that.leafBean != null)
- return false;
- if (message != null ? !message.equals(that.message) : that.message != null)
- return false;
- if (messageTemplate != null ? !messageTemplate.equals(that.messageTemplate) : that.messageTemplate != null)
- return false;
- // Probably incorrect - comparing Object[] arrays with Arrays.equals
- if (!Arrays.equals(parameters, that.parameters))
- return false;
- if (propertyPath != null ? !propertyPath.equals(that.propertyPath) : that.propertyPath != null)
- return false;
- if (returnValue != null ? !returnValue.equals(that.returnValue) : that.returnValue != null)
- return false;
- if (rootBean != null ? !rootBean.equals(that.rootBean) : that.rootBean != null)
- return false;
- if (rootBeanClass != null ? !rootBeanClass.equals(that.rootBeanClass) : that.rootBeanClass != null)
- return false;
- if (value != null ? !value.equals(that.value) : that.value != null)
- return false;
+ @SuppressWarnings("rawtypes")
+ final ConstraintViolationImpl that = (ConstraintViolationImpl) o;
- return true;
+ return Objects.equals(constraintDescriptor, that.constraintDescriptor) && elementType == that.elementType
+ && Objects.equals(leafBean, that.leafBean) && Objects.equals(message, that.message)
+ && Objects.equals(messageTemplate, that.messageTemplate) && Arrays.equals(parameters, that.parameters)
+ && Objects.equals(propertyPath, that.propertyPath) && Objects.equals(returnValue, that.returnValue)
+ && Objects.equals(rootBean, that.rootBean) && Objects.equals(rootBeanClass, that.rootBeanClass)
+ && Objects.equals(value, that.value);
}
@Override
@@ -217,18 +209,10 @@ class ConstraintViolationImpl<T> implements ConstraintViolation<T>, Serializable
return hashCode;
}
- public int computeHashCode() {
- int result = messageTemplate != null ? messageTemplate.hashCode() : 0;
- result = 31 * result + (message != null ? message.hashCode() : 0);
- result = 31 * result + (rootBean != null ? rootBean.hashCode() : 0);
- result = 31 * result + (rootBeanClass != null ? rootBeanClass.hashCode() : 0);
- result = 31 * result + (leafBean != null ? leafBean.hashCode() : 0);
- result = 31 * result + (value != null ? value.hashCode() : 0);
- result = 31 * result + (propertyPath != null ? propertyPath.hashCode() : 0);
- result = 31 * result + (elementType != null ? elementType.hashCode() : 0);
- result = 31 * result + (constraintDescriptor != null ? constraintDescriptor.hashCode() : 0);
- result = 31 * result + (returnValue != null ? returnValue.hashCode() : 0);
- result = 31 * result + (parameters != null ? Arrays.hashCode(parameters) : 0);
+ private int computeHashCode() {
+ int result = Objects.hash(messageTemplate, message, rootBean, rootBeanClass, leafBean, value, propertyPath,
+ elementType, constraintDescriptor, returnValue);
+ result = 31 * result + (parameters == null ? 0 : Arrays.hashCode(parameters));
return result;
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultConstraintValidatorFactory.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultConstraintValidatorFactory.java b/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultConstraintValidatorFactory.java
index 4aca48a..9474705 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultConstraintValidatorFactory.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultConstraintValidatorFactory.java
@@ -32,8 +32,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
* Description: create constraint instances with the default / no-arg constructor <br/>
*/
public class DefaultConstraintValidatorFactory implements ConstraintValidatorFactory, Closeable {
- private final Collection<BValExtension.Releasable<?>> releasables =
- new CopyOnWriteArrayList<BValExtension.Releasable<?>>();
+ private final Collection<BValExtension.Releasable<?>> releasables = new CopyOnWriteArrayList<>();
private volatile Boolean useCdi = null; // store it to avoid NoClassDefFoundError when cdi is not present (it is slow) + lazily (to wait cdi is started)
/**
@@ -49,9 +48,7 @@ public class DefaultConstraintValidatorFactory implements ConstraintValidatorFac
if (useCdi == null) {
try {
useCdi = BValExtension.getBeanManager() != null;
- } catch (final NoClassDefFoundError error) {
- useCdi = Boolean.FALSE;
- } catch (final Exception e) {
+ } catch (NoClassDefFoundError | Exception error) {
useCdi = Boolean.FALSE;
}
}
@@ -69,10 +66,7 @@ public class DefaultConstraintValidatorFactory implements ConstraintValidatorFac
return instance.getInstance();
}
throw new IllegalStateException("Can't create " + constraintClass.getName());
- } catch (final Exception e) {
- return constraintClass.newInstance();
- } catch (final NoClassDefFoundError error) {
- return constraintClass.newInstance();
+ } catch (Exception | NoClassDefFoundError e) {
}
}
return constraintClass.newInstance();
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultMessageInterpolator.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultMessageInterpolator.java b/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultMessageInterpolator.java
index 8c77162..6a85a2a 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultMessageInterpolator.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultMessageInterpolator.java
@@ -54,10 +54,10 @@ public class DefaultMessageInterpolator implements MessageInterpolator {
private Locale defaultLocale;
/** User specified resource bundles hashed against their locale. */
- private final Map<Locale, ResourceBundle> userBundlesMap = new ConcurrentHashMap<Locale, ResourceBundle>();
+ private final Map<Locale, ResourceBundle> userBundlesMap = new ConcurrentHashMap<>();
/** Builtin resource bundles hashed against their locale. */
- private final Map<Locale, ResourceBundle> defaultBundlesMap = new ConcurrentHashMap<Locale, ResourceBundle>();
+ private final Map<Locale, ResourceBundle> defaultBundlesMap = new ConcurrentHashMap<>();
private final MessageEvaluator evaluator;
@@ -83,12 +83,12 @@ public class DefaultMessageInterpolator implements MessageInterpolator {
userBundlesMap.put(defaultLocale, resourceBundle);
}
- MessageEvaluator ev = null;
+ MessageEvaluator ev;
try {
ev = MessageEvaluator.class
.cast(getClass().getClassLoader().loadClass("org.apache.bval.el.ELFacade").newInstance());
} catch (final Throwable e) { // can be exception or error
- // no-op
+ ev = null;
}
evaluator = ev;
}
@@ -170,47 +170,42 @@ public class DefaultMessageInterpolator implements MessageInterpolator {
* @return the resource bundle or <code>null</code> if none is found.
*/
private ResourceBundle getFileBasedResourceBundle(Locale locale) {
- ResourceBundle rb = null;
+ ResourceBundle rb;
final ClassLoader classLoader = Reflection.getClassLoader(DefaultMessageInterpolator.class);
if (classLoader != null) {
rb = loadBundle(classLoader, locale, USER_VALIDATION_MESSAGES + " not found by thread local classloader");
- }
-
+ } else {
// 2011-03-27 jw: No privileged action required.
// A class can always access the classloader of itself and of subclasses.
- if (rb == null) {
rb = loadBundle(getClass().getClassLoader(), locale,
USER_VALIDATION_MESSAGES + " not found by validator classloader");
}
if (LOG_FINEST) {
- if (rb != null) {
- log.log(Level.FINEST, String.format("%s found", USER_VALIDATION_MESSAGES));
- } else {
+ if (rb == null) {
log.log(Level.FINEST, String.format("%s not found. Delegating to %s", USER_VALIDATION_MESSAGES,
DEFAULT_VALIDATION_MESSAGES));
+ } else {
+ log.log(Level.FINEST, String.format("%s found", USER_VALIDATION_MESSAGES));
}
}
return rb;
}
private ResourceBundle loadBundle(ClassLoader classLoader, Locale locale, String message) {
- ResourceBundle rb = null;
try {
- rb = ResourceBundle.getBundle(USER_VALIDATION_MESSAGES, locale, classLoader);
+ return ResourceBundle.getBundle(USER_VALIDATION_MESSAGES, locale, classLoader);
} catch (final MissingResourceException e) {
log.fine(message);
}
- return rb;
+ return null;
}
private String replaceVariables(String message, ResourceBundle bundle, Locale locale, boolean recurse) {
final Matcher matcher = messageParameterPattern.matcher(message);
final StringBuffer sb = new StringBuffer(64);
- String resolvedParameterValue;
while (matcher.find()) {
final String parameter = matcher.group(1);
- resolvedParameterValue = resolveParameter(parameter, bundle, locale, recurse);
-
+ String resolvedParameterValue = resolveParameter(parameter, bundle, locale, recurse);
matcher.appendReplacement(sb, sanitizeForAppendReplacement(resolvedParameterValue));
}
matcher.appendTail(sb);
@@ -242,13 +237,13 @@ public class DefaultMessageInterpolator implements MessageInterpolator {
private String resolveParameter(String parameterName, ResourceBundle bundle, Locale locale, boolean recurse) {
String parameterValue;
try {
- if (bundle != null) {
+ if (bundle == null) {
+ parameterValue = parameterName;
+ } else {
parameterValue = bundle.getString(removeCurlyBrace(parameterName));
if (recurse) {
parameterValue = replaceVariables(parameterValue, bundle, locale, recurse);
}
- } else {
- parameterValue = parameterName;
}
} catch (final MissingResourceException e) {
// return parameter itself
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultValidationProviderResolver.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultValidationProviderResolver.java b/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultValidationProviderResolver.java
index 671b0d9..e63bdf4 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultValidationProviderResolver.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultValidationProviderResolver.java
@@ -38,6 +38,11 @@ public class DefaultValidationProviderResolver implements ValidationProviderReso
//TODO - Spec recommends caching per classloader
private static final String SPI_CFG = "META-INF/services/javax.validation.spi.ValidationProvider";
+ private static ClassLoader getCurrentClassLoader() {
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ return cl == null ? DefaultValidationProviderResolver.class.getClassLoader() : cl;
+ }
+
/**
* {@inheritDoc}
*/
@@ -46,43 +51,28 @@ public class DefaultValidationProviderResolver implements ValidationProviderReso
List<ValidationProvider<?>> providers = new ArrayList<ValidationProvider<?>>();
try {
// get our classloader
- ClassLoader cl = Thread.currentThread().getContextClassLoader();
- if (cl == null)
- cl = DefaultValidationProviderResolver.class.getClassLoader();
+ ClassLoader cl = getCurrentClassLoader();
// find all service provider cfgs
Enumeration<URL> cfgs = cl.getResources(SPI_CFG);
while (cfgs.hasMoreElements()) {
final URL url = cfgs.nextElement();
- BufferedReader br = null;
- try {
- br = new BufferedReader(new InputStreamReader(url.openStream()), 256);
- String line = br.readLine();
- // cfgs may contain multiple providers and/or comments
- while (line != null) {
- line = line.trim();
- if (!line.startsWith("#")) {
- try {
- // try loading the specified class
- @SuppressWarnings("rawtypes")
- final Class<? extends ValidationProvider> providerType =
- cl.loadClass(line).asSubclass(ValidationProvider.class);
- // create an instance to return
- providers
- .add(Reflection.newInstance(providerType.asSubclass(ValidationProvider.class)));
-
- } catch (ClassNotFoundException e) {
- throw new ValidationException(
- "Failed to load provider " + line + " configured in file " + url, e);
- }
+ try (BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()), 256)) {
+ br.lines().filter(s -> s.charAt(0) != '#').map(String::trim).forEach(line -> {
+ // cfgs may contain multiple providers and/or comments
+ try {
+ // try loading the specified class
+ @SuppressWarnings("rawtypes")
+ final Class<? extends ValidationProvider> providerType =
+ cl.loadClass(line).asSubclass(ValidationProvider.class);
+ // create an instance to return
+ providers.add(Reflection.newInstance(providerType));
+ } catch (ClassNotFoundException e) {
+ throw new ValidationException(
+ "Failed to load provider " + line + " configured in file " + url, e);
}
- line = br.readLine();
- }
+ });
} catch (IOException e) {
throw new ValidationException("Error trying to read " + url, e);
- } finally {
- if (br != null) {
- br.close();
- }
}
}
} catch (IOException e) {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/GraphBeanIdentity.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/GraphBeanIdentity.java b/bval-jsr/src/main/java/org/apache/bval/jsr/GraphBeanIdentity.java
index 3ec666e..26391e6 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/GraphBeanIdentity.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/GraphBeanIdentity.java
@@ -18,6 +18,8 @@
*/
package org.apache.bval.jsr;
+import java.util.Objects;
+
/**
* Class that stores the needed properties to avoid circular paths when
* validating an object graph.
@@ -80,32 +82,16 @@ public class GraphBeanIdentity {
*/
@Override
public boolean equals(Object obj) {
-
if (this == obj) {
return true;
}
-
- if (obj == null) {
- return false;
- }
-
if (!(obj instanceof GraphBeanIdentity)) {
return false;
}
-
GraphBeanIdentity other = (GraphBeanIdentity) obj;
- // Bean ref must be the same
- if (this.bean != other.bean) {
- return false;
- }
-
- // Group ref must be the same
- if (this.group != other.group) {
- return false;
- }
-
- return true;
+ // Bean ref must be the same; Group ref must be the same
+ return bean == other.bean && group == other.group;
}
/**
@@ -113,11 +99,7 @@ public class GraphBeanIdentity {
*/
@Override
public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((this.bean == null) ? 0 : this.bean.hashCode());
- result = prime * result + ((this.group == null) ? 0 : this.group.hashCode());
- return result;
+ return Objects.hash(bean, group);
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/GraphContext.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/GraphContext.java b/bval-jsr/src/main/java/org/apache/bval/jsr/GraphContext.java
new file mode 100644
index 0000000..26350d6
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/GraphContext.java
@@ -0,0 +1,95 @@
+/*
+ * 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;
+
+import javax.validation.Path;
+
+import org.apache.bval.jsr.util.NodeImpl;
+import org.apache.bval.jsr.util.PathImpl;
+import org.apache.bval.util.Validate;
+
+public class GraphContext {
+
+ private final ApacheFactoryContext validatorContext;
+ private final PathImpl path;
+ private final Object value;
+ private final GraphContext parent;
+
+ public GraphContext(ApacheFactoryContext validatorContext, PathImpl path, Object value) {
+ this(validatorContext, path, value, null);
+ }
+
+ private GraphContext(ApacheFactoryContext validatorContext, PathImpl path, Object value, GraphContext parent) {
+ super();
+ this.validatorContext = Validate.notNull(validatorContext, "validatorContext");
+ this.path = Validate.notNull(path, "path");
+ this.value = value;
+ this.parent = parent;
+ }
+
+ public ApacheFactoryContext getValidatorContext() {
+ return validatorContext;
+ }
+
+ public PathImpl getPath() {
+ return PathImpl.copy(path);
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public GraphContext child(NodeImpl node, Object value) {
+ Validate.notNull(node, "node");
+ final PathImpl p = PathImpl.copy(path);
+ p.addNode(node);
+ return new GraphContext(validatorContext, p, value, this);
+ }
+
+ public GraphContext child(Path p, Object value) {
+ Validate.notNull(p, "Path");
+ final PathImpl impl = PathImpl.copy(p);
+ Validate.isTrue(impl.isSubPathOf(path), "%s is not a subpath of %s", p, path);
+ return new GraphContext(validatorContext, impl, value, this);
+ }
+
+ public boolean isRoot() {
+ return parent == null;
+ }
+
+ public boolean isRecursive() {
+ GraphContext c = parent;
+ while (c != null) {
+ if (c.value == value) {
+ return true;
+ }
+ c = c.parent;
+ }
+ return false;
+ }
+
+ public GraphContext getParent() {
+ return parent;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s: %s at '%s'", getClass().getSimpleName(), value, path);
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/NodeBuilderCustomizableContextImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/NodeBuilderCustomizableContextImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/NodeBuilderCustomizableContextImpl.java
new file mode 100644
index 0000000..8200bfe
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/NodeBuilderCustomizableContextImpl.java
@@ -0,0 +1,89 @@
+/*
+ * 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;
+
+import org.apache.bval.jsr.util.LeafNodeBuilderCustomizableContextImpl;
+import org.apache.bval.jsr.util.NodeImpl;
+import org.apache.bval.jsr.util.PathImpl;
+
+import javax.validation.ConstraintValidatorContext;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.ContainerElementNodeBuilderCustomizableContext;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext;
+import javax.validation.ElementKind;
+
+public class NodeBuilderCustomizableContextImpl
+ implements ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext {
+ private final PathImpl path;
+ private final ConstraintValidatorContextImpl context;
+ private final String template;
+
+ public NodeBuilderCustomizableContextImpl(final ConstraintValidatorContextImpl parent, final String messageTemplate,
+ final PathImpl propertyPath) {
+ context = parent;
+ template = messageTemplate;
+ path = propertyPath;
+ }
+
+ @Override
+ public ConstraintValidatorContext.ConstraintViolationBuilder.NodeContextBuilder inIterable() {
+ path.getLeafNode().setInIterable(true);
+ return new NodeContextBuilderImpl(context, template, path);
+ }
+
+ @Override
+ public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext addNode(String name) {
+ path.addNode(new NodeImpl(name));
+ return this;
+ }
+
+ @Override
+ public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext addPropertyNode(
+ String name) {
+ final NodeImpl node = new NodeImpl.PropertyNodeImpl(name);
+ path.addNode(node);
+ return this;
+ }
+
+ @Override
+ public ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeBuilderCustomizableContext addBeanNode() {
+ final NodeImpl node = new NodeImpl.BeanNodeImpl();
+ path.addNode(node);
+ return null;
+// return new LeafNodeBuilderCustomizableContextImpl(context, template, path);
+ }
+
+ @Override
+ public ConstraintValidatorContext addConstraintViolation() {
+ context.addError(template, path);
+ return context;
+ }
+
+ @Override
+ public NodeBuilderCustomizableContext inContainer(Class<?> containerClass, Integer typeArgumentIndex) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public ContainerElementNodeBuilderCustomizableContext addContainerElementNode(String name, Class<?> containerType,
+ Integer typeArgumentIndex) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/NodeContextBuilderImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/NodeContextBuilderImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/NodeContextBuilderImpl.java
new file mode 100644
index 0000000..d1f191e
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/NodeContextBuilderImpl.java
@@ -0,0 +1,88 @@
+/*
+ * 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;
+
+import org.apache.bval.jsr.util.LeafNodeBuilderCustomizableContextImpl;
+import org.apache.bval.jsr.util.NodeBuilderDefinedContextImpl;
+import org.apache.bval.jsr.util.NodeImpl;
+import org.apache.bval.jsr.util.PathImpl;
+
+import javax.validation.ConstraintValidatorContext;
+import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.ContainerElementNodeBuilderCustomizableContext;
+import javax.validation.ElementKind;
+
+public class NodeContextBuilderImpl
+ implements ConstraintValidatorContext.ConstraintViolationBuilder.NodeContextBuilder {
+ private final PathImpl path;
+ private final String template;
+ private final ConstraintValidatorContextImpl context;
+
+ public NodeContextBuilderImpl(final ConstraintValidatorContextImpl context, final String template,
+ final PathImpl path) {
+ this.context = context;
+ this.template = template;
+ this.path = path;
+ }
+
+ @Override
+ public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderDefinedContext atKey(Object key) {
+ path.getLeafNode().setKey(key);
+ return null;
+// return new NodeBuilderDefinedContextImpl(context, template, path);
+ }
+
+ @Override
+ public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderDefinedContext atIndex(Integer index) {
+ path.getLeafNode().setIndex(index);
+ return null;
+// return new NodeBuilderDefinedContextImpl(context, template, path);
+ }
+
+ @Override
+ public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext addNode(String name) {
+ return new NodeBuilderCustomizableContextImpl(context, template, path).addNode(name);
+ }
+
+ @Override
+ public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext addPropertyNode(
+ String name) {
+ return new NodeBuilderCustomizableContextImpl(context, template, path).addPropertyNode(name);
+ }
+
+ @Override
+ public ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeBuilderCustomizableContext addBeanNode() {
+ final NodeImpl node = new NodeImpl.BeanNodeImpl();
+ path.addNode(node);
+ return null;
+// return new LeafNodeBuilderCustomizableContextImpl(context, template, path);
+ }
+
+ @Override
+ public ConstraintValidatorContext addConstraintViolation() {
+ context.addError(template, path);
+ return context;
+ }
+
+ @Override
+ public ContainerElementNodeBuilderCustomizableContext addContainerElementNode(String name, Class<?> containerType,
+ Integer typeArgumentIndex) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/ParameterDescriptorImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ParameterDescriptorImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ParameterDescriptorImpl.java
index 187fd7e..65f3ecc 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ParameterDescriptorImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ParameterDescriptorImpl.java
@@ -21,6 +21,7 @@ import org.apache.bval.jsr.groups.GroupConversionDescriptorImpl;
import org.apache.bval.model.MetaBean;
import org.apache.bval.model.Validation;
+import javax.validation.metadata.ContainerElementTypeDescriptor;
import javax.validation.metadata.GroupConversionDescriptor;
import javax.validation.metadata.ParameterDescriptor;
import java.util.Set;
@@ -86,4 +87,10 @@ public class ParameterDescriptorImpl extends ElementDescriptorImpl implements Pa
groupConversions.add(new GroupConversionDescriptorImpl(from, to));
super.addGroupMapping(from, to);
}
+
+ @Override
+ public Set<ContainerElementTypeDescriptor> getConstrainedContainerElementTypes() {
+ // TODO Auto-generated method stub
+ return null;
+ }
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/PropertyDescriptorImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/PropertyDescriptorImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/PropertyDescriptorImpl.java
index 7f7c56d..03cf5de 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/PropertyDescriptorImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/PropertyDescriptorImpl.java
@@ -21,6 +21,9 @@ package org.apache.bval.jsr;
import org.apache.bval.model.Features;
import org.apache.bval.model.MetaProperty;
+import java.util.Set;
+
+import javax.validation.metadata.ContainerElementTypeDescriptor;
import javax.validation.metadata.PropertyDescriptor;
/**
@@ -67,4 +70,10 @@ class PropertyDescriptorImpl extends ElementDescriptorImpl implements PropertyDe
return "PropertyDescriptorImpl{" + "returnType=" + elementClass + ", propertyPath='" + propertyPath + '\''
+ '}';
}
+
+ @Override
+ public Set<ContainerElementTypeDescriptor> getConstrainedContainerElementTypes() {
+ // TODO Auto-generated method stub
+ return null;
+ }
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/ReturnValueDescriptorImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ReturnValueDescriptorImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ReturnValueDescriptorImpl.java
index b1fc72d..a6faa9b 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ReturnValueDescriptorImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ReturnValueDescriptorImpl.java
@@ -18,8 +18,10 @@ package org.apache.bval.jsr;
import org.apache.bval.model.MetaBean;
+import javax.validation.metadata.ContainerElementTypeDescriptor;
import javax.validation.metadata.ReturnValueDescriptor;
import java.util.Collection;
+import java.util.Set;
public class ReturnValueDescriptorImpl extends ElementDescriptorImpl implements ReturnValueDescriptor {
public ReturnValueDescriptorImpl(final MetaBean metaBean, Class<?> returnType,
@@ -32,4 +34,10 @@ public class ReturnValueDescriptorImpl extends ElementDescriptorImpl implements
public boolean hasConstraints() {
return false;
}
+
+ @Override
+ public Set<ContainerElementTypeDescriptor> getConstrainedContainerElementTypes() {
+ // TODO Auto-generated method stub
+ return null;
+ }
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/ValidatorImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ValidatorImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ValidatorImpl.java
new file mode 100644
index 0000000..606e191
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ValidatorImpl.java
@@ -0,0 +1,141 @@
+/*
+ * 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;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Set;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.ValidationException;
+import javax.validation.executable.ExecutableValidator;
+import javax.validation.metadata.BeanDescriptor;
+
+import org.apache.bval.jsr.job.ValidationJobFactory;
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.Reflection;
+
+public class ValidatorImpl implements CascadingPropertyValidator, ExecutableValidator {
+
+ private final ApacheFactoryContext validatorContext;
+ private final ValidationJobFactory validationJobFactory;
+
+ ValidatorImpl(ApacheFactoryContext validatorContext) {
+ super();
+ this.validatorContext = Validate.notNull(validatorContext, "validatorContext");
+ this.validationJobFactory = new ValidationJobFactory(validatorContext);
+ }
+
+ @Override
+ public BeanDescriptor getConstraintsForClass(Class<?> clazz) {
+ return validatorContext.getDescriptorManager().getBeanDescriptor(clazz);
+ }
+
+ @Override
+ public <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) {
+ return validationJobFactory.validateBean(object, groups).getResults();
+ }
+
+ @Override
+ public <T> Set<ConstraintViolation<T>> validateProperty(T object, String propertyName, boolean cascade,
+ Class<?>... groups) {
+ return validationJobFactory.validateProperty(object, propertyName, groups).cascade(cascade).getResults();
+ }
+
+ @Override
+ public <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value,
+ boolean cascade, Class<?>... groups) {
+ return validationJobFactory.validateValue(beanType, propertyName, value, groups).cascade(cascade).getResults();
+ }
+
+ @Override
+ public ExecutableValidator forExecutables() {
+ return this;
+ }
+
+ @Override
+ public <T> Set<ConstraintViolation<T>> validateParameters(T object, Method method, Object[] parameterValues,
+ Class<?>... groups) {
+ return validationJobFactory.validateParameters(object, method, parameterValues, groups).getResults();
+ }
+
+ @Override
+ public <T> Set<ConstraintViolation<T>> validateReturnValue(T object, Method method, Object returnValue,
+ Class<?>... groups) {
+ return validationJobFactory.validateReturnValue(object, method, returnValue, groups).getResults();
+ }
+
+ @Override
+ public <T> Set<ConstraintViolation<T>> validateConstructorParameters(Constructor<? extends T> constructor,
+ Object[] parameterValues, Class<?>... groups) {
+ return validationJobFactory.<T> validateConstructorParameters(constructor, parameterValues, groups)
+ .getResults();
+ }
+
+ @Override
+ public <T> Set<ConstraintViolation<T>> validateConstructorReturnValue(Constructor<? extends T> constructor,
+ T createdObject, Class<?>... groups) {
+ return validationJobFactory.<T> validateConstructorReturnValue(constructor, createdObject, groups).getResults();
+ }
+
+ @Override
+ public <T> T unwrap(Class<T> type) {
+ // FIXME 2011-03-27 jw:
+ // This code is unsecure.
+ // It should allow only a fixed set of classes.
+ // Can't fix this because don't know which classes this method should support.
+
+ if (type.isAssignableFrom(getClass())) {
+ @SuppressWarnings("unchecked")
+ final T result = (T) this;
+ return result;
+ }
+ if (!(type.isInterface() || Modifier.isAbstract(type.getModifiers()))) {
+ return newInstance(type);
+ }
+ try {
+ final Class<?> cls = Reflection.toClass(type.getName() + "Impl");
+ if (type.isAssignableFrom(cls)) {
+ @SuppressWarnings("unchecked")
+ final Class<? extends T> implClass = (Class<? extends T>) cls;
+ return newInstance(implClass);
+ }
+ } catch (ClassNotFoundException e) {
+ }
+ throw new ValidationException("Type " + type + " not supported");
+ }
+
+ private <T> T newInstance(final Class<T> cls) {
+ final Constructor<T> cons = Reflection.getDeclaredConstructor(cls, ApacheFactoryContext.class);
+ if (cons == null) {
+ throw new ValidationException("Cannot instantiate " + cls);
+ }
+ final boolean mustUnset = Reflection.setAccessible(cons, true);
+ try {
+ return cons.newInstance(validatorContext);
+ } catch (final Exception ex) {
+ throw new ValidationException("Cannot instantiate " + cls, ex);
+ } finally {
+ if (mustUnset) {
+ Reflection.setAccessible(cons, false);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/BeanD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/BeanD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/BeanD.java
new file mode 100644
index 0000000..7f52c6d
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/BeanD.java
@@ -0,0 +1,128 @@
+/*
+ * 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.descriptor;
+
+import java.lang.reflect.Type;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import javax.validation.metadata.BeanDescriptor;
+import javax.validation.metadata.ConstructorDescriptor;
+import javax.validation.metadata.MethodDescriptor;
+import javax.validation.metadata.MethodType;
+import javax.validation.metadata.PropertyDescriptor;
+
+import org.apache.bval.jsr.metadata.Signature;
+import org.apache.bval.jsr.util.ToUnmodifiable;
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.Lazy;
+import org.apache.bval.util.StringUtils;
+
+public class BeanD extends ElementD<Class<?>, MetadataReader.ForBean> implements BeanDescriptor {
+
+ private static boolean constrainedProperty(PropertyDescriptor pd) {
+ return pd.hasConstraints() || pd.isCascaded();
+ }
+
+ private final Class<?> beanClass;
+
+ private final Lazy<List<Class<?>>> groupSequence;
+ private final Lazy<Map<String, PropertyDescriptor>> propertiesMap;
+ private final Lazy<Set<PropertyDescriptor>> properties;
+ private final Lazy<Map<Signature, ConstructorD>> constructors;
+ private final Lazy<Map<Signature, MethodD>> methods;
+
+ BeanD(MetadataReader.ForBean reader) {
+ super(reader);
+ this.beanClass = reader.meta.getHost();
+
+ groupSequence = new Lazy<>(reader::getGroupSequence);
+ propertiesMap = new Lazy<>(() -> reader.getProperties(this));
+ properties = new Lazy<>(() -> propertiesMap.get().values().stream().filter(BeanD::constrainedProperty)
+ .collect(ToUnmodifiable.set()));
+ constructors = new Lazy<>(() -> reader.getConstructors(this));
+ methods = new Lazy<>(() -> reader.getMethods(this));
+ }
+
+ @Override
+ public Class<?> getElementClass() {
+ return beanClass;
+ }
+
+ @Override
+ public boolean isBeanConstrained() {
+ return hasConstraints() || properties.get().stream().anyMatch(DescriptorManager::isConstrained);
+ }
+
+ @Override
+ public PropertyDescriptor getConstraintsForProperty(String propertyName) {
+ return Optional.ofNullable(getProperty(propertyName)).filter(BeanD::constrainedProperty).orElse(null);
+ }
+
+ @Override
+ public Set<PropertyDescriptor> getConstrainedProperties() {
+ return properties.get();
+ }
+
+ @Override
+ public MethodDescriptor getConstraintsForMethod(String methodName, Class<?>... parameterTypes) {
+ return methods.get().get(new Signature(methodName, parameterTypes));
+ }
+
+ @SuppressWarnings("unlikely-arg-type")
+ @Override
+ public Set<MethodDescriptor> getConstrainedMethods(MethodType methodType, MethodType... methodTypes) {
+ return methods.get().values().stream().filter(EnumSet.of(methodType, methodTypes)::contains)
+ .collect(ToUnmodifiable.set());
+ }
+
+ @Override
+ public ConstructorDescriptor getConstraintsForConstructor(Class<?>... parameterTypes) {
+ return constructors.get().get(new Signature(beanClass.getName(), parameterTypes));
+ }
+
+ @Override
+ public Set<ConstructorDescriptor> getConstrainedConstructors() {
+ return constructors.get().values().stream().collect(ToUnmodifiable.set());
+ }
+
+ public PropertyDescriptor getProperty(String propertyName) {
+ Exceptions.raiseIf(StringUtils.isBlank(propertyName), IllegalArgumentException::new,
+ "propertyName was null/empty/blank");
+
+ return propertiesMap.get().get(propertyName);
+ }
+
+ @Override
+ protected BeanD getBean() {
+ return this;
+ }
+
+ @Override
+ public List<Class<?>> getGroupSequence() {
+ return groupSequence.get();
+ }
+
+ public final Type getGenericType() {
+ return getElementClass();
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CascadableContainerD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CascadableContainerD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CascadableContainerD.java
new file mode 100644
index 0000000..8c76fb0
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CascadableContainerD.java
@@ -0,0 +1,88 @@
+/*
+ * 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.descriptor;
+
+import java.lang.reflect.AnnotatedElement;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import javax.validation.ValidationException;
+import javax.validation.metadata.CascadableDescriptor;
+import javax.validation.metadata.ContainerDescriptor;
+import javax.validation.metadata.ContainerElementTypeDescriptor;
+import javax.validation.metadata.GroupConversionDescriptor;
+
+import org.apache.bval.jsr.GraphContext;
+import org.apache.bval.jsr.util.ToUnmodifiable;
+import org.apache.bval.util.Lazy;
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.TypeUtils;
+
+public abstract class CascadableContainerD<P extends ElementD<?, ?>, E extends AnnotatedElement> extends
+ ElementD.NonRoot<P, E, MetadataReader.ForContainer<E>> implements CascadableDescriptor, ContainerDescriptor {
+
+ private final boolean cascaded;
+ private final Set<GroupConversion> groupConversions;
+ private final Lazy<Set<ContainerElementTypeD>> containerElementTypes;
+
+ protected CascadableContainerD(MetadataReader.ForContainer<E> reader, P parent) {
+ super(reader, parent);
+ cascaded = reader.isCascaded();
+ groupConversions = reader.getGroupConversions();
+ containerElementTypes = new Lazy<>(() -> reader.getContainerElementTypes(this));
+ }
+
+ @Override
+ public Class<?> getElementClass() {
+ return TypeUtils.getRawType(getGenericType(), parent.getElementClass());
+ }
+
+ @Override
+ public boolean isCascaded() {
+ return cascaded;
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Override
+ public Set<GroupConversionDescriptor> getGroupConversions() {
+ return (Set) groupConversions;
+ }
+
+ @Override
+ public Set<ContainerElementTypeDescriptor> getConstrainedContainerElementTypes() {
+ return containerElementTypes.get().stream().filter(DescriptorManager::isConstrained)
+ .collect(ToUnmodifiable.set());
+ }
+
+ public final Stream<GraphContext> read(GraphContext context) {
+ Validate.notNull(context);
+ if (context.getValue() == null) {
+ return Stream.empty();
+ }
+ try {
+ return readImpl(context);
+ } catch (Exception e) {
+ throw new ValidationException(e);
+ }
+ }
+
+ protected Stream<GraphContext> readImpl(GraphContext context) throws Exception {
+ throw new UnsupportedOperationException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComposedD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComposedD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComposedD.java
new file mode 100644
index 0000000..6d3b004
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComposedD.java
@@ -0,0 +1,123 @@
+/*
+ * 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.descriptor;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import javax.validation.metadata.CascadableDescriptor;
+import javax.validation.metadata.ConstraintDescriptor;
+import javax.validation.metadata.ContainerDescriptor;
+import javax.validation.metadata.ContainerElementTypeDescriptor;
+import javax.validation.metadata.ElementDescriptor;
+import javax.validation.metadata.GroupConversionDescriptor;
+import javax.validation.metadata.PropertyDescriptor;
+
+import org.apache.bval.jsr.util.ToUnmodifiable;
+import org.apache.bval.util.Validate;
+
+public abstract class ComposedD<D extends ElementD<?, ?>> implements ElementDescriptor {
+
+ static abstract class ForCascadableContainer<D extends CascadableContainerD<?, ?>> extends ComposedD<D>
+ implements CascadableDescriptor, ContainerDescriptor {
+
+ ForCascadableContainer(List<D> delegates) {
+ super(delegates);
+ }
+
+ @Override
+ public Set<ContainerElementTypeDescriptor> getConstrainedContainerElementTypes() {
+ return delegates.stream().map(ContainerDescriptor::getConstrainedContainerElementTypes)
+ .flatMap(Collection::stream).collect(ToUnmodifiable.set());
+ }
+
+ @Override
+ public boolean isCascaded() {
+ return delegates.stream().anyMatch(CascadableDescriptor::isCascaded);
+ }
+
+ @Override
+ public Set<GroupConversionDescriptor> getGroupConversions() {
+ return delegates.stream().map(CascadableDescriptor::getGroupConversions).flatMap(Collection::stream)
+ .collect(ToUnmodifiable.set());
+ }
+ }
+
+ static class ForProperty extends ComposedD.ForCascadableContainer<PropertyD<?>> implements PropertyDescriptor {
+
+ ForProperty(List<PropertyD<?>> delegates) {
+ super(delegates);
+ }
+
+ @Override
+ public String getPropertyName() {
+ return delegates.stream().map(PropertyDescriptor::getPropertyName).findFirst()
+ .orElseThrow(IllegalStateException::new);
+ }
+ }
+
+ public static <T extends ElementD<?, ?>> Stream<T> unwrap(ElementDescriptor descriptor, Class<T> delegateType) {
+ final Stream<?> s;
+
+ if (descriptor instanceof ComposedD<?>) {
+ s = ((ComposedD<?>) descriptor).delegates.stream()
+ // unwrap recursively:
+ .flatMap(d -> unwrap(d, delegateType));
+ } else {
+ s = Stream.of(descriptor);
+ }
+ return s.map(delegateType::cast);
+ }
+
+ protected final List<D> delegates;
+
+ ComposedD(List<D> delegates) {
+ super();
+ this.delegates = delegates;
+
+ Validate.notNull(delegates, "delegates");
+ Validate.isTrue(!delegates.isEmpty(), "At least one delegate is required");
+ Validate.isTrue(delegates.stream().noneMatch(Objects::isNull), "null delegates not permitted");
+ }
+
+ @Override
+ public boolean hasConstraints() {
+ return delegates.stream().anyMatch(ElementDescriptor::hasConstraints);
+ }
+
+ @Override
+ public Class<?> getElementClass() {
+ return delegates.stream().map(ElementDescriptor::getElementClass).findFirst()
+ .orElseThrow(IllegalStateException::new);
+ }
+
+ @Override
+ public Set<ConstraintDescriptor<?>> getConstraintDescriptors() {
+ return delegates.stream().map(ElementDescriptor::getConstraintDescriptors).flatMap(Collection::stream)
+ .collect(ToUnmodifiable.set());
+ }
+
+ @Override
+ public ConstraintFinder findConstraints() {
+ return new Finder(this);
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComputeConstraintValidatorClass.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComputeConstraintValidatorClass.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComputeConstraintValidatorClass.java
new file mode 100644
index 0000000..7eeefd2
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComputeConstraintValidatorClass.java
@@ -0,0 +1,183 @@
+package org.apache.bval.jsr.descriptor;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.WildcardType;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import javax.validation.ConstraintDefinitionException;
+import javax.validation.ConstraintValidator;
+import javax.validation.UnexpectedTypeException;
+import javax.validation.constraintvalidation.ValidationTarget;
+
+import org.apache.bval.jsr.ApacheValidatorFactory;
+import org.apache.bval.jsr.ConstraintCached.ConstraintValidatorInfo;
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.Reflection;
+import org.apache.bval.util.reflection.Reflection.Interfaces;
+import org.apache.bval.util.reflection.TypeUtils;
+import org.apache.commons.weaver.privilizer.Privilizing;
+import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
+
+@Privilizing(@CallTo(Reflection.class))
+class ComputeConstraintValidatorClass<A extends Annotation>
+ implements Supplier<Class<? extends ConstraintValidator<A, ?>>> {
+
+ private static class TypeWrapper {
+ final Class<?> componentType;
+ final int arrayDepth;
+
+ TypeWrapper(Class<?> type) {
+ Class<?> c = type;
+ int d = 0;
+ while (Object[].class.isAssignableFrom(c)) {
+ d++;
+ c = c.getComponentType();
+ }
+ this.componentType = c;
+ this.arrayDepth = d;
+ }
+
+ Class<?> unwrap(Class<?> t) {
+ Exceptions.raiseUnless(t.isAssignableFrom(componentType), IllegalArgumentException::new,
+ "%s not assignable from %s", t, componentType);
+ if (arrayDepth == 0) {
+ return t;
+ }
+ return Array.newInstance(t, new int[arrayDepth]).getClass();
+ }
+ }
+
+ private static final String CV = ConstraintValidator.class.getSimpleName();
+ private static final WildcardType UNBOUNDED = TypeUtils.wildcardType().build();
+
+ private static Class<?> getValidatedType(Class<? extends ConstraintValidator<?, ?>> validatorType) {
+ final Type result = TypeUtils.getTypeArguments(validatorType, ConstraintValidator.class)
+ .get(ConstraintValidator.class.getTypeParameters()[1]);
+ Exceptions.raiseUnless(isSupported(result), ConstraintDefinitionException::new,
+ "Validated type %s declared by %s %s is unsupported", result, CV, validatorType.getName());
+ return TypeUtils.getRawType(result, null);
+ }
+
+ private static boolean isSupported(Type validatedType) {
+ if (validatedType instanceof Class<?>) {
+ return true;
+ }
+ if (validatedType instanceof ParameterizedType) {
+ return Stream.of(((ParameterizedType) validatedType).getActualTypeArguments())
+ .allMatch(arg -> TypeUtils.equals(arg, UNBOUNDED));
+ }
+ return false;
+ }
+
+ private final ApacheValidatorFactory validatorFactory;
+ private final Class<?> validatedType;
+ private final ValidationTarget validationTarget;
+ private final A constraint;
+ private final boolean composed;
+
+ ComputeConstraintValidatorClass(ApacheValidatorFactory validatorFactory, ValidationTarget validationTarget,
+ A constraint, Class<?> validatedType) {
+ super();
+ this.validatorFactory = Validate.notNull(validatorFactory, "validatorFactory");
+ this.validationTarget = Validate.notNull(validationTarget, "validationTarget");
+ this.constraint = Validate.notNull(constraint, "constraint");
+ this.validatedType = Validate.notNull(validatedType, "validatedType");
+ this.composed = validatorFactory.getAnnotationsManager().isComposed(constraint);
+ }
+
+ @Override
+ public Class<? extends ConstraintValidator<A, ?>> get() {
+ @SuppressWarnings("unchecked")
+ final Class<A> constraintType = (Class<A>) constraint.annotationType();
+ return findValidator(validatorFactory.getConstraintsCache().getConstraintValidatorInfo(constraintType));
+ }
+
+ private Class<? extends ConstraintValidator<A, ?>> findValidator(Set<ConstraintValidatorInfo<A>> infos) {
+ switch (validationTarget) {
+ case PARAMETERS:
+ return findCrossParameterValidator(infos);
+ case ANNOTATED_ELEMENT:
+ return findAnnotatedElementValidator(infos);
+ default:
+ return null;
+ }
+ }
+
+ private Class<? extends ConstraintValidator<A, ?>> findCrossParameterValidator(
+ Set<ConstraintValidatorInfo<A>> infos) {
+
+ final Set<ConstraintValidatorInfo<A>> set =
+ infos.stream().filter(info -> info.getSupportedTargets().contains(ValidationTarget.PARAMETERS))
+ .collect(Collectors.toSet());
+
+ @SuppressWarnings("unchecked")
+ final Class<A> constraintType = (Class<A>) constraint.annotationType();
+
+ Exceptions.raiseIf(set.size() > 1 || !composed && set.isEmpty(), UnexpectedTypeException::new,
+ "%d cross-parameter %ss found for constraint type %s", set.size(), CV, constraintType);
+
+ final Class<? extends ConstraintValidator<A, ?>> result = set.iterator().next().getType();
+ Exceptions.raiseUnless(TypeUtils.isAssignable(Object[].class, getValidatedType(result)),
+ ConstraintDefinitionException::new,
+ "Cross-parameter %s %s does not support the validation of an object array", CV, result.getName());
+
+ return result;
+ }
+
+ private Class<? extends ConstraintValidator<A, ?>> findAnnotatedElementValidator(
+ Set<ConstraintValidatorInfo<A>> infos) {
+
+ final Map<Class<?>, Class<? extends ConstraintValidator<?, ?>>> validators =
+ infos.stream().filter(info -> info.getSupportedTargets().contains(ValidationTarget.ANNOTATED_ELEMENT))
+ .map(ConstraintValidatorInfo::getType)
+ .collect(Collectors.toMap(ComputeConstraintValidatorClass::getValidatedType, Function.identity()));
+
+ final Map<Type, Class<? extends ConstraintValidator<?, ?>>> candidates = new HashMap<>();
+
+ walkHierarchy().filter(validators::containsKey).forEach(type -> {
+ // if we haven't already found a candidate whose validated type
+ // is a subtype of the current evaluated type, save:
+ if (!candidates.keySet().stream().anyMatch(k -> TypeUtils.isAssignable(k, type))) {
+ candidates.put(type, validators.get(type));
+ }
+ });
+ final String cond;
+ switch (candidates.size()) {
+ case 1:
+ @SuppressWarnings("unchecked")
+ final Class<? extends ConstraintValidator<A, ?>> result =
+ (Class<? extends ConstraintValidator<A, ?>>) candidates.values().iterator().next();
+ return result;
+ case 0:
+ if (composed) {
+ return null;
+ }
+ cond = "No compliant";
+ break;
+ default:
+ cond = "> 1 maximally specific";
+ break;
+ }
+ throw Exceptions.create(UnexpectedTypeException::new, "%s %s %s found for annotated element of type %s", cond,
+ constraint.annotationType().getName(), CV, TypeUtils.toString(validatedType));
+ }
+
+ // account for validated array types by unwrapping and rewrapping component
+ // type hierarchy:
+ private Stream<Class<?>> walkHierarchy() {
+ final TypeWrapper w = new TypeWrapper(Reflection.primitiveToWrapper(validatedType));
+ Stream.Builder<Class<?>> hierarchy = Stream.builder();
+ Reflection.hierarchy(w.componentType, Interfaces.INCLUDE).forEach(hierarchy);
+ return hierarchy.build().map(w::unwrap);
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstraintD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstraintD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstraintD.java
new file mode 100644
index 0000000..0c1be1b
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstraintD.java
@@ -0,0 +1,276 @@
+/*
+ * 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.descriptor;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+import javax.validation.ConstraintDeclarationException;
+import javax.validation.ConstraintDefinitionException;
+import javax.validation.ConstraintTarget;
+import javax.validation.ConstraintValidator;
+import javax.validation.Payload;
+import javax.validation.ReportAsSingleViolation;
+import javax.validation.UnexpectedTypeException;
+import javax.validation.ValidationException;
+import javax.validation.groups.Default;
+import javax.validation.metadata.ConstraintDescriptor;
+import javax.validation.metadata.Scope;
+import javax.validation.metadata.ValidateUnwrappedValue;
+import javax.validation.valueextraction.UnwrapByDefault;
+import javax.validation.valueextraction.Unwrapping;
+import javax.validation.valueextraction.Unwrapping.Skip;
+import javax.validation.valueextraction.Unwrapping.Unwrap;
+import javax.validation.valueextraction.ValueExtractor;
+
+import org.apache.bval.jsr.ApacheValidatorFactory;
+import org.apache.bval.jsr.ConstraintAnnotationAttributes;
+import org.apache.bval.jsr.ConstraintAnnotationAttributes.Worker;
+import org.apache.bval.jsr.metadata.ContainerElementKey;
+import org.apache.bval.jsr.metadata.Metas;
+import org.apache.bval.jsr.util.AnnotationsManager;
+import org.apache.bval.jsr.util.ToUnmodifiable;
+import org.apache.bval.jsr.valueextraction.ValueExtractors;
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.Lazy;
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.TypeUtils;
+
+public class ConstraintD<A extends Annotation> implements ConstraintDescriptor<A> {
+ private static <T> Set<T> set(Supplier<T[]> array) {
+ return Stream.of(array.get()).collect(ToUnmodifiable.set());
+ }
+
+ private final A annotation;
+ private final Scope scope;
+ private final Metas<?> meta;
+ private final Class<?> validatedType;
+
+ private final Lazy<Set<Class<?>>> groups = new Lazy<>(this::computeGroups);
+
+ private final Set<Class<? extends Payload>> payload;
+
+ private final Lazy<Boolean> reportAsSingle =
+ new Lazy<>(() -> getAnnotation().annotationType().isAnnotationPresent(ReportAsSingleViolation.class));
+
+ private final Lazy<ValidateUnwrappedValue> valueUnwrapping = new Lazy<>(this::computeValidateUnwrappedValue);
+
+ private final Lazy<Map<String, Object>> attributes;
+ private final Lazy<Set<ConstraintDescriptor<?>>> composingConstraints;
+ private final Lazy<List<Class<? extends ConstraintValidator<A, ?>>>> constraintValidatorClasses;
+ private final Lazy<Class<? extends ConstraintValidator<A, ?>>> constraintValidatorClass;
+
+ public ConstraintD(A annotation, Scope scope, Metas<?> meta, ApacheValidatorFactory validatorFactory) {
+ this.annotation = Validate.notNull(annotation, "annotation");
+ this.scope = Validate.notNull(scope, "scope");
+ this.meta = Validate.notNull(meta, "meta");
+ this.payload = computePayload();
+ this.validatedType = computeValidatedType(validatorFactory);
+
+ attributes = new Lazy<>(() -> AnnotationsManager.readAttributes(annotation));
+
+ // retain no references to the validatorFactory; only wrap it in lazy
+ // suppliers
+ Validate.notNull(validatorFactory, "validatorFactory");
+ composingConstraints = new Lazy<>(computeComposingConstraints(validatorFactory));
+ constraintValidatorClasses = new Lazy<>(computeConstraintValidatorClasses(validatorFactory));
+
+ final Supplier<Class<? extends ConstraintValidator<A, ?>>> computeConstraintValidatorClass =
+ new ComputeConstraintValidatorClass<>(validatorFactory, meta.getValidationTarget(), annotation,
+ validatedType);
+
+ constraintValidatorClass = new Lazy<>(computeConstraintValidatorClass);
+ }
+
+ @Override
+ public A getAnnotation() {
+ return annotation;
+ }
+
+ @Override
+ public Set<Class<?>> getGroups() {
+ return groups.get();
+ }
+
+ @Override
+ public Set<Class<? extends Payload>> getPayload() {
+ return payload;
+ }
+
+ @Override
+ public List<Class<? extends ConstraintValidator<A, ?>>> getConstraintValidatorClasses() {
+ return constraintValidatorClasses.get();
+ }
+
+ @Override
+ public Map<String, Object> getAttributes() {
+ return attributes.get();
+ }
+
+ @Override
+ public Set<ConstraintDescriptor<?>> getComposingConstraints() {
+ return composingConstraints.get();
+ }
+
+ @Override
+ public boolean isReportAsSingleViolation() {
+ return reportAsSingle.get().booleanValue();
+ }
+
+ @Override
+ public String getMessageTemplate() {
+ final boolean required = true;
+ return read(ConstraintAnnotationAttributes.MESSAGE, required);
+ }
+
+ @Override
+ public ConstraintTarget getValidationAppliesTo() {
+ return read(ConstraintAnnotationAttributes.VALIDATION_APPLIES_TO);
+ }
+
+ @Override
+ public ValidateUnwrappedValue getValueUnwrapping() {
+ return valueUnwrapping.get();
+ }
+
+ @Override
+ public <U> U unwrap(Class<U> type) throws ValidationException {
+ try {
+ return type.cast(this);
+ } catch (ClassCastException e) {
+ throw new ValidationException(e);
+ }
+ }
+
+ public Scope getScope() {
+ return scope;
+ }
+
+ public Class<?> getDeclaringClass() {
+ return meta.getDeclaringClass();
+ }
+
+ public ElementType getDeclaredOn() {
+ return meta.getElementType();
+ }
+
+ public Class<?> getValidatedType() {
+ return validatedType;
+ }
+
+ public Class<? extends ConstraintValidator<A, ?>> getConstraintValidatorClass() {
+ return constraintValidatorClass.get();
+ }
+
+ private <T> T read(ConstraintAnnotationAttributes attr) {
+ return read(attr, false);
+ }
+
+ private <T> T read(ConstraintAnnotationAttributes attr, boolean required) {
+ final Class<? extends Annotation> constraintType = annotation.annotationType();
+ final Optional<T> result =
+ Optional.of(constraintType).map(attr::analyze).filter(Worker::isValid).map(w -> w.<T> read(annotation));
+
+ Exceptions.raiseIf(required && !result.isPresent(), ConstraintDefinitionException::new,
+ "Required attribute %s missing from constraint type %s", attr.getAttributeName(), constraintType);
+
+ return result.orElse(null);
+ }
+
+ private Supplier<Set<ConstraintDescriptor<?>>> computeComposingConstraints(
+ ApacheValidatorFactory validatorFactory) {
+ return () -> Stream.of(validatorFactory.getAnnotationsManager().getComposingConstraints(annotation))
+ .map(c -> new ConstraintD<>(c, scope, meta, validatorFactory))
+ .collect(ToUnmodifiable.set(LinkedHashSet::new));
+ }
+
+ @SuppressWarnings("unchecked")
+ private Supplier<List<Class<? extends ConstraintValidator<A, ?>>>> computeConstraintValidatorClasses(
+ ApacheValidatorFactory validatorFactory) {
+ return () -> validatorFactory.getConstraintsCache()
+ .getConstraintValidatorClasses((Class<A>) annotation.annotationType());
+ }
+
+ private ValidateUnwrappedValue computeValidateUnwrappedValue() {
+ final Set<Class<? extends Payload>> p = getPayload();
+ final boolean unwrap = p.contains(Unwrap.class);
+ final boolean skip = p.contains(Skip.class);
+ if (unwrap) {
+ Validate.validState(!skip, "Cannot specify both %s and %s", Unwrap.class.getSimpleName(),
+ Skip.class.getSimpleName());
+ return ValidateUnwrappedValue.UNWRAP;
+ }
+ return skip ? ValidateUnwrappedValue.SKIP : ValidateUnwrappedValue.DEFAULT;
+ }
+
+ private Set<Class<?>> computeGroups() {
+ final boolean required = true;
+ final Class<?>[] groups = read(ConstraintAnnotationAttributes.GROUPS, required);
+ if (groups.length == 0) {
+ return Collections.singleton(Default.class);
+ }
+ return set(() -> groups);
+ }
+
+ private Set<Class<? extends Payload>> computePayload() {
+ final boolean required = true;
+ final Set<Class<? extends Payload>> result = set(() -> read(ConstraintAnnotationAttributes.PAYLOAD, required));
+ Exceptions.raiseIf(result.containsAll(Arrays.asList(Unwrapping.Unwrap.class, Unwrapping.Skip.class)),
+ ConstraintDeclarationException::new,
+ "Constraint %s declared at %s specifies conflicting value unwrapping hints", annotation, meta.getHost());
+ return result;
+ }
+
+ private Class<?> computeValidatedType(ApacheValidatorFactory validatorFactory) {
+ final Class<?> rawType = TypeUtils.getRawType(meta.getType(), null);
+
+ Exceptions.raiseIf(rawType == null, UnexpectedTypeException::new, "Could not calculate validated type from %s",
+ meta.getType());
+
+ if (payload.contains(Unwrapping.Skip.class)) {
+ return rawType;
+ }
+ final ValueExtractor<?> valueExtractor =
+ validatorFactory.getValueExtractors().find(new ContainerElementKey(meta.getAnnotatedType(), null));
+
+ final boolean unwrap = payload.contains(Unwrapping.Unwrap.class);
+
+ if (valueExtractor == null) {
+ Exceptions.raiseIf(unwrap, ConstraintDeclarationException::new, "No compatible %s found for %s",
+ ValueExtractor.class.getSimpleName(), meta.getType());
+ } else {
+ @SuppressWarnings("unchecked")
+ final Class<? extends ValueExtractor<?>> extractorClass =
+ (Class<? extends ValueExtractor<?>>) valueExtractor.getClass();
+ if (unwrap || extractorClass.isAnnotationPresent(UnwrapByDefault.class)) {
+ return ValueExtractors.getExtractedType(valueExtractor, meta.getType());
+ }
+ }
+ return rawType;
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstructorD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstructorD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstructorD.java
new file mode 100644
index 0000000..b89d29c
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstructorD.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.descriptor;
+
+import java.lang.reflect.Constructor;
+
+import javax.validation.metadata.ConstructorDescriptor;
+
+public class ConstructorD extends ExecutableD<Constructor<?>, MetadataReader.ForConstructor, ConstructorD>
+ implements ConstructorDescriptor {
+
+ ConstructorD(MetadataReader.ForConstructor reader, BeanD parent) {
+ super(reader, parent);
+ }
+
+ @Override
+ public Class<?> getElementClass() {
+ return getParent().getElementClass();
+ }
+
+ @Override
+ protected String nameOf(Constructor<?> e) {
+ return e.getDeclaringClass().getSimpleName();
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ContainerElementTypeD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ContainerElementTypeD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ContainerElementTypeD.java
new file mode 100644
index 0000000..7cacff3
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ContainerElementTypeD.java
@@ -0,0 +1,119 @@
+/*
+ * 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.descriptor;
+
+import java.lang.reflect.AnnotatedType;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+import javax.validation.ValidationException;
+import javax.validation.metadata.ContainerElementTypeDescriptor;
+import javax.validation.valueextraction.ValueExtractor;
+
+import org.apache.bval.jsr.GraphContext;
+import org.apache.bval.jsr.metadata.ContainerElementKey;
+import org.apache.bval.jsr.util.NodeImpl;
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.Lazy;
+import org.apache.bval.util.Validate;
+
+public class ContainerElementTypeD extends CascadableContainerD<CascadableContainerD<?, ?>, AnnotatedType>
+ implements ContainerElementTypeDescriptor {
+
+ private static class Receiver implements ValueExtractor.ValueReceiver {
+ private final GraphContext context;
+ private Lazy<List<GraphContext>> result = new Lazy<>(ArrayList::new);
+
+ Receiver(GraphContext context) {
+ super();
+ this.context = context;
+ }
+
+ @Override
+ public void value(String nodeName, Object object) {
+ addChild(new NodeImpl.PropertyNodeImpl(nodeName), object);
+ }
+
+ @Override
+ public void iterableValue(String nodeName, Object object) {
+ final NodeImpl.PropertyNodeImpl node = new NodeImpl.PropertyNodeImpl(nodeName);
+ node.setInIterable(true);
+ addChild(node, object);
+ }
+
+ @Override
+ public void indexedValue(String nodeName, int i, Object object) {
+ final NodeImpl.PropertyNodeImpl node = new NodeImpl.PropertyNodeImpl(nodeName);
+ node.setIndex(Integer.valueOf(i));
+ addChild(node, object);
+ }
+
+ @Override
+ public void keyedValue(String nodeName, Object key, Object object) {
+ final NodeImpl.PropertyNodeImpl node = new NodeImpl.PropertyNodeImpl(nodeName);
+ node.setKey(key);
+ addChild(node, object);
+ }
+
+ private void addChild(NodeImpl node, Object value) {
+ result.get().add(context.child(node, value));
+ }
+ }
+
+ private final ContainerElementKey key;
+
+ ContainerElementTypeD(ContainerElementKey key, MetadataReader.ForContainer<AnnotatedType> reader,
+ CascadableContainerD<?, ?> parent) {
+ super(reader, parent);
+ this.key = Validate.notNull(key, "key");
+ }
+
+ @Override
+ public Class<?> getContainerClass() {
+ return key.getContainerClass();
+ }
+
+ @Override
+ public Integer getTypeArgumentIndex() {
+ return Integer.valueOf(key.getTypeArgumentIndex());
+ }
+
+ public ContainerElementKey getKey() {
+ return key;
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ @Override
+ protected Stream<GraphContext> readImpl(GraphContext context) throws Exception {
+ final ValueExtractor valueExtractor = context.getValidatorContext().getValueExtractors().find(key);
+ Exceptions.raiseIf(valueExtractor == null, ValidationException::new, "No %s found for %s",
+ ValueExtractor.class.getSimpleName(), key);
+
+ final Receiver receiver = new Receiver(context);
+ try {
+ valueExtractor.extractValues(context.getValue(), receiver);
+ } catch (ValidationException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ValidationException(e);
+ }
+ return receiver.result.get().stream();
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CrossParameterD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CrossParameterD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CrossParameterD.java
new file mode 100644
index 0000000..0d51800
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CrossParameterD.java
@@ -0,0 +1,18 @@
+package org.apache.bval.jsr.descriptor;
+
+import java.lang.reflect.Executable;
+
+import javax.validation.metadata.CrossParameterDescriptor;
+
+public class CrossParameterD<P extends ExecutableD<?, ?, P>, E extends Executable>
+ extends ElementD.NonRoot<P, E, MetadataReader.ForElement<E, ?>> implements CrossParameterDescriptor {
+
+ protected CrossParameterD(MetadataReader.ForElement<E, ?> reader, P parent) {
+ super(reader, parent);
+ }
+
+ @Override
+ public Class<?> getElementClass() {
+ return Object[].class;
+ }
+}