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:24:57 UTC
[01/11] bval git commit: implement BV 2.0 against existing BVal unit
tests [Forced Update!]
Repository: bval
Updated Branches:
refs/heads/bv2 a43c0b0c7 -> 3f287a7af (forced update)
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/xsd/validation-mapping-2.0.xsd
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/xsd/validation-mapping-2.0.xsd b/bval-jsr/src/main/xsd/validation-mapping-2.0.xsd
new file mode 100644
index 0000000..9d16bf3
--- /dev/null
+++ b/bval-jsr/src/main/xsd/validation-mapping-2.0.xsd
@@ -0,0 +1,297 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<xs:schema attributeFormDefault="unqualified"
+ elementFormDefault="qualified"
+ targetNamespace="http://xmlns.jcp.org/xml/ns/javax/validation/mapping"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:map="http://xmlns.jcp.org/xml/ns/javax/validation/mapping"
+ version="2.0">
+ <xs:element name="constraint-mappings" type="map:constraint-mappingsType" />
+
+ <xs:complexType name="payloadType">
+ <xs:sequence>
+ <xs:element type="xs:string" name="value" maxOccurs="unbounded" minOccurs="0" />
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="groupsType">
+ <xs:sequence>
+ <xs:element type="xs:string" name="value" maxOccurs="unbounded" minOccurs="0" />
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="groupSequenceType">
+ <xs:sequence>
+ <xs:element type="xs:string" name="value" maxOccurs="unbounded" minOccurs="0" />
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="groupConversionType">
+ <xs:attribute type="xs:string" name="from" use="required" />
+ <xs:attribute type="xs:string" name="to" use="required" />
+ </xs:complexType>
+ <xs:complexType name="constraint-mappingsType">
+ <xs:sequence>
+ <xs:element type="xs:string" name="default-package" minOccurs="0" />
+ <xs:element type="map:beanType"
+ name="bean"
+ maxOccurs="unbounded"
+ minOccurs="0" />
+ <xs:element type="map:constraint-definitionType"
+ name="constraint-definition"
+ maxOccurs="unbounded"
+ minOccurs="0" />
+ </xs:sequence>
+ <xs:attribute name="version" type="map:versionType" fixed="2.0" /> <!-- use="required" -->
+ </xs:complexType>
+ <xs:simpleType name="versionType">
+ <xs:restriction base="xs:token">
+ <xs:pattern value="[0-9]+(\.[0-9]+)*" />
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="validated-byType">
+ <xs:sequence>
+ <xs:element type="xs:string" name="value" maxOccurs="unbounded" minOccurs="0" />
+ </xs:sequence>
+ <xs:attribute type="xs:boolean" name="include-existing-validators" use="optional" />
+ </xs:complexType>
+ <xs:complexType name="constraintType">
+ <xs:sequence>
+ <xs:element type="xs:string" name="message" minOccurs="0" />
+ <xs:element type="map:groupsType"
+ name="groups"
+ minOccurs="0" />
+ <xs:element type="map:payloadType"
+ name="payload"
+ minOccurs="0" />
+ <xs:element type="map:elementType"
+ name="element"
+ maxOccurs="unbounded"
+ minOccurs="0" />
+ </xs:sequence>
+ <xs:attribute type="xs:string" name="annotation" use="required" />
+ </xs:complexType>
+ <xs:complexType name="elementType" mixed="true">
+ <xs:sequence>
+ <xs:element type="xs:string" name="value" maxOccurs="unbounded" minOccurs="0" />
+ <xs:element type="map:annotationType"
+ name="annotation"
+ maxOccurs="unbounded"
+ minOccurs="0" />
+ </xs:sequence>
+ <xs:attribute type="xs:string" name="name" use="required" />
+ </xs:complexType>
+ <xs:complexType name="containerElementTypeType">
+ <xs:sequence>
+ <xs:element type="xs:string"
+ name="valid"
+ minOccurs="0"
+ fixed="" />
+ <xs:element type="map:groupConversionType"
+ name="convert-group"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ <xs:element type="map:containerElementTypeType"
+ name="container-element-type"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ <xs:element type="map:constraintType"
+ name="constraint"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ </xs:sequence>
+ <xs:attribute name="type-argument-index" use="optional">
+ <xs:simpleType>
+ <xs:restriction base="xs:int">
+ <xs:minInclusive value="0" />
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="classType">
+ <xs:sequence>
+ <xs:element type="map:groupSequenceType"
+ name="group-sequence"
+ minOccurs="0" />
+ <xs:element type="map:constraintType"
+ name="constraint"
+ maxOccurs="unbounded"
+ minOccurs="0" />
+ </xs:sequence>
+ <xs:attribute type="xs:boolean" name="ignore-annotations" use="optional" />
+ </xs:complexType>
+ <xs:complexType name="beanType">
+ <xs:sequence>
+ <xs:element type="map:classType"
+ name="class"
+ minOccurs="0">
+ </xs:element>
+ <xs:element type="map:fieldType"
+ name="field"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ <xs:element type="map:getterType"
+ name="getter"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ <xs:element type="map:constructorType"
+ name="constructor"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ <xs:element type="map:methodType"
+ name="method"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ </xs:sequence>
+ <xs:attribute type="xs:string" name="class" use="required" />
+ <xs:attribute type="xs:boolean" name="ignore-annotations" use="optional" default="true" />
+ </xs:complexType>
+ <xs:complexType name="annotationType">
+ <xs:sequence>
+ <xs:element type="map:elementType"
+ name="element"
+ maxOccurs="unbounded"
+ minOccurs="0" />
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="getterType">
+ <xs:sequence>
+ <xs:element type="xs:string" name="valid" minOccurs="0" fixed="" />
+ <xs:element type="map:groupConversionType"
+ name="convert-group"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ <xs:element type="map:containerElementTypeType"
+ name="container-element-type"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ <xs:element type="map:constraintType"
+ name="constraint"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ </xs:sequence>
+ <xs:attribute type="xs:string" name="name" use="required" />
+ <xs:attribute type="xs:boolean" name="ignore-annotations" use="optional" />
+ </xs:complexType>
+ <xs:complexType name="methodType">
+ <xs:sequence>
+ <xs:element type="map:parameterType"
+ name="parameter"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ <xs:element type="map:crossParameterType"
+ name="cross-parameter"
+ minOccurs="0"
+ maxOccurs="1" />
+ <xs:element type="map:returnValueType"
+ name="return-value"
+ minOccurs="0"
+ maxOccurs="1" />
+ </xs:sequence>
+ <xs:attribute type="xs:string" name="name" use="required" />
+ <xs:attribute type="xs:boolean" name="ignore-annotations" use="optional" />
+ </xs:complexType>
+ <xs:complexType name="constructorType">
+ <xs:sequence>
+ <xs:element type="map:parameterType"
+ name="parameter"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ <xs:element type="map:crossParameterType"
+ name="cross-parameter"
+ minOccurs="0"
+ maxOccurs="1" />
+ <xs:element type="map:returnValueType"
+ name="return-value"
+ minOccurs="0"
+ maxOccurs="1" />
+ </xs:sequence>
+ <xs:attribute type="xs:boolean" name="ignore-annotations" use="optional" />
+ </xs:complexType>
+ <xs:complexType name="parameterType">
+ <xs:sequence>
+ <xs:element type="xs:string" name="valid" minOccurs="0" fixed="" />
+ <xs:element type="map:groupConversionType"
+ name="convert-group"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ <xs:element type="map:containerElementTypeType"
+ name="container-element-type"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ <xs:element type="map:constraintType"
+ name="constraint"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ </xs:sequence>
+ <xs:attribute type="xs:string" name="type" use="required" />
+ <xs:attribute type="xs:boolean" name="ignore-annotations" use="optional" />
+ </xs:complexType>
+ <xs:complexType name="returnValueType">
+ <xs:sequence>
+ <xs:element type="xs:string" name="valid" minOccurs="0" fixed="" />
+ <xs:element type="map:groupConversionType"
+ name="convert-group"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ <xs:element type="map:containerElementTypeType"
+ name="container-element-type"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ <xs:element type="map:constraintType"
+ name="constraint"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ </xs:sequence>
+ <xs:attribute type="xs:boolean" name="ignore-annotations" use="optional" />
+ </xs:complexType>
+ <xs:complexType name="crossParameterType">
+ <xs:sequence>
+ <xs:element type="map:constraintType"
+ name="constraint"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ </xs:sequence>
+ <xs:attribute type="xs:boolean" name="ignore-annotations" use="optional" />
+ </xs:complexType>
+ <xs:complexType name="constraint-definitionType">
+ <xs:sequence>
+ <xs:element type="map:validated-byType"
+ name="validated-by" />
+ </xs:sequence>
+ <xs:attribute type="xs:string" name="annotation" use="required" />
+ </xs:complexType>
+ <xs:complexType name="fieldType">
+ <xs:sequence>
+ <xs:element type="xs:string" name="valid" minOccurs="0" fixed="" />
+ <xs:element type="map:groupConversionType"
+ name="convert-group"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ <xs:element type="map:containerElementTypeType"
+ name="container-element-type"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ <xs:element type="map:constraintType"
+ name="constraint"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ </xs:sequence>
+ <xs:attribute type="xs:string" name="name" use="required" />
+ <xs:attribute type="xs:boolean" name="ignore-annotations" use="optional" />
+ </xs:complexType>
+</xs:schema>
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/test/java/org/apache/bval/jsr/BeanDescriptorTest.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/test/java/org/apache/bval/jsr/BeanDescriptorTest.java b/bval-jsr/src/test/java/org/apache/bval/jsr/BeanDescriptorTest.java
index d81f90a..5c949c1 100644
--- a/bval-jsr/src/test/java/org/apache/bval/jsr/BeanDescriptorTest.java
+++ b/bval-jsr/src/test/java/org/apache/bval/jsr/BeanDescriptorTest.java
@@ -42,6 +42,7 @@ import javax.validation.metadata.PropertyDescriptor;
import javax.validation.metadata.Scope;
import org.apache.bval.jsr.util.TestUtils;
+import org.junit.Ignore;
import org.junit.Test;
/**
@@ -120,6 +121,8 @@ public class BeanDescriptorTest extends ValidationTestBase {
* interface group when querying the interface directly.
*/
@Test
+ // spec does not dictate this
+ @Ignore
public void testNoImplicitGroupWhenQueryingInterfaceDirectly() {
Set<ConstraintDescriptor<?>> nameDescriptors =
validator.getConstraintsForClass(Person.class).getConstraintsForProperty("name").getConstraintDescriptors();
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/test/java/org/apache/bval/jsr/CustomValidatorFactoryTest.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/test/java/org/apache/bval/jsr/CustomValidatorFactoryTest.java b/bval-jsr/src/test/java/org/apache/bval/jsr/CustomValidatorFactoryTest.java
index 355d676..fca45d1 100644
--- a/bval-jsr/src/test/java/org/apache/bval/jsr/CustomValidatorFactoryTest.java
+++ b/bval-jsr/src/test/java/org/apache/bval/jsr/CustomValidatorFactoryTest.java
@@ -20,6 +20,7 @@ package org.apache.bval.jsr;
import static org.hamcrest.CoreMatchers.isA;
+import javax.validation.ClockProvider;
import javax.validation.ConstraintValidatorFactory;
import javax.validation.MessageInterpolator;
import javax.validation.ParameterNameProvider;
@@ -95,6 +96,11 @@ public class CustomValidatorFactoryTest {
return null;
}
+ @Override
+ public ClockProvider getClockProvider() {
+ return null;
+ }
+
}
public static class NotAValidatorFactory {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/test/java/org/apache/bval/jsr/Jsr303Test.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/test/java/org/apache/bval/jsr/Jsr303Test.java b/bval-jsr/src/test/java/org/apache/bval/jsr/Jsr303Test.java
index 83f2427..2dfe493 100644
--- a/bval-jsr/src/test/java/org/apache/bval/jsr/Jsr303Test.java
+++ b/bval-jsr/src/test/java/org/apache/bval/jsr/Jsr303Test.java
@@ -31,8 +31,10 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
+import javax.validation.ConstraintValidator;
import javax.validation.ConstraintViolation;
import javax.validation.UnexpectedTypeException;
+import javax.validation.constraints.Max;
import javax.validation.metadata.BeanDescriptor;
import javax.validation.metadata.ConstraintDescriptor;
import javax.validation.metadata.ElementDescriptor;
@@ -48,6 +50,7 @@ import org.apache.bval.jsr.example.NoValidatorTestEntity;
import org.apache.bval.jsr.example.Second;
import org.apache.bval.jsr.example.SizeTestEntity;
import org.apache.bval.jsr.util.TestUtils;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@@ -65,8 +68,10 @@ public class Jsr303Test extends ValidationTestBase {
assertTrue(cons.getConstraintsForProperty("author").hasConstraints());
assertTrue(cons.getConstraintsForProperty("title").hasConstraints());
assertTrue(cons.getConstraintsForProperty("uselessField").hasConstraints());
- // cons.getConstraintsForProperty("unconstraintField") == null without Introspector
- // cons.getConstraintsForProperty("unconstraintField") != null with Introspector
+ // cons.getConstraintsForProperty("unconstraintField") == null without
+ // Introspector
+ // cons.getConstraintsForProperty("unconstraintField") != null with
+ // Introspector
assertTrue(cons.getConstraintsForProperty("unconstraintField") == null
|| !cons.getConstraintsForProperty("unconstraintField").hasConstraints());
assertNull(cons.getConstraintsForProperty("unknownField"));
@@ -83,11 +88,13 @@ public class Jsr303Test extends ValidationTestBase {
@Test(expected = IllegalArgumentException.class)
public void testUnknownProperty() {
- // tests for issue 22: validation of unknown field cause ValidationException
+ // tests for issue 22: validation of unknown field cause
+ // ValidationException
validator.validateValue(Book.class, "unknownProperty", 4);
}
@Test(expected = IllegalArgumentException.class)
+ @Ignore
public void testValidateNonCascadedRealNestedProperty() {
validator.validateValue(IllustratedBook.class, "illustrator.firstName", "Edgar");
}
@@ -95,7 +102,8 @@ public class Jsr303Test extends ValidationTestBase {
@Test
public void testMetadataAPI_Book() {
assertNotNull(validator.getConstraintsForClass(Book.class));
- // not necessary for implementation correctness, but we'll test nevertheless:
+ // not necessary for implementation correctness, but we'll test
+ // nevertheless:
assertSame(validator.getConstraintsForClass(Book.class), validator.getConstraintsForClass(Book.class));
BeanDescriptor bc = validator.getConstraintsForClass(Book.class);
assertEquals(Book.class, bc.getElementClass());
@@ -135,8 +143,9 @@ public class Jsr303Test extends ValidationTestBase {
validator.getConstraintsForClass(Address.class).getConstraintsForProperty("addressline1");
assertNotNull(desc);
boolean found = false;
+
for (ConstraintDescriptor<?> each : desc.getConstraintDescriptors()) {
- if (SizeValidatorForCharSequence.class.equals(each.getConstraintValidatorClasses().get(0))) {
+ if (each.getConstraintValidatorClasses().contains(SizeValidatorForCharSequence.class)) {
assertTrue(each.getAttributes().containsKey("max"));
assertEquals(30, each.getAttributes().get("max"));
found = true;
@@ -175,9 +184,8 @@ public class Jsr303Test extends ValidationTestBase {
@Test
public void testConstraintValidatorResolutionAlgorithm2() {
thrown.expect(UnexpectedTypeException.class);
- thrown.expectMessage("No validator could be found for type java.lang.Object. "
- + "See: @Max at private java.lang.Object org.apache.bval.jsr.example." + "NoValidatorTestEntity.anything");
-
+ thrown.expectMessage(String.format("No compliant %s %s found for annotated element of type %s",
+ Max.class.getName(), ConstraintValidator.class.getSimpleName(), Object.class.getName()));
NoValidatorTestEntity entity2 = new NoValidatorTestEntity();
validator.validate(entity2);
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/test/java/org/apache/bval/jsr/ValidationTest.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/test/java/org/apache/bval/jsr/ValidationTest.java b/bval-jsr/src/test/java/org/apache/bval/jsr/ValidationTest.java
index f6c7a4f..b696627 100644
--- a/bval-jsr/src/test/java/org/apache/bval/jsr/ValidationTest.java
+++ b/bval-jsr/src/test/java/org/apache/bval/jsr/ValidationTest.java
@@ -59,6 +59,7 @@ import org.apache.bval.jsr.example.Last;
import org.apache.bval.jsr.example.RecursiveFoo;
import org.apache.bval.jsr.util.TestUtils;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
/**
@@ -73,6 +74,7 @@ public class ValidationTest extends ValidationTestBase {
}
@Test
+ @Ignore // per spec, fields should after all be validated on subclasses
public void testAccessStrategies_field_method() {
AccessTestBusinessObject o1 = new AccessTestBusinessObject("1");
assertTrue(validator.validate(o1).isEmpty());
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/test/java/org/apache/bval/jsr/example/Engine.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/test/java/org/apache/bval/jsr/example/Engine.java b/bval-jsr/src/test/java/org/apache/bval/jsr/example/Engine.java
index 4ee8101..b65d091 100644
--- a/bval-jsr/src/test/java/org/apache/bval/jsr/example/Engine.java
+++ b/bval-jsr/src/test/java/org/apache/bval/jsr/example/Engine.java
@@ -21,9 +21,11 @@ package org.apache.bval.jsr.example;
import javax.validation.constraints.Pattern;
public class Engine {
- @Pattern.List({
- @Pattern(regexp = "^[A-Z0-9-]+$", flags = Pattern.Flag.CASE_INSENSITIVE, message = "must contain alphabetical characters only"),
- @Pattern(regexp = "^....-....-....$", message = "must match ....-....-....") })
+ // TODO See about Windows bug with container @ Field#getAnnotatedType()
+// @Pattern.List({
+ @Pattern(regexp = "^[A-Z0-9-]+$", flags = Pattern.Flag.CASE_INSENSITIVE, message = "must contain alphabetical characters only")//,
+ @Pattern(regexp = "^....-....-....$", message = "must match ....-....-....")
+// })
public String serialNumber;
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/test/java/org/apache/bval/jsr/extensions/MethodValidatorImplTest.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/test/java/org/apache/bval/jsr/extensions/MethodValidatorImplTest.java b/bval-jsr/src/test/java/org/apache/bval/jsr/extensions/MethodValidatorImplTest.java
index 4740f5b..d05b47d 100644
--- a/bval-jsr/src/test/java/org/apache/bval/jsr/extensions/MethodValidatorImplTest.java
+++ b/bval-jsr/src/test/java/org/apache/bval/jsr/extensions/MethodValidatorImplTest.java
@@ -26,7 +26,7 @@ import javax.validation.constraints.Size;
import javax.validation.executable.ExecutableValidator;
import org.apache.bval.jsr.ApacheValidationProvider;
-import org.apache.bval.jsr.ClassValidator;
+import org.apache.bval.jsr.ValidatorImpl;
import org.apache.bval.jsr.extensions.ExampleMethodService.Person;
import org.junit.Ignore;
@@ -53,7 +53,7 @@ public class MethodValidatorImplTest extends TestCase {
public void testUnwrap() {
Validator v = getValidator();
- ClassValidator cv = v.unwrap(ClassValidator.class);
+ ValidatorImpl cv = v.unwrap(ValidatorImpl.class);
assertSame(v, cv);
assertSame(v, v.unwrap(Validator.class));
assertNotNull(v.forExecutables());
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/test/java/org/apache/bval/jsr/groups/GroupSequenceIsolationTest.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/test/java/org/apache/bval/jsr/groups/GroupSequenceIsolationTest.java b/bval-jsr/src/test/java/org/apache/bval/jsr/groups/GroupSequenceIsolationTest.java
index 89489fb..17d6dba 100644
--- a/bval-jsr/src/test/java/org/apache/bval/jsr/groups/GroupSequenceIsolationTest.java
+++ b/bval-jsr/src/test/java/org/apache/bval/jsr/groups/GroupSequenceIsolationTest.java
@@ -52,16 +52,13 @@ public class GroupSequenceIsolationTest extends ValidationTestBase {
public void testGroupSequencesInHierarchyClasses() {
HolderWithNoGS h = new HolderWithNoGS();
- assertEquals(set("a1", "b2"), violationPaths(validator.validate(h)));
-
- h.a1 = "good";
assertEquals(set("a2", "b2"), violationPaths(validator.validate(h)));
h.b2 = "good";
- assertEquals(set("a2", "b1"), violationPaths(validator.validate(h)));
-
- h.b1 = "good";
assertEquals(set("a2"), violationPaths(validator.validate(h)));
+
+ h.a2 = "good";
+ assertEquals(set("b1"), violationPaths(validator.validate(h)));
}
/**
@@ -82,6 +79,7 @@ public class GroupSequenceIsolationTest extends ValidationTestBase {
assertEquals(Collections.singleton("b1"), violationPaths(validator.validate(h)));
}
+ @SafeVarargs
private static <T> Set<T> set(T... elements) {
return new HashSet<T>(Arrays.asList(elements));
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/test/java/org/apache/bval/jsr/groups/GroupsComputerTest.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/test/java/org/apache/bval/jsr/groups/GroupsComputerTest.java b/bval-jsr/src/test/java/org/apache/bval/jsr/groups/GroupsComputerTest.java
index 13a49e1..4222339 100644
--- a/bval-jsr/src/test/java/org/apache/bval/jsr/groups/GroupsComputerTest.java
+++ b/bval-jsr/src/test/java/org/apache/bval/jsr/groups/GroupsComputerTest.java
@@ -18,22 +18,25 @@
*/
package org.apache.bval.jsr.groups;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestSuite;
-import org.apache.bval.jsr.example.Address;
-import org.apache.bval.jsr.example.First;
-import org.apache.bval.jsr.example.Last;
-import org.apache.bval.jsr.example.Second;
+import static org.junit.Assert.assertEquals;
-import javax.validation.GroupDefinitionException;
-import javax.validation.ValidationException;
-import javax.validation.groups.Default;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
+import javax.validation.GroupDefinitionException;
+import javax.validation.ValidationException;
+import javax.validation.groups.Default;
+
+import org.apache.bval.jsr.example.Address;
+import org.apache.bval.jsr.example.First;
+import org.apache.bval.jsr.example.Last;
+import org.apache.bval.jsr.example.Second;
+import org.junit.Before;
+import org.junit.Test;
+
/**
* GroupListComputer Tester.
*
@@ -41,79 +44,41 @@ import java.util.Set;
* @version 1.0
* @since <pre>04/09/2009</pre>
*/
-public class GroupsComputerTest extends TestCase {
+public class GroupsComputerTest {
GroupsComputer groupsComputer;
- public GroupsComputerTest(String name) {
- super(name);
- }
-
- @Override
+ @Before
public void setUp() throws Exception {
- super.setUp();
groupsComputer = new GroupsComputer();
}
- @Override
- public void tearDown() throws Exception {
- super.tearDown();
- }
-
- public static Test suite() {
- return new TestSuite(GroupsComputerTest.class);
- }
-
+ @Test(expected = ValidationException.class)
public void testComputeGroupsNotAnInterface() {
- Set<Class<?>> groups = new HashSet<Class<?>>();
- groups.add(String.class);
- try {
- groupsComputer.computeGroups(groups);
- fail();
- } catch (ValidationException ex) {
-
- }
+ groupsComputer.computeGroups(Collections.singleton(String.class));
}
+ @Test(expected = IllegalArgumentException.class)
public void testGroupChainForNull() {
- try {
groupsComputer.computeGroups((Class<?>[]) null);
- fail();
- } catch (IllegalArgumentException ex) {
-
- }
}
+ @Test
public void testGroupChainForEmptySet() {
- try {
- groupsComputer.computeGroups(new HashSet<Class<?>>());
- fail();
- } catch (IllegalArgumentException ex) {
-
- }
+ assertEquals(Collections.singletonList(Group.DEFAULT),
+ groupsComputer.computeGroups(new HashSet<Class<?>>()).getGroups());
}
+ @Test(expected = GroupDefinitionException.class)
public void testCyclicGroupSequences() {
- try {
- Set<Class<?>> groups = new HashSet<Class<?>>();
- groups.add(CyclicGroupSequence1.class);
- groupsComputer.computeGroups(groups);
- fail();
- } catch (GroupDefinitionException ex) {
-
- }
+ groupsComputer.computeGroups(Collections.singleton(CyclicGroupSequence1.class));
}
+ @Test(expected = GroupDefinitionException.class)
public void testCyclicGroupSequence() {
- try {
- Set<Class<?>> groups = new HashSet<Class<?>>();
- groups.add(CyclicGroupSequence.class);
- groupsComputer.computeGroups(groups);
- fail();
- } catch (GroupDefinitionException ex) {
-
- }
+ groupsComputer.computeGroups(Collections.singleton(CyclicGroupSequence.class));
}
+ @Test
public void testGroupDuplicates() {
Set<Class<?>> groups = new HashSet<Class<?>>();
groups.add(First.class);
@@ -136,6 +101,7 @@ public class GroupsComputerTest extends TestCase {
assertEquals(2, chain.groups.size());
}
+ @Test
public void testSequenceResolution() {
Set<Class<?>> groups = new HashSet<Class<?>>();
groups.add(Address.Complete.class);
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/test/java/org/apache/bval/jsr/xml/Demo.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/test/java/org/apache/bval/jsr/xml/Demo.java b/bval-jsr/src/test/java/org/apache/bval/jsr/xml/Demo.java
new file mode 100644
index 0000000..02a07a8
--- /dev/null
+++ b/bval-jsr/src/test/java/org/apache/bval/jsr/xml/Demo.java
@@ -0,0 +1,40 @@
+package org.apache.bval.jsr.xml;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.UnmarshallerHandler;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.junit.Test;
+import org.xml.sax.InputSource;
+import org.xml.sax.XMLReader;
+
+public class Demo {
+
+ @Test
+ public void test1() throws Exception {
+ JAXBContext jc = JAXBContext.newInstance(ObjectFactory.class);
+
+ // Set the parent XMLReader on the XMLFilter
+ SAXParserFactory spf = SAXParserFactory.newInstance();
+ spf.setNamespaceAware(true);
+ SAXParser sp = spf.newSAXParser();
+ XMLReader xr = sp.getXMLReader();
+
+ // Set UnmarshallerHandler as ContentHandler on XMLFilter
+
+ Unmarshaller unmarshaller = jc.createUnmarshaller();
+
+ UnmarshallerHandler unmarshallerHandler = unmarshaller.getUnmarshallerHandler();
+ xr.setContentHandler(unmarshallerHandler);
+
+ // Parse the XML
+ InputSource xml = new InputSource(getClass().getResourceAsStream("/sample-validation2.xml"));
+ xr.parse(xml);
+ JAXBElement<ValidationConfigType> result = (JAXBElement<ValidationConfigType>) unmarshallerHandler.getResult();
+ System.out.println(ToStringBuilder.reflectionToString(result.getValue()));
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/test/java/org/apache/bval/jsr/xml/ValidationParserTest.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/test/java/org/apache/bval/jsr/xml/ValidationParserTest.java b/bval-jsr/src/test/java/org/apache/bval/jsr/xml/ValidationParserTest.java
index 827abae..41d4f13 100644
--- a/bval-jsr/src/test/java/org/apache/bval/jsr/xml/ValidationParserTest.java
+++ b/bval-jsr/src/test/java/org/apache/bval/jsr/xml/ValidationParserTest.java
@@ -19,6 +19,8 @@
package org.apache.bval.jsr.xml;
import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@@ -84,6 +86,18 @@ public class ValidationParserTest implements ApacheValidatorConfiguration.Proper
}
@Test
+ public void testParseV11() {
+ ConfigurationImpl config = new ConfigurationImpl(null, new ApacheValidationProvider());
+ ValidationParser.processValidationConfig("sample-validation11.xml", config, false);
+ }
+
+ @Test
+ public void testParseV20() {
+ ConfigurationImpl config = new ConfigurationImpl(null, new ApacheValidationProvider());
+ ValidationParser.processValidationConfig("sample-validation2.xml", config, false);
+ }
+
+ @Test
public void testConfigureFromXml() {
ValidatorFactory factory = getFactory();
assertThat(factory.getMessageInterpolator(), instanceOf(TestMessageInterpolator.class));
@@ -105,8 +119,8 @@ public class ValidationParserTest implements ApacheValidatorConfiguration.Proper
bean.setValueCode("illegal");
Validator validator = getFactory().getValidator();
Set<ConstraintViolation<XmlEntitySampleBean>> results = validator.validate(bean);
- assertTrue(!results.isEmpty());
- assertTrue(results.size() == 3);
+ assertFalse(results.isEmpty());
+ assertEquals(3, results.size());
bean.setZipCode("123");
bean.setValueCode("20");
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/test/resources/sample-validation11.xml
----------------------------------------------------------------------
diff --git a/bval-jsr/src/test/resources/sample-validation11.xml b/bval-jsr/src/test/resources/sample-validation11.xml
new file mode 100644
index 0000000..648ba1c
--- /dev/null
+++ b/bval-jsr/src/test/resources/sample-validation11.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<validation-config
+ xmlns="http://jboss.org/xml/ns/javax/validation/configuration"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation=
+ "http://jboss.org/xml/ns/javax/validation/configuration validation-configuration-1.0.xsd"
+ version="1.1">
+ <default-provider>org.apache.bval.jsr.ApacheValidationProvider</default-provider>
+ <message-interpolator>org.apache.bval.jsr.xml.TestMessageInterpolator</message-interpolator>
+ <traversable-resolver>org.apache.bval.jsr.resolver.SimpleTraversableResolver</traversable-resolver>
+ <constraint-validator-factory>org.apache.bval.jsr.xml.TestConstraintValidatorFactory</constraint-validator-factory>
+ <constraint-mapping>sample-constraints.xml</constraint-mapping>
+ <property name="test-prop">test-prop-value</property>
+</validation-config>
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/test/resources/sample-validation2.xml
----------------------------------------------------------------------
diff --git a/bval-jsr/src/test/resources/sample-validation2.xml b/bval-jsr/src/test/resources/sample-validation2.xml
new file mode 100644
index 0000000..4758454
--- /dev/null
+++ b/bval-jsr/src/test/resources/sample-validation2.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<validation-config
+ xmlns="http://xmlns.jcp.org/xml/ns/javax/validation/configuration"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation=
+ "http://xmlns.jcp.org/xml/ns/javax/validation/configuration validation-configuration-2.0.xsd"
+ version="2.0">
+ <default-provider>org.apache.bval.jsr.ApacheValidationProvider</default-provider>
+ <message-interpolator>org.apache.bval.jsr.xml.TestMessageInterpolator</message-interpolator>
+ <traversable-resolver>org.apache.bval.jsr.resolver.SimpleTraversableResolver</traversable-resolver>
+ <constraint-validator-factory>org.apache.bval.jsr.xml.TestConstraintValidatorFactory</constraint-validator-factory>
+ <constraint-mapping>sample-constraints.xml</constraint-mapping>
+ <property name="test-prop">test-prop-value</property>
+</validation-config>
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-tck11/pom.xml
----------------------------------------------------------------------
diff --git a/bval-tck11/pom.xml b/bval-tck11/pom.xml
index fb2ae65..63611b9 100644
--- a/bval-tck11/pom.xml
+++ b/bval-tck11/pom.xml
@@ -23,7 +23,7 @@ under the License.
<parent>
<artifactId>bval-parent</artifactId>
<groupId>org.apache.bval</groupId>
- <version>1.1.3-SNAPSHOT</version>
+ <version>2.0.0-SNAPSHOT</version>
</parent>
<artifactId>bval-tck11-runner</artifactId>
@@ -32,15 +32,15 @@ under the License.
<properties>
<tck.version>1.1.4.Final</tck.version>
- <owb.version>1.7.2</owb.version>
- <arquillian.version>1.1.13.Final</arquillian.version>
+ <owb.version>1.6.0</owb.version>
+ <arquillian.version>1.1.8.Final</arquillian.version>
<validation.provider>org.apache.bval.jsr.ApacheValidationProvider</validation.provider>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
- <artifactId>geronimo-validation_1.1_spec</artifactId>
+ <artifactId>geronimo-validation_2.0_spec</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-xstream/pom.xml
----------------------------------------------------------------------
diff --git a/bval-xstream/pom.xml b/bval-xstream/pom.xml
index 67ac48d..bf90180 100644
--- a/bval-xstream/pom.xml
+++ b/bval-xstream/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.apache.bval</groupId>
<artifactId>bval-parent</artifactId>
- <version>1.1.3-SNAPSHOT</version>
+ <version>2.0.0-SNAPSHOT</version>
</parent>
<artifactId>bval-xstream</artifactId>
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 470ddd0..42e8d80 100644
--- a/pom.xml
+++ b/pom.xml
@@ -35,14 +35,16 @@
<artifactId>bval-parent</artifactId>
<name>Apache BVal :: bval-parent (Parent POM)</name>
<packaging>pom</packaging>
- <version>1.1.3-SNAPSHOT</version>
+ <version>2.0.0-SNAPSHOT</version>
<description>Apache BVal parent pom</description>
<properties>
<site.deploy.url>sftp://people.apache.org/home/${user.name}/public_html/bval/${project.version}/staging-site</site.deploy.url>
<commons.weaver.version>1.3</commons.weaver.version>
- <privilizer.policy>DYNAMIC</privilizer.policy>
+<!-- temporarily disable privilizer due to Java 8 incompatibility -->
+<!-- <privilizer.policy>DYNAMIC</privilizer.policy> -->
+ <privilizer.policy>NEVER</privilizer.policy>
</properties>
<inceptionYear>2010</inceptionYear>
@@ -257,10 +259,10 @@
<configuration>
<show>package</show>
<quiet>true</quiet>
- <source>1.6</source>
+ <source>1.8</source>
<links>
- <link>http://docs.oracle.com/javase/6/docs/api</link>
- <link>http://docs.oracle.com/javaee/7/api</link>
+ <link>http://docs.oracle.com/javase/8/docs/api</link>
+<!-- <link>http://docs.oracle.com/javaee/7/api</link> -->
</links>
</configuration>
<reportSets>
@@ -292,8 +294,8 @@
<dependencies>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
- <artifactId>geronimo-validation_1.1_spec</artifactId>
- <version>1.0</version>
+ <artifactId>geronimo-validation_2.0_spec</artifactId>
+ <version>1.0-SNAPSHOT</version>
</dependency>
<!-- Optional profile to use Spec RI API -->
<dependency>
@@ -367,6 +369,13 @@
<version>7.0.72</version>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>com.oracle</groupId>
+ <artifactId>javafx</artifactId>
+ <version>8.0</version>
+ <systemPath>${java.home}/lib/ext/jfxrt.jar</systemPath>
+ <scope>system</scope>
+ </dependency>
</dependencies>
</dependencyManagement>
@@ -391,8 +400,8 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
- <source>1.6</source>
- <target>1.6</target>
+ <source>1.8</source>
+ <target>1.8</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
@@ -406,9 +415,9 @@
</manifest>
<manifestEntries>
<Implementation-Build>${buildNumber}</Implementation-Build>
- <Specification-Title>JSR-349 Bean Validation</Specification-Title>
+ <Specification-Title>JSR-380 Bean Validation</Specification-Title>
<Specification-Vendor>Sun Microsystems, Inc.</Specification-Vendor>
- <Specification-Version>1.1</Specification-Version>
+ <Specification-Version>2.0</Specification-Version>
</manifestEntries>
</archive>
</configuration>
@@ -424,8 +433,8 @@
<verbose>false</verbose>
<maxmemory>512m</maxmemory>
<links>
- <link>http://docs.oracle.com/javase/6/docs/api</link>
- <link>http://docs.oracle.com/javaee/7/api</link>
+ <link>http://docs.oracle.com/javase/8/docs/api</link>
+<!-- <link>http://docs.oracle.com/javaee/7/api</link> -->
</links>
</configuration>
</plugin>
@@ -459,7 +468,7 @@
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
- <version>2.0.1</version>
+ <version>3.3.0</version>
<extensions>true</extensions>
<configuration>
<instructions>
@@ -626,7 +635,7 @@
<version>[2.2.1,)</version>
</requireMavenVersion>
<requireJavaVersion>
- <version>[1.6,)</version>
+ <version>[1.8,)</version>
</requireJavaVersion>
</rules>
</configuration>
[02/11] bval git commit: implement BV 2.0 against existing BVal unit
tests
Posted by mb...@apache.org.
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/xml/ValidationMappingParser.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/xml/ValidationMappingParser.java b/bval-jsr/src/main/java/org/apache/bval/jsr/xml/ValidationMappingParser.java
index b260a9e..3a86142 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/xml/ValidationMappingParser.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/xml/ValidationMappingParser.java
@@ -18,730 +18,100 @@ package org.apache.bval.jsr.xml;
import java.io.IOException;
import java.io.InputStream;
-import java.io.Serializable;
import java.lang.annotation.Annotation;
-import java.lang.reflect.Array;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.Member;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.HashSet;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Set;
-import javax.validation.Constraint;
-import javax.validation.ConstraintValidator;
-import javax.validation.Payload;
import javax.validation.ValidationException;
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBElement;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Unmarshaller;
-import javax.xml.transform.stream.StreamSource;
-import javax.xml.validation.Schema;
import org.apache.bval.jsr.ApacheValidatorFactory;
-import org.apache.bval.jsr.ConstraintAnnotationAttributes;
-import org.apache.bval.jsr.util.IOs;
-import org.apache.bval.util.FieldAccess;
-import org.apache.bval.util.MethodAccess;
-import org.apache.bval.util.ObjectUtils;
-import org.apache.bval.util.StringUtils;
+import org.apache.bval.jsr.metadata.XmlBuilder;
+import org.apache.bval.jsr.metadata.XmlValidationMappingProvider;
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.Validate;
import org.apache.bval.util.reflection.Reflection;
-import org.apache.commons.weaver.privilizer.Privileged;
import org.apache.commons.weaver.privilizer.Privilizing;
import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
+import org.xml.sax.InputSource;
/**
- * Uses JAXB to parse constraints.xml based on validation-mapping-1.0.xsd.<br>
+ * Uses JAXB to parse constraints.xml based on the validation-mapping XML
+ * schema.
*/
@Privilizing(@CallTo(Reflection.class))
public class ValidationMappingParser {
- private static final String VALIDATION_MAPPING_XSD = "META-INF/validation-mapping-1.1.xsd";
+ private static final SchemaManager SCHEMA_MANAGER = new SchemaManager.Builder()
+ .add(null, "http://jboss.org/xml/ns/javax/validation/mapping", "META-INF/validation-mapping-1.0.xsd")
+ .add(XmlBuilder.Version.v11.getId(), "http://jboss.org/xml/ns/javax/validation/mapping",
+ "META-INF/validation-mapping-1.1.xsd")
+ .add(XmlBuilder.Version.v20.getId(), "http://xmlns.jcp.org/xml/ns/javax/validation/mapping",
+ "META-INF/validation-mapping-2.0.xsd")
+ .build();
- private static final Set<ConstraintAnnotationAttributes> RESERVED_PARAMS = Collections
- .unmodifiableSet(EnumSet.of(ConstraintAnnotationAttributes.GROUPS, ConstraintAnnotationAttributes.MESSAGE,
- ConstraintAnnotationAttributes.PAYLOAD, ConstraintAnnotationAttributes.VALIDATION_APPLIES_TO));
-
- private final Set<Class<?>> processedClasses;
private final ApacheValidatorFactory factory;
public ValidationMappingParser(ApacheValidatorFactory factory) {
- this.factory = factory;
- this.processedClasses = new HashSet<Class<?>>();
+ this.factory = Validate.notNull(factory, "factory");
}
/**
- * Parse files with constraint mappings and collect information in the factory.
- *
- * @param xmlStreams - one or more contraints.xml file streams to parse
+ * Parse files with constraint mappings and collect information in the
+ * factory.
+ *
+ * @param xmlStreams
+ * - one or more contraints.xml file streams to parse
*/
public void processMappingConfig(Set<InputStream> xmlStreams) throws ValidationException {
for (final InputStream xmlStream : xmlStreams) {
- ConstraintMappingsType mapping = parseXmlMappings(xmlStream);
-
- final String defaultPackage = mapping.getDefaultPackage();
- processConstraintDefinitions(mapping.getConstraintDefinition(), defaultPackage);
- for (final BeanType bean : mapping.getBean()) {
- Class<?> beanClass = loadClass(bean.getClazz(), defaultPackage);
- if (!processedClasses.add(beanClass)) {
- // spec: A given class must not be described more than once amongst all
- // the XML mapping descriptors.
- throw new ValidationException(beanClass.getName() + " has already be configured in xml.");
- }
-
- boolean ignoreAnnotations = bean.getIgnoreAnnotations() == null ? true : bean.getIgnoreAnnotations();
- factory.getAnnotationIgnores().setDefaultIgnoreAnnotation(beanClass, ignoreAnnotations);
- processClassLevel(bean.getClassType(), beanClass, defaultPackage);
- processConstructorLevel(bean.getConstructor(), beanClass, defaultPackage, ignoreAnnotations);
- processFieldLevel(bean.getField(), beanClass, defaultPackage, ignoreAnnotations);
- final Collection<String> potentialMethodName =
- processPropertyLevel(bean.getGetter(), beanClass, defaultPackage, ignoreAnnotations);
- processMethodLevel(bean.getMethod(), beanClass, defaultPackage, ignoreAnnotations, potentialMethodName);
- processedClasses.add(beanClass);
- }
+ final ConstraintMappingsType mapping = parseXmlMappings(xmlStream);
+ processConstraintDefinitions(mapping.getConstraintDefinition(), mapping.getDefaultPackage());
+ new XmlBuilder(mapping).forBeans().forEach(factory.getMetadataBuilders()::registerCustomBuilder);
}
}
- /** @param in XML stream to parse using the validation-mapping-1.0.xsd */
+ /**
+ * @param in
+ * XML stream to parse using the validation-mapping-1.0.xsd
+ */
private ConstraintMappingsType parseXmlMappings(final InputStream in) {
- ConstraintMappingsType mappings;
try {
- final JAXBContext jc = JAXBContext.newInstance(ConstraintMappingsType.class);
- final Unmarshaller unmarshaller = jc.createUnmarshaller();
- unmarshaller.setSchema(getSchema());
- final StreamSource stream = new StreamSource(in);
- final JAXBElement<ConstraintMappingsType> root =
- unmarshaller.unmarshal(stream, ConstraintMappingsType.class);
- mappings = root.getValue();
- } catch (final JAXBException e) {
+ return SCHEMA_MANAGER.unmarshal(new InputSource(in), ConstraintMappingsType.class);
+ } catch (Exception e) {
throw new ValidationException("Failed to parse XML deployment descriptor file.", e);
} finally {
- IOs.closeQuietly(in);
try {
- in.reset(); // can be read several times + we ensured it was re-readable in addMapping()
+ in.reset(); // can be read several times + we ensured it was
+ // re-readable in addMapping()
} catch (final IOException e) {
// no-op
}
}
- return mappings;
- }
-
- /** @return validation-mapping-1.0.xsd based schema */
- private Schema getSchema() {
- return ValidationParser.getSchema(VALIDATION_MAPPING_XSD);
- }
-
- private void processClassLevel(ClassType classType, Class<?> beanClass, String defaultPackage) {
- if (classType == null) {
- return;
- }
-
- // ignore annotation
- if (classType.getIgnoreAnnotations() != null) {
- factory.getAnnotationIgnores().setIgnoreAnnotationsOnClass(beanClass, classType.getIgnoreAnnotations());
- }
-
- // group sequence
- Class<?>[] groupSequence = createGroupSequence(classType.getGroupSequence(), defaultPackage);
- if (groupSequence != null) {
- factory.addDefaultSequence(beanClass, groupSequence);
- }
-
- // constraints
- for (ConstraintType constraint : classType.getConstraint()) {
- MetaConstraint<?, ?> metaConstraint = createConstraint(constraint, beanClass, null, defaultPackage);
- factory.addMetaConstraint(beanClass, metaConstraint);
- }
- }
-
- @SuppressWarnings("unchecked")
- private <A extends Annotation, T> MetaConstraint<?, ?> createConstraint(final ConstraintType constraint,
- final Class<T> beanClass, final Member member, final String defaultPackage) {
-
- final Class<A> annotationClass = (Class<A>) loadClass(constraint.getAnnotation(), defaultPackage);
- final AnnotationProxyBuilder<A> annoBuilder = new AnnotationProxyBuilder<A>(annotationClass);
-
- if (constraint.getMessage() != null) {
- annoBuilder.setMessage(constraint.getMessage());
- }
- annoBuilder.setGroups(getGroups(constraint.getGroups(), defaultPackage));
- annoBuilder.setPayload(getPayload(constraint.getPayload(), defaultPackage));
-
- for (final ElementType elementType : constraint.getElement()) {
- final String name = elementType.getName();
- checkValidName(name);
-
- final Class<?> returnType = getAnnotationParameterType(annotationClass, name);
- final Object elementValue = getElementValue(elementType, returnType, defaultPackage);
- annoBuilder.putValue(name, elementValue);
- }
- return new MetaConstraint<T, A>(beanClass, member, annoBuilder.createAnnotation());
- }
-
- private void checkValidName(String name) {
- for (ConstraintAnnotationAttributes attr : RESERVED_PARAMS) {
- if (attr.getAttributeName().equals(name)) {
- throw new ValidationException(name + " is a reserved parameter name.");
- }
- }
- }
-
- private <A extends Annotation> Class<?> getAnnotationParameterType(final Class<A> annotationClass,
- final String name) {
- final Method m = Reflection.getPublicMethod(annotationClass, name);
- if (m == null) {
- throw new ValidationException(
- "Annotation of type " + annotationClass.getName() + " does not contain a parameter " + name + ".");
- }
- return m.getReturnType();
- }
-
- private Object getElementValue(ElementType elementType, Class<?> returnType, String defaultPackage) {
- removeEmptyContentElements(elementType);
-
- boolean isArray = returnType.isArray();
- if (!isArray) {
- if (elementType.getContent().size() != 1) {
- throw new ValidationException("Attempt to specify an array where single value is expected.");
- }
- return getSingleValue(elementType.getContent().get(0), returnType, defaultPackage);
- }
- List<Object> values = new ArrayList<Object>();
- for (Serializable s : elementType.getContent()) {
- values.add(getSingleValue(s, returnType.getComponentType(), defaultPackage));
- }
- return values.toArray((Object[]) Array.newInstance(returnType.getComponentType(), values.size()));
- }
-
- private void removeEmptyContentElements(ElementType elementType) {
- List<Serializable> contentToDelete = new ArrayList<Serializable>();
- for (Serializable content : elementType.getContent()) {
- if (content instanceof String && ((String) content).matches("[\\n ].*")) {
- contentToDelete.add(content);
- }
- }
- elementType.getContent().removeAll(contentToDelete);
- }
-
- @SuppressWarnings("unchecked")
- private Object getSingleValue(Serializable serializable, Class<?> returnType, String defaultPackage) {
- if (serializable instanceof String) {
- String value = (String) serializable;
- return convertToResultType(returnType, value, defaultPackage);
- }
- if (serializable instanceof JAXBElement<?>) {
- JAXBElement<?> elem = (JAXBElement<?>) serializable;
- if (String.class.equals(elem.getDeclaredType())) {
- String value = (String) elem.getValue();
- return convertToResultType(returnType, value, defaultPackage);
- }
- if (AnnotationType.class.equals(elem.getDeclaredType())) {
- AnnotationType annotationType = (AnnotationType) elem.getValue();
- try {
- Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) returnType;
- return createAnnotation(annotationType, annotationClass, defaultPackage);
- } catch (ClassCastException e) {
- throw new ValidationException("Unexpected parameter value");
- }
- }
- }
- throw new ValidationException("Unexpected parameter value");
}
- private Object convertToResultType(Class<?> returnType, String value, String defaultPackage) {
- /**
- * Class is represented by the fully qualified class name of the class.
- * spec: Note that if the raw string is unqualified,
- * default package is taken into account.
- */
- if (returnType.equals(String.class)) {
- return value;
- }
- if (returnType.equals(Class.class)) {
- ClassLoader cl = Reflection.getClassLoader(ValidationMappingParser.class);
- try {
- return Reflection.toClass(toQualifiedClassName(value, defaultPackage), cl);
- } catch (Exception e) {
- throw new ValidationException(e);
- }
- }
- if (returnType.isEnum()) {
- try {
- @SuppressWarnings({ "rawtypes", "unchecked" })
- final Enum e = Enum.valueOf(returnType.asSubclass(Enum.class), value);
- return e;
- } catch (IllegalArgumentException e) {
- throw new ValidationException(e);
- }
- }
- if (Byte.class.equals(returnType) || byte.class.equals(returnType)) { // spec mandates it
- return Byte.parseByte(value);
- }
- if (Short.class.equals(returnType) || short.class.equals(returnType)) {
- return Short.parseShort(value);
- }
- if (Integer.class.equals(returnType) || int.class.equals(returnType)) {
- return Integer.parseInt(value);
- }
- if (Long.class.equals(returnType) || long.class.equals(returnType)) {
- return Long.parseLong(value);
- }
- if (Float.class.equals(returnType) || float.class.equals(returnType)) {
- return Float.parseFloat(value);
- }
- if (Double.class.equals(returnType) || double.class.equals(returnType)) {
- return Double.parseDouble(value);
- }
- if (Boolean.class.equals(returnType) || boolean.class.equals(returnType)) {
- return Boolean.parseBoolean(value);
- }
- if (Character.class.equals(returnType) || char.class.equals(returnType)) {
- if (value.length() > 1) {
- throw new IllegalArgumentException("a char has a length of 1");
- }
- return value.charAt(0);
- }
- throw new ValidationException(String.format("Unknown annotation value type %s", returnType.getName()));
- }
-
- private <A extends Annotation> Annotation createAnnotation(AnnotationType annotationType, Class<A> returnType,
+ private void processConstraintDefinitions(List<ConstraintDefinitionType> constraintDefinitionList,
String defaultPackage) {
- AnnotationProxyBuilder<A> metaAnnotation = new AnnotationProxyBuilder<A>(returnType);
- for (ElementType elementType : annotationType.getElement()) {
- String name = elementType.getName();
- Class<?> parameterType = getAnnotationParameterType(returnType, name);
- Object elementValue = getElementValue(elementType, parameterType, defaultPackage);
- metaAnnotation.putValue(name, elementValue);
- }
- return metaAnnotation.createAnnotation();
- }
- private Class<?>[] getGroups(GroupsType groupsType, String defaultPackage) {
- if (groupsType == null) {
- return ObjectUtils.EMPTY_CLASS_ARRAY;
- }
+ final Map<Class<? extends Annotation>, ValidatedByType> validatorMappings = new HashMap<>();
- List<Class<?>> groupList = new ArrayList<Class<?>>();
- for (String groupClass : groupsType.getValue()) {
- groupList.add(loadClass(groupClass, defaultPackage));
- }
- return groupList.toArray(new Class[groupList.size()]);
- }
-
- @SuppressWarnings("unchecked")
- private Class<? extends Payload>[] getPayload(PayloadType payloadType, String defaultPackage) {
- if (payloadType == null) {
- return new Class[] {};
- }
-
- List<Class<? extends Payload>> payloadList = new ArrayList<Class<? extends Payload>>();
- for (String groupClass : payloadType.getValue()) {
- Class<?> payload = loadClass(groupClass, defaultPackage);
- if (!Payload.class.isAssignableFrom(payload)) {
- throw new ValidationException(
- "Specified payload class " + payload.getName() + " does not implement javax.validation.Payload");
- }
- payloadList.add((Class<? extends Payload>) payload);
- }
- return payloadList.toArray(new Class[payloadList.size()]);
- }
-
- private Class<?>[] createGroupSequence(GroupSequenceType groupSequenceType, String defaultPackage) {
- if (groupSequenceType != null) {
- Class<?>[] groupSequence = new Class<?>[groupSequenceType.getValue().size()];
- int i = 0;
- for (String groupName : groupSequenceType.getValue()) {
- Class<?> group = loadClass(groupName, defaultPackage);
- groupSequence[i++] = group;
- }
- return groupSequence;
- }
- return null;
- }
-
- private <A> void processMethodLevel(final List<MethodType> methods, final Class<A> beanClass,
- final String defaultPackage, final boolean parentIgnoreAnn, final Collection<String> getters) {
- final List<String> methodNames = new ArrayList<String>();
- for (final MethodType methodType : methods) {
- final String methodName = methodType.getName();
- if (methodNames.contains(methodName) || getters.contains(methodName)) {
- throw new ValidationException(
- methodName + " is defined more than once in mapping xml for bean " + beanClass.getName());
- }
- methodNames.add(methodName);
-
- final Method method =
- Reflection.getDeclaredMethod(beanClass, methodName, toTypes(methodType.getParameter(), defaultPackage));
- if (method == null) {
- throw new ValidationException(beanClass.getName() + " does not contain the method " + methodName);
- }
-
- // ignore annotations
- final boolean ignoreMethodAnnotation =
- methodType.getIgnoreAnnotations() == null ? parentIgnoreAnn : methodType.getIgnoreAnnotations();
- factory.getAnnotationIgnores().setIgnoreAnnotationsOnMember(method, ignoreMethodAnnotation);
-
- final boolean ignoreAnn;
- if (methodType.getIgnoreAnnotations() == null) {
- ignoreAnn = parentIgnoreAnn;
- } else {
- ignoreAnn = methodType.getIgnoreAnnotations();
- }
-
- // constraints
- int i = 0;
- for (final ParameterType p : methodType.getParameter()) {
- for (final ConstraintType constraintType : p.getConstraint()) {
- final MetaConstraint<?, ?> constraint =
- createConstraint(constraintType, beanClass, method, defaultPackage);
- constraint.setIndex(i);
- factory.addMetaConstraint(beanClass, constraint);
- }
- if (p.getValid() != null) {
- final MetaConstraint<?, ?> constraint = new MetaConstraint<A, Annotation>(beanClass, method,
- AnnotationProxyBuilder.ValidAnnotation.INSTANCE);
- constraint.setIndex(i);
- factory.addMetaConstraint(beanClass, constraint);
- }
-
- if (p.getConvertGroup() != null) {
- for (final GroupConversionType groupConversion : p.getConvertGroup()) {
- final Class<?> from = loadClass(groupConversion.getFrom(), defaultPackage);
- final Class<?> to = loadClass(groupConversion.getTo(), defaultPackage);
- final MetaConstraint<?, ?> constraint = new MetaConstraint<A, Annotation>(beanClass, method,
- new AnnotationProxyBuilder.ConvertGroupAnnotation(from, to));
- constraint.setIndex(i);
- factory.addMetaConstraint(beanClass, constraint);
- }
- }
-
- boolean ignoreParametersAnnotation =
- p.getIgnoreAnnotations() == null ? ignoreMethodAnnotation : p.getIgnoreAnnotations();
- factory.getAnnotationIgnores().setIgnoreAnnotationsOnParameter(method, i, ignoreParametersAnnotation);
-
- i++;
- }
-
- final ReturnValueType returnValue = methodType.getReturnValue();
- if (returnValue != null) {
- for (final ConstraintType constraintType : returnValue.getConstraint()) {
- final MetaConstraint<?, ?> constraint =
- createConstraint(constraintType, beanClass, method, defaultPackage);
- factory.addMetaConstraint(beanClass, constraint);
- }
- if (returnValue.getValid() != null) {
- final MetaConstraint<?, ?> constraint = new MetaConstraint<A, Annotation>(beanClass, method,
- AnnotationProxyBuilder.ValidAnnotation.INSTANCE);
- factory.addMetaConstraint(beanClass, constraint);
- }
-
- if (returnValue.getConvertGroup() != null) {
- for (final GroupConversionType groupConversion : returnValue.getConvertGroup()) {
- final Class<?> from = loadClass(groupConversion.getFrom(), defaultPackage);
- final Class<?> to = loadClass(groupConversion.getTo(), defaultPackage);
- final MetaConstraint<?, ?> constraint = new MetaConstraint<A, Annotation>(beanClass, method,
- new AnnotationProxyBuilder.ConvertGroupAnnotation(from, to));
- factory.addMetaConstraint(beanClass, constraint);
- }
- }
- factory.getAnnotationIgnores().setIgnoreAnnotationOnReturn(method,
- returnValue.getIgnoreAnnotations() == null ? ignoreAnn : returnValue.getIgnoreAnnotations());
- }
-
- final CrossParameterType crossParameter = methodType.getCrossParameter();
- if (crossParameter != null) {
- for (final ConstraintType constraintType : crossParameter.getConstraint()) {
- final MetaConstraint<?, ?> constraint =
- createConstraint(constraintType, beanClass, method, defaultPackage);
- factory.addMetaConstraint(beanClass, constraint);
- }
- factory.getAnnotationIgnores().setIgnoreAnnotationOnCrossParameter(method,
- crossParameter.getIgnoreAnnotations() != null ? crossParameter.getIgnoreAnnotations() : ignoreAnn);
- }
- }
- }
-
- private <A> void processConstructorLevel(final List<ConstructorType> constructors, final Class<A> beanClass,
- final String defaultPackage, final boolean parentIgnore) {
- for (final ConstructorType constructorType : constructors) {
- final Constructor<?> constructor =
- Reflection.getDeclaredConstructor(beanClass, toTypes(constructorType.getParameter(), defaultPackage));
- if (constructor == null) {
- throw new ValidationException(
- beanClass.getName() + " does not contain the constructor " + constructorType);
- }
-
- // ignore annotations
- final boolean ignoreMethodAnnotation =
- constructorType.getIgnoreAnnotations() == null ? parentIgnore : constructorType.getIgnoreAnnotations();
- factory.getAnnotationIgnores().setIgnoreAnnotationsOnMember(constructor, ignoreMethodAnnotation);
-
- final boolean ignoreAnn;
- if (constructorType.getIgnoreAnnotations() == null) {
- ignoreAnn = parentIgnore;
- } else {
- ignoreAnn = constructorType.getIgnoreAnnotations();
- }
-
- // constraints
- int i = 0;
- for (final ParameterType p : constructorType.getParameter()) {
- for (final ConstraintType constraintType : p.getConstraint()) {
- final MetaConstraint<?, ?> constraint =
- createConstraint(constraintType, beanClass, constructor, defaultPackage);
- constraint.setIndex(i);
- factory.addMetaConstraint(beanClass, constraint);
- }
- if (p.getValid() != null) {
- final MetaConstraint<?, ?> constraint = new MetaConstraint<A, Annotation>(beanClass, constructor,
- AnnotationProxyBuilder.ValidAnnotation.INSTANCE);
- constraint.setIndex(i);
- factory.addMetaConstraint(beanClass, constraint);
- }
-
- if (p.getConvertGroup() != null) {
- for (final GroupConversionType groupConversion : p.getConvertGroup()) {
- final Class<?> from = loadClass(groupConversion.getFrom(), defaultPackage);
- final Class<?> to = loadClass(groupConversion.getTo(), defaultPackage);
- final MetaConstraint<?, ?> constraint = new MetaConstraint<A, Annotation>(beanClass,
- constructor, new AnnotationProxyBuilder.ConvertGroupAnnotation(from, to));
- constraint.setIndex(i);
- factory.addMetaConstraint(beanClass, constraint);
- }
- }
-
- boolean ignoreParametersAnnotation =
- p.getIgnoreAnnotations() == null ? ignoreMethodAnnotation : p.getIgnoreAnnotations();
- if (ignoreParametersAnnotation || (ignoreMethodAnnotation && p.getIgnoreAnnotations() == null)) {
- // TODO what ?
- }
- factory.getAnnotationIgnores().setIgnoreAnnotationsOnParameter(constructor, i,
- p.getIgnoreAnnotations() != null ? p.getIgnoreAnnotations() : ignoreAnn);
-
- i++;
- }
-
- final ReturnValueType returnValue = constructorType.getReturnValue();
- if (returnValue != null) {
- for (final ConstraintType constraintType : returnValue.getConstraint()) {
- final MetaConstraint<?, ?> constraint =
- createConstraint(constraintType, beanClass, constructor, defaultPackage);
- constraint.setIndex(-1);
- factory.addMetaConstraint(beanClass, constraint);
- }
- if (returnValue.getValid() != null) {
- final MetaConstraint<?, ?> constraint = new MetaConstraint<A, Annotation>(beanClass, constructor,
- AnnotationProxyBuilder.ValidAnnotation.INSTANCE);
- constraint.setIndex(-1);
- factory.addMetaConstraint(beanClass, constraint);
- }
-
- if (returnValue.getConvertGroup() != null) {
- for (final GroupConversionType groupConversion : returnValue.getConvertGroup()) {
- final Class<?> from = loadClass(groupConversion.getFrom(), defaultPackage);
- final Class<?> to = loadClass(groupConversion.getTo(), defaultPackage);
- final MetaConstraint<?, ?> constraint = new MetaConstraint<A, Annotation>(beanClass,
- constructor, new AnnotationProxyBuilder.ConvertGroupAnnotation(from, to));
- constraint.setIndex(-1);
- factory.addMetaConstraint(beanClass, constraint);
- }
- }
- factory.getAnnotationIgnores().setIgnoreAnnotationOnReturn(constructor,
- returnValue.getIgnoreAnnotations() != null ? returnValue.getIgnoreAnnotations() : ignoreAnn);
- }
-
- final CrossParameterType crossParameter = constructorType.getCrossParameter();
- if (crossParameter != null) {
- for (final ConstraintType constraintType : crossParameter.getConstraint()) {
- final MetaConstraint<?, ?> constraint =
- createConstraint(constraintType, beanClass, constructor, defaultPackage);
- factory.addMetaConstraint(beanClass, constraint);
- }
- factory.getAnnotationIgnores().setIgnoreAnnotationOnCrossParameter(constructor,
- crossParameter.getIgnoreAnnotations() != null ? crossParameter.getIgnoreAnnotations() : ignoreAnn);
- }
- }
- }
-
- private Class<?>[] toTypes(final List<ParameterType> parameter, final String defaultPck) {
- if (parameter == null) {
- return null;
- }
- final Class<?>[] types = new Class<?>[parameter.size()];
- int i = 0;
- for (final ParameterType type : parameter) {
- types[i++] = loadClass(type.getType(), defaultPck);
- }
- return types;
- }
-
- private <A> void processFieldLevel(List<FieldType> fields, Class<A> beanClass, String defaultPackage,
- boolean ignoreAnnotations) {
- final List<String> fieldNames = new ArrayList<String>();
- for (FieldType fieldType : fields) {
- String fieldName = fieldType.getName();
- if (fieldNames.contains(fieldName)) {
- throw new ValidationException(
- fieldName + " is defined more than once in mapping xml for bean " + beanClass.getName());
- }
- fieldNames.add(fieldName);
-
- final Field field = Reflection.getDeclaredField(beanClass, fieldName);
- if (field == null) {
- throw new ValidationException(beanClass.getName() + " does not contain the fieldType " + fieldName);
- }
-
- // ignore annotations
- final boolean ignoreFieldAnnotation =
- fieldType.getIgnoreAnnotations() == null ? ignoreAnnotations : fieldType.getIgnoreAnnotations();
- factory.getAnnotationIgnores().setIgnoreAnnotationsOnMember(field, ignoreFieldAnnotation);
-
- // valid
- if (fieldType.getValid() != null) {
- factory.addValid(beanClass, new FieldAccess(field));
- }
-
- for (final GroupConversionType conversion : fieldType.getConvertGroup()) {
- final Class<?> from = loadClass(conversion.getFrom(), defaultPackage);
- final Class<?> to = loadClass(conversion.getTo(), defaultPackage);
- final MetaConstraint<?, ?> constraint = new MetaConstraint<A, Annotation>(beanClass, field,
- new AnnotationProxyBuilder.ConvertGroupAnnotation(from, to));
- factory.addMetaConstraint(beanClass, constraint);
- }
-
- // constraints
- for (ConstraintType constraintType : fieldType.getConstraint()) {
- MetaConstraint<?, ?> constraint = createConstraint(constraintType, beanClass, field, defaultPackage);
- factory.addMetaConstraint(beanClass, constraint);
- }
- }
- }
-
- private <A> Collection<String> processPropertyLevel(List<GetterType> getters, Class<A> beanClass,
- String defaultPackage, boolean ignoreAnnotatino) {
- List<String> getterNames = new ArrayList<String>();
- for (GetterType getterType : getters) {
- final String getterName = getterType.getName();
- final String methodName = "get" + StringUtils.capitalize(getterType.getName());
- if (getterNames.contains(methodName)) {
- throw new ValidationException(
- getterName + " is defined more than once in mapping xml for bean " + beanClass.getName());
- }
- getterNames.add(methodName);
-
- final Method method = getGetter(beanClass, getterName);
- if (method == null) {
- throw new ValidationException(beanClass.getName() + " does not contain the property " + getterName);
- }
-
- // ignore annotations
- final boolean ignoreGetterAnnotation =
- getterType.getIgnoreAnnotations() == null ? ignoreAnnotatino : getterType.getIgnoreAnnotations();
- factory.getAnnotationIgnores().setIgnoreAnnotationsOnMember(method, ignoreGetterAnnotation);
-
- // valid
- if (getterType.getValid() != null) {
- factory.addValid(beanClass, new MethodAccess(getterName, method));
- }
-
- // ConvertGroup
- for (final GroupConversionType conversion : getterType.getConvertGroup()) {
- final Class<?> from = loadClass(conversion.getFrom(), defaultPackage);
- final Class<?> to = loadClass(conversion.getTo(), defaultPackage);
- final MetaConstraint<?, ?> constraint = new MetaConstraint<A, Annotation>(beanClass, method,
- new AnnotationProxyBuilder.ConvertGroupAnnotation(from, to));
- factory.addMetaConstraint(beanClass, constraint);
- }
-
- // constraints
- for (ConstraintType constraintType : getterType.getConstraint()) {
- MetaConstraint<?, ?> metaConstraint =
- createConstraint(constraintType, beanClass, method, defaultPackage);
- factory.addMetaConstraint(beanClass, metaConstraint);
- }
- }
-
- return getterNames;
- }
-
- @SuppressWarnings("unchecked")
- private void processConstraintDefinitions(List<ConstraintDefinitionType> constraintDefinitionList,
- String defaultPackage) {
for (ConstraintDefinitionType constraintDefinition : constraintDefinitionList) {
- String annotationClassName = constraintDefinition.getAnnotation();
+ final String annotationClassName = constraintDefinition.getAnnotation();
- Class<?> clazz = loadClass(annotationClassName, defaultPackage);
- if (!clazz.isAnnotation()) {
- throw new ValidationException(annotationClassName + " is not an annotation");
- }
- Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) clazz;
+ final Class<?> clazz = loadClass(annotationClassName, defaultPackage);
- ValidatedByType validatedByType = constraintDefinition.getValidatedBy();
- List<Class<? extends ConstraintValidator<?, ?>>> classes =
- new ArrayList<Class<? extends ConstraintValidator<?, ?>>>();
- /*
- If include-existing-validator is set to false,
- ConstraintValidator defined on the constraint annotation are ignored.
- */
- if (validatedByType.getIncludeExistingValidators() != null
- && validatedByType.getIncludeExistingValidators()) {
- /*
- If set to true, the list of ConstraintValidators described in XML
- are concatenated to the list of ConstraintValidator described on the
- annotation to form a new array of ConstraintValidator evaluated.
- */
- classes.addAll(findConstraintValidatorClasses(annotationClass));
- }
- for (String validatorClassName : validatedByType.getValue()) {
- Class<? extends ConstraintValidator<?, ?>> validatorClass;
- validatorClass = (Class<? extends ConstraintValidator<?, ?>>) loadClass(validatorClassName);
+ Exceptions.raiseUnless(clazz.isAnnotation(), ValidationException::new, "%s is not an annotation",
+ annotationClassName);
- if (!ConstraintValidator.class.isAssignableFrom(validatorClass)) {
- throw new ValidationException(validatorClass + " is not a constraint validator class");
- }
+ final Class<? extends Annotation> annotationClass = clazz.asSubclass(Annotation.class);
- /*
- Annotation based ConstraintValidator come before XML based
- ConstraintValidator in the array. The new list is returned
- by ConstraintDescriptor.getConstraintValidatorClasses().
- */
- if (!classes.contains(validatorClass))
- classes.add(validatorClass);
- }
- if (factory.getConstraintsCache().containsConstraintValidator(annotationClass)) {
- throw new ValidationException(
- "Constraint validator for " + annotationClass.getName() + " already configured.");
- } else {
- factory.getConstraintsCache().putConstraintValidator(annotationClass,
- classes.toArray(new Class[classes.size()]));
- }
- }
- }
+ Exceptions.raiseIf(validatorMappings.containsKey(annotationClass), ValidationException::new,
+ "Constraint validator for %s already configured.", annotationClass);
- private List<Class<? extends ConstraintValidator<? extends Annotation, ?>>> findConstraintValidatorClasses(
- Class<? extends Annotation> annotationType) {
- List<Class<? extends ConstraintValidator<? extends Annotation, ?>>> classes =
- new ArrayList<Class<? extends ConstraintValidator<? extends Annotation, ?>>>();
-
- Class<? extends ConstraintValidator<?, ?>>[] validator =
- factory.getDefaultConstraints().getValidatorClasses(annotationType);
- if (validator == null) {
- /* Collections.addAll() would be more straightforward here, but there is an Oracle compiler bug of some sort
- * that precludes this:
- */
- Class<? extends ConstraintValidator<?, ?>>[] validatedBy =
- annotationType.getAnnotation(Constraint.class).validatedBy();
- classes.addAll(Arrays.asList(validatedBy));
- } else {
- Collections.addAll(classes, validator);
+ validatorMappings.put(annotationClass, constraintDefinition.getValidatedBy());
}
- return classes;
+ factory.getConstraintsCache()
+ .add(new XmlValidationMappingProvider(validatorMappings, cn -> toQualifiedClassName(cn, defaultPackage)));
}
private Class<?> loadClass(String className, String defaultPackage) {
@@ -751,42 +121,27 @@ public class ValidationMappingParser {
private String toQualifiedClassName(String className, String defaultPackage) {
if (!isQualifiedClass(className)) {
if (className.startsWith("[L") && className.endsWith(";")) {
- className = "[L" + defaultPackage + "." + className.substring(2);
+ className = "[L" + defaultPackage + '.' + className.substring(2);
} else {
- className = defaultPackage + "." + className;
+ className = defaultPackage + '.' + className;
}
}
return className;
}
private boolean isQualifiedClass(String clazz) {
- return clazz.contains(".");
- }
-
- @Privileged
- private static Method getGetter(Class<?> clazz, String propertyName) {
- try {
- final String p = StringUtils.capitalize(propertyName);
- try {
- return clazz.getMethod("get" + p);
- } catch (NoSuchMethodException e) {
- return clazz.getMethod("is" + p);
- }
- } catch (NoSuchMethodException e) {
- return null;
- }
+ return clazz.indexOf('.') >= 0;
}
private Class<?> loadClass(final String className) {
ClassLoader loader = Reflection.getClassLoader(ValidationMappingParser.class);
- if (loader == null)
+ if (loader == null) {
loader = getClass().getClassLoader();
-
+ }
try {
- return Class.forName(className, true, loader);
+ return Reflection.toClass(className, loader);
} catch (ClassNotFoundException ex) {
- throw new ValidationException("Unable to load class: " + className, ex);
+ throw Exceptions.create(ValidationException::new, ex, "Unable to load class: %s", className);
}
}
-
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/xml/ValidationParser.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/xml/ValidationParser.java b/bval-jsr/src/main/java/org/apache/bval/jsr/xml/ValidationParser.java
index 7b9b14f..bed2e10 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/xml/ValidationParser.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/xml/ValidationParser.java
@@ -22,12 +22,14 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Collection;
-import java.util.Enumeration;
+import java.util.Collections;
+import java.util.EnumSet;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
+import java.util.Optional;
+import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.logging.Level;
@@ -40,59 +42,34 @@ import javax.validation.TraversableResolver;
import javax.validation.ValidationException;
import javax.validation.executable.ExecutableType;
import javax.validation.spi.ValidationProvider;
-import javax.xml.XMLConstants;
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBElement;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Unmarshaller;
-import javax.xml.transform.stream.StreamSource;
-import javax.xml.validation.Schema;
-import javax.xml.validation.SchemaFactory;
import org.apache.bval.jsr.BootstrapConfigurationImpl;
import org.apache.bval.jsr.ConfigurationImpl;
-import org.apache.bval.jsr.util.IOs;
+import org.apache.bval.jsr.metadata.XmlBuilder;
+import org.apache.bval.util.Exceptions;
import org.apache.bval.util.reflection.Reflection;
import org.apache.commons.weaver.privilizer.Privileged;
import org.apache.commons.weaver.privilizer.Privilizing;
import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
-import org.xml.sax.SAXException;
+import org.xml.sax.InputSource;
/**
* Description: uses jaxb to parse validation.xml<br/>
*/
@Privilizing(@CallTo(Reflection.class))
public class ValidationParser {
+
private static final String DEFAULT_VALIDATION_XML_FILE = "META-INF/validation.xml";
- private static final String VALIDATION_CONFIGURATION_XSD = "META-INF/validation-configuration-1.1.xsd";
private static final Logger log = Logger.getLogger(ValidationParser.class.getName());
- private static final ConcurrentMap<String, Schema> SCHEMA_CACHE = new ConcurrentHashMap<String, Schema>(1);
-
- private ValidationConfigType xmlConfig;
- private BootstrapConfigurationImpl bootstrap;
- private Collection<ValidationException> exceptions = new CopyOnWriteArrayList<ValidationException>();
-
- private ValidationParser() {
- // no-op
- }
- public void applyConfigWithInstantiation(ConfigurationImpl targetConfig) {
- if (xmlConfig == null) {
- return;
- }
-
- applyProviderClass(xmlConfig, targetConfig);
- applyMessageInterpolator(xmlConfig, targetConfig);
- applyTraversableResolver(xmlConfig, targetConfig);
- applyConstraintFactory(xmlConfig, targetConfig);
- applyParameterNameProvider(xmlConfig, targetConfig);
- applyMappingStreams(xmlConfig, targetConfig);
- applyProperties(xmlConfig, targetConfig);
- }
-
- public BootstrapConfigurationImpl getBootstrap() {
- return bootstrap;
- }
+ private static final SchemaManager SCHEMA_MANAGER = new SchemaManager.Builder()
+ .add(null, "http://jboss.org/xml/ns/javax/validation/configuration",
+ "META-INF/validation-configuration-1.0.xsd")
+ .add(XmlBuilder.Version.v11.getId(), "http://jboss.org/xml/ns/javax/validation/configuration",
+ "META-INF/validation-configuration-1.1.xsd")
+ .add(XmlBuilder.Version.v20.getId(), "http://xmlns.jcp.org/xml/ns/javax/validation/configuration",
+ "META-INF/validation-configuration-2.0.xsd")
+ .build();
public static String getValidationXmlFile(String file) {
if (file == null) {
@@ -101,19 +78,30 @@ public class ValidationParser {
return file;
}
- public static ValidationParser processValidationConfig(final String file, final ConfigurationImpl targetConfig, final boolean ignoreXml) {
+ public static ValidationParser processValidationConfig(final String file, final ConfigurationImpl targetConfig,
+ final boolean ignoreXml) {
final ValidationParser parser = new ValidationParser();
if (!ignoreXml) {
parser.xmlConfig = parseXmlConfig(file);
}
- if (parser.xmlConfig != null) {
+ if (parser.xmlConfig == null) { // default config
+ final CopyOnWriteArraySet<ExecutableType> executableTypes = new CopyOnWriteArraySet<>();
+ executableTypes.add(ExecutableType.CONSTRUCTORS);
+ executableTypes.add(ExecutableType.NON_GETTER_METHODS);
+
+ parser.bootstrap = new BootstrapConfigurationImpl(null, null, null, null, null, Collections.emptySet(),
+ true, executableTypes, Collections.emptyMap(), null, Collections.emptySet());
+
+ targetConfig.setExecutableValidation(executableTypes);
+ } else {
if (parser.xmlConfig.getExecutableValidation() == null) {
final ExecutableValidationType value = new ExecutableValidationType();
value.setEnabled(true);
- final DefaultValidatedExecutableTypesType defaultValidatedExecutableTypes = new DefaultValidatedExecutableTypesType();
+ final DefaultValidatedExecutableTypesType defaultValidatedExecutableTypes =
+ new DefaultValidatedExecutableTypesType();
value.setDefaultValidatedExecutableTypes(defaultValidatedExecutableTypes);
defaultValidatedExecutableTypes.getExecutableType().add(ExecutableType.CONSTRUCTORS);
defaultValidatedExecutableTypes.getExecutableType().add(ExecutableType.NON_GETTER_METHODS);
@@ -123,35 +111,19 @@ public class ValidationParser {
applySimpleConfig(parser.xmlConfig, targetConfig);
- parser.bootstrap = new BootstrapConfigurationImpl(
- parser.xmlConfig.getDefaultProvider(),
- parser.xmlConfig.getConstraintValidatorFactory(),
- parser.xmlConfig.getMessageInterpolator(),
- parser.xmlConfig.getTraversableResolver(),
- parser.xmlConfig.getParameterNameProvider(),
- new CopyOnWriteArraySet<String>(parser.xmlConfig.getConstraintMapping()),
- parser.xmlConfig.getExecutableValidation().getEnabled(),
- new CopyOnWriteArraySet<ExecutableType>(targetConfig.getExecutableValidation()),
- toMap(parser.xmlConfig.getProperty()));
- } else { // default config
- final CopyOnWriteArraySet<ExecutableType> executableTypes = new CopyOnWriteArraySet<ExecutableType>();
- executableTypes.add(ExecutableType.CONSTRUCTORS);
- executableTypes.add(ExecutableType.NON_GETTER_METHODS);
-
- parser.bootstrap = new BootstrapConfigurationImpl(
- null, null, null, null, null,
- new CopyOnWriteArraySet<String>(),
- true,
- executableTypes,
- new HashMap<String, String>());
-
- targetConfig.setExecutableValidation(executableTypes);
+ parser.bootstrap = new BootstrapConfigurationImpl(parser.xmlConfig.getDefaultProvider(),
+ parser.xmlConfig.getConstraintValidatorFactory(), parser.xmlConfig.getMessageInterpolator(),
+ parser.xmlConfig.getTraversableResolver(), parser.xmlConfig.getParameterNameProvider(),
+ new HashSet<>(parser.xmlConfig.getConstraintMapping()),
+ parser.xmlConfig.getExecutableValidation().getEnabled(),
+ new HashSet<>(targetConfig.getExecutableValidation()), toMap(parser.xmlConfig.getProperty()),
+ parser.xmlConfig.getClockProvider(), new HashSet<>(parser.xmlConfig.getValueExtractor()));
}
return parser;
}
private static Map<String, String> toMap(final List<PropertyType> property) {
- final Map<String, String> map = new HashMap<String, String>();
+ final Map<String, String> map = new HashMap<>();
if (property != null) {
for (final PropertyType p : property) {
map.put(p.getName(), p.getValue());
@@ -162,78 +134,26 @@ public class ValidationParser {
@Privileged
private static ValidationConfigType parseXmlConfig(final String validationXmlFile) {
- InputStream inputStream = null;
- try {
- inputStream = getInputStream(getValidationXmlFile(validationXmlFile));
+ try (InputStream inputStream = getInputStream(getValidationXmlFile(validationXmlFile))) {
if (inputStream == null) {
- log.log(Level.FINEST, String.format("No %s found. Using annotation based configuration only.", validationXmlFile));
+ log.log(Level.FINEST,
+ String.format("No %s found. Using annotation based configuration only.", validationXmlFile));
return null;
}
-
log.log(Level.FINEST, String.format("%s found.", validationXmlFile));
- Schema schema = getSchema();
- JAXBContext jc = JAXBContext.newInstance(ValidationConfigType.class);
- Unmarshaller unmarshaller = jc.createUnmarshaller();
- unmarshaller.setSchema(schema);
- StreamSource stream = new StreamSource(inputStream);
- JAXBElement<ValidationConfigType> root =
- unmarshaller.unmarshal(stream, ValidationConfigType.class);
- return root.getValue();
- } catch (JAXBException e) {
- throw new ValidationException("Unable to parse " + validationXmlFile, e);
- } catch (IOException e) {
+ return SCHEMA_MANAGER.unmarshal(new InputSource(inputStream), ValidationConfigType.class);
+ } catch (Exception e) {
throw new ValidationException("Unable to parse " + validationXmlFile, e);
- } finally {
- IOs.closeQuietly(inputStream);
}
}
protected static InputStream getInputStream(final String path) throws IOException {
final ClassLoader loader = Reflection.getClassLoader(ValidationParser.class);
- final InputStream inputStream = loader.getResourceAsStream(path);
-
- if (inputStream != null) {
- // spec says: If more than one META-INF/validation.xml file
- // is found in the classpath, a ValidationException is raised.
- final Enumeration<URL> urls = loader.getResources(path);
- if (urls.hasMoreElements()) {
- final String url = urls.nextElement().toString();
- while (urls.hasMoreElements()) {
- if (!url.equals(urls.nextElement().toString())) { // complain when first duplicate found
- throw new ValidationException("More than one " + path + " is found in the classpath");
- }
- }
- }
- }
-
- return IOs.convertToMarkableInputStream(inputStream);
- }
-
- private static Schema getSchema() {
- return getSchema(VALIDATION_CONFIGURATION_XSD);
- }
-
- static Schema getSchema(final String xsd) {
- final Schema schema = SCHEMA_CACHE.get(xsd);
- if (schema != null) {
- return schema;
- }
-
- final ClassLoader loader = Reflection.getClassLoader(ValidationParser.class);
- final SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
- final URL schemaUrl = loader.getResource(xsd);
- try {
- Schema s = sf.newSchema(schemaUrl);
- final Schema old = SCHEMA_CACHE.putIfAbsent(xsd, s);
- if (old != null) {
- s = old;
- }
- return s;
- } catch (SAXException e) {
- log.log(Level.WARNING, String.format("Unable to parse schema: %s", xsd), e);
- return null;
- }
+ final List<URL> urls = Collections.list(loader.getResources(path));
+ Exceptions.raiseIf(urls.stream().distinct().count() > 1, ValidationException::new,
+ "More than one %s is found in the classpath", path);
+ return urls.isEmpty() ? null : urls.get(0).openStream();
}
public static void applySimpleConfig(ValidationConfigType xmlConfig, ConfigurationImpl targetConfig) {
@@ -246,37 +166,84 @@ public class ValidationParser {
}
}
- private static void applyExecutableValidation(final ValidationConfigType xmlConfig, final ConfigurationImpl targetConfig) {
- final CopyOnWriteArrayList<ExecutableType> executableTypes = new CopyOnWriteArrayList<ExecutableType>();
- if (xmlConfig.getExecutableValidation() != null && xmlConfig.getExecutableValidation().getEnabled()
- && xmlConfig.getExecutableValidation().getDefaultValidatedExecutableTypes() != null) {
- executableTypes.addAll(xmlConfig.getExecutableValidation().getDefaultValidatedExecutableTypes().getExecutableType());
- }
+ private static void applyExecutableValidation(final ValidationConfigType xmlConfig,
+ final ConfigurationImpl targetConfig) {
+
+ final Set<ExecutableType> executableTypes = Optional.of(xmlConfig)
+ .map(ValidationConfigType::getExecutableValidation).filter(vc -> Boolean.TRUE.equals(vc.getEnabled()))
+ .map(ExecutableValidationType::getDefaultValidatedExecutableTypes)
+ .map(DefaultValidatedExecutableTypesType::getExecutableType).map(EnumSet::copyOf)
+ .orElseGet(() -> EnumSet.noneOf(ExecutableType.class));
if (executableTypes.contains(ExecutableType.ALL)) {
executableTypes.clear();
executableTypes.add(ExecutableType.CONSTRUCTORS);
executableTypes.add(ExecutableType.NON_GETTER_METHODS);
executableTypes.add(ExecutableType.GETTER_METHODS);
- } else if (executableTypes.contains(ExecutableType.NONE)) { // if both are present ALL gains
+ } else if (executableTypes.contains(ExecutableType.NONE)) { // if both are present ALL trumps NONE
executableTypes.clear();
}
+ targetConfig.setExecutableValidation(Collections.unmodifiableSet(executableTypes));
+ }
+
+ private static void applyMappingStreams(ValidationConfigType xmlConfig, ConfigurationImpl target) {
+ for (String rawMappingFileName : xmlConfig.getConstraintMapping()) {
+ String mappingFileName = rawMappingFileName;
+ if (mappingFileName.charAt(0) == '/') {
+ // Classloader needs a path without a starting /
+ mappingFileName = mappingFileName.substring(1);
+ }
+ log.log(Level.FINEST, String.format("Trying to open input stream for %s", mappingFileName));
+ try {
+ final InputStream in = getInputStream(mappingFileName);
+ Exceptions.raiseIf(in == null, ValidationException::new,
+ "Unable to open input stream for mapping file %s", mappingFileName);
+ target.addMapping(in);
+ } catch (IOException e) {
+ Exceptions.raise(ValidationException::new, e, "Unable to open input stream for mapping file %s",
+ mappingFileName);
+ }
+ }
+ }
+
+ private ValidationConfigType xmlConfig;
+ private BootstrapConfigurationImpl bootstrap;
+ private Collection<ValidationException> exceptions = new CopyOnWriteArrayList<ValidationException>();
+
+ private ValidationParser() {
+ // no-op
+ }
+
+ public void applyConfigWithInstantiation(ConfigurationImpl targetConfig) {
+ if (xmlConfig == null) {
+ return;
+ }
- targetConfig.setExecutableValidation(executableTypes);
+ applyProviderClass(xmlConfig, targetConfig);
+ applyMessageInterpolator(xmlConfig, targetConfig);
+ applyTraversableResolver(xmlConfig, targetConfig);
+ applyConstraintFactory(xmlConfig, targetConfig);
+ applyParameterNameProvider(xmlConfig, targetConfig);
+ applyMappingStreams(xmlConfig, targetConfig);
+ applyProperties(xmlConfig, targetConfig);
+ }
+
+ public BootstrapConfigurationImpl getBootstrap() {
+ return bootstrap;
}
- private void applyParameterNameProvider(final ValidationConfigType xmlConfig, final ConfigurationImpl targetConfig) {
+ private void applyParameterNameProvider(final ValidationConfigType xmlConfig,
+ final ConfigurationImpl targetConfig) {
final String parameterNameProvider = xmlConfig.getParameterNameProvider();
- if (targetConfig.getParameterNameProvider() == targetConfig.getDefaultParameterNameProvider()) { // ref ==
- if (parameterNameProvider != null) {
- final Class<?> loaded = loadClass(parameterNameProvider);
- if (loaded == null) {
- log.log(Level.SEVERE, "Can't load " + parameterNameProvider);
- } else {
- final Class<? extends ParameterNameProvider> clazz = loaded.asSubclass(ParameterNameProvider.class);
- targetConfig.parameterNameProviderClass(clazz);
- log.log(Level.INFO, String.format("Using %s as validation provider.", parameterNameProvider));
- }
+ if (targetConfig.getParameterNameProvider() == targetConfig.getDefaultParameterNameProvider()
+ && parameterNameProvider != null) {
+ final Class<?> loaded = loadClass(parameterNameProvider);
+ if (loaded == null) {
+ log.log(Level.SEVERE, "Can't load " + parameterNameProvider);
+ } else {
+ final Class<? extends ParameterNameProvider> clazz = loaded.asSubclass(ParameterNameProvider.class);
+ targetConfig.parameterNameProviderClass(clazz);
+ log.log(Level.INFO, String.format("Using %s as validation provider.", parameterNameProvider));
}
}
}
@@ -293,65 +260,36 @@ public class ValidationParser {
}
@SuppressWarnings("unchecked")
- private void applyMessageInterpolator(ValidationConfigType xmlConfig,
- ConfigurationImpl target) {
+ private void applyMessageInterpolator(ValidationConfigType xmlConfig, ConfigurationImpl target) {
String messageInterpolatorClass = xmlConfig.getMessageInterpolator();
- if (target.getMessageInterpolator() == target.getDefaultMessageInterpolator()) { // ref ==
- if (messageInterpolatorClass != null) {
- Class<MessageInterpolator> clazz = (Class<MessageInterpolator>)
- loadClass(messageInterpolatorClass);
- target.messageInterpolatorClass(clazz);
- log.log(Level.INFO, String.format("Using %s as message interpolator.", messageInterpolatorClass));
- }
+ if (target.getMessageInterpolator() == target.getDefaultMessageInterpolator()
+ && messageInterpolatorClass != null) {
+ Class<MessageInterpolator> clazz = (Class<MessageInterpolator>) loadClass(messageInterpolatorClass);
+ target.messageInterpolatorClass(clazz);
+ log.log(Level.INFO, String.format("Using %s as message interpolator.", messageInterpolatorClass));
}
}
@SuppressWarnings("unchecked")
- private void applyTraversableResolver(ValidationConfigType xmlConfig,
- ConfigurationImpl target) {
+ private void applyTraversableResolver(ValidationConfigType xmlConfig, ConfigurationImpl target) {
String traversableResolverClass = xmlConfig.getTraversableResolver();
- if (target.getTraversableResolver() == target.getDefaultTraversableResolver() && traversableResolverClass != null) {
- Class<TraversableResolver> clazz = (Class<TraversableResolver>)
- loadClass(traversableResolverClass);
- target.traversableResolverClass(clazz);
- log.log(Level.INFO, String.format("Using %s as traversable resolver.", traversableResolverClass));
- }
+ if (target.getTraversableResolver() == target.getDefaultTraversableResolver()
+ && traversableResolverClass != null) {
+ Class<TraversableResolver> clazz = (Class<TraversableResolver>) loadClass(traversableResolverClass);
+ target.traversableResolverClass(clazz);
+ log.log(Level.INFO, String.format("Using %s as traversable resolver.", traversableResolverClass));
+ }
}
@SuppressWarnings("unchecked")
- private void applyConstraintFactory(ValidationConfigType xmlConfig,
- ConfigurationImpl target) {
+ private void applyConstraintFactory(ValidationConfigType xmlConfig, ConfigurationImpl target) {
String constraintFactoryClass = xmlConfig.getConstraintValidatorFactory();
- if (target.getConstraintValidatorFactory() == target.getDefaultConstraintValidatorFactory() && constraintFactoryClass != null) {
- Class<ConstraintValidatorFactory> clazz = (Class<ConstraintValidatorFactory>)
- loadClass(constraintFactoryClass);
- target.constraintValidatorFactoryClass(clazz);
- log.log(Level.INFO, String.format("Using %s as constraint factory.", constraintFactoryClass));
- }
- }
-
- private static void applyMappingStreams(ValidationConfigType xmlConfig,
- ConfigurationImpl target) {
- for (String rawMappingFileName : xmlConfig.getConstraintMapping()) {
- String mappingFileName = rawMappingFileName;
- if (mappingFileName.startsWith("/")) {
- // Classloader needs a path without a starting /
- mappingFileName = mappingFileName.substring(1);
- }
- log.log(Level.FINEST, String.format("Trying to open input stream for %s", mappingFileName));
- InputStream in;
- try {
- in = getInputStream(mappingFileName);
- if (in == null) {
- throw new ValidationException(
- "Unable to open input stream for mapping file " +
- mappingFileName);
- }
- } catch (IOException e) {
- throw new ValidationException("Unable to open input stream for mapping file " +
- mappingFileName, e);
- }
- target.addMapping(in);
+ if (target.getConstraintValidatorFactory() == target.getDefaultConstraintValidatorFactory()
+ && constraintFactoryClass != null) {
+ Class<ConstraintValidatorFactory> clazz =
+ (Class<ConstraintValidatorFactory>) loadClass(constraintFactoryClass);
+ target.constraintValidatorFactoryClass(clazz);
+ log.log(Level.INFO, String.format("Using %s as constraint factory.", constraintFactoryClass));
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/xml/XmlUtils.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/xml/XmlUtils.java b/bval-jsr/src/main/java/org/apache/bval/jsr/xml/XmlUtils.java
new file mode 100644
index 0000000..2826174
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/xml/XmlUtils.java
@@ -0,0 +1,67 @@
+/*
+ * 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.xml;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.xml.XMLConstants;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.helpers.DefaultValidationEventHandler;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+
+import org.apache.bval.util.reflection.Reflection;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+class XmlUtils {
+ private static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
+ private static final Logger log = Logger.getLogger(XmlUtils.class.getName());
+ private static final SchemaFactory SCHEMA_FACTORY = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+
+ static Schema loadSchema(String resource) {
+ final URL schemaUrl = Reflection.getClassLoader(XmlUtils.class).getResource(resource);
+ try {
+ return SCHEMA_FACTORY.newSchema(schemaUrl);
+ } catch (SAXException e) {
+ log.log(Level.WARNING, String.format("Unable to parse schema: %s", resource), e);
+ return null;
+ }
+ }
+
+ static Document parse(InputStream in) throws SAXException, IOException, ParserConfigurationException {
+ return DOCUMENT_BUILDER_FACTORY.newDocumentBuilder().parse(in);
+ }
+
+ static <T> T unmarshal(Document document, Schema schema, Class<T> type) throws JAXBException {
+ final JAXBContext jc = JAXBContext.newInstance(type);
+ final Unmarshaller unmarshaller = jc.createUnmarshaller();
+ unmarshaller.setSchema(schema);
+ unmarshaller.setEventHandler(new DefaultValidationEventHandler());
+ final JAXBElement<T> root = unmarshaller.unmarshal(document, type);
+ return root.getValue();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/resources/org/apache/bval/jsr/DefaultConstraints.properties
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/resources/org/apache/bval/jsr/DefaultConstraints.properties b/bval-jsr/src/main/resources/org/apache/bval/jsr/DefaultConstraints.properties
index 7bc433b..cc5cd6c 100644
--- a/bval-jsr/src/main/resources/org/apache/bval/jsr/DefaultConstraints.properties
+++ b/bval-jsr/src/main/resources/org/apache/bval/jsr/DefaultConstraints.properties
@@ -22,22 +22,94 @@
javax.validation.constraints.AssertFalse=org.apache.bval.constraints.AssertFalseValidator
javax.validation.constraints.AssertTrue=org.apache.bval.constraints.AssertTrueValidator
+
javax.validation.constraints.DecimalMax=org.apache.bval.constraints.DecimalMaxValidatorForNumber,\
org.apache.bval.constraints.DecimalMaxValidatorForString
+
javax.validation.constraints.DecimalMin=org.apache.bval.constraints.DecimalMinValidatorForNumber,\
org.apache.bval.constraints.DecimalMinValidatorForString
+
javax.validation.constraints.Digits=org.apache.bval.constraints.DigitsValidatorForNumber,\
org.apache.bval.constraints.DigitsValidatorForString
-javax.validation.constraints.Future=org.apache.bval.constraints.FutureValidatorForDate,\
- org.apache.bval.constraints.FutureValidatorForCalendar
+
+javax.validation.constraints.Email=org.apache.bval.constraints.EmailValidator
+
+javax.validation.constraints.Future=\
+ org.apache.bval.constraints.FutureValidator$ForCalendar,\
+ org.apache.bval.constraints.FutureValidator$ForDate,\
+ org.apache.bval.constraints.FutureValidator$ForChronoLocalDate,\
+ org.apache.bval.constraints.FutureValidator$ForChronoLocalDateTime,\
+ org.apache.bval.constraints.FutureValidator$ForChronoZonedDateTime,\
+ org.apache.bval.constraints.FutureValidator$ForInstant,\
+ org.apache.bval.constraints.FutureValidator$ForLocalTime,\
+ org.apache.bval.constraints.FutureValidator$ForMonthDay,\
+ org.apache.bval.constraints.FutureValidator$ForOffsetDateTime,\
+ org.apache.bval.constraints.FutureValidator$ForOffsetTime,\
+ org.apache.bval.constraints.FutureValidator$ForYear,\
+ org.apache.bval.constraints.FutureValidator$ForYearMonth
+
+javax.validation.constraints.FutureOrPresent=\
+ org.apache.bval.constraints.FutureOrPresentValidator$ForCalendar,\
+ org.apache.bval.constraints.FutureOrPresentValidator$ForDate,\
+ org.apache.bval.constraints.FutureOrPresentValidator$ForChronoLocalDate,\
+ org.apache.bval.constraints.FutureOrPresentValidator$ForChronoLocalDateTime,\
+ org.apache.bval.constraints.FutureOrPresentValidator$ForChronoZonedDateTime,\
+ org.apache.bval.constraints.FutureOrPresentValidator$ForInstant,\
+ org.apache.bval.constraints.FutureOrPresentValidator$ForLocalTime,\
+ org.apache.bval.constraints.FutureOrPresentValidator$ForMonthDay,\
+ org.apache.bval.constraints.FutureOrPresentValidator$ForOffsetDateTime,\
+ org.apache.bval.constraints.FutureOrPresentValidator$ForOffsetTime,\
+ org.apache.bval.constraints.FutureOrPresentValidator$ForYear,\
+ org.apache.bval.constraints.FutureOrPresentValidator$ForYearMonth
+
javax.validation.constraints.Max=org.apache.bval.constraints.MaxValidatorForNumber,\
org.apache.bval.constraints.MaxValidatorForString
+
javax.validation.constraints.Min=org.apache.bval.constraints.MinValidatorForNumber,\
org.apache.bval.constraints.MinValidatorForString
+
+javax.validation.constraints.Negative=org.apache.bval.constraints.NumberSignValidator$ForNegative
+javax.validation.constraints.NegativeOrZero=org.apache.bval.constraints.NumberSignValidator$ForNegative$OrZero
+
+javax.validation.constraints.NotEmpty=org.apache.bval.constraints.NotEmptyValidator,\
+ org.apache.bval.constraints.NotEmptyValidatorForCharSequence,\
+ org.apache.bval.constraints.NotEmptyValidatorForCollection,\
+ org.apache.bval.constraints.NotEmptyValidatorForMap
+
javax.validation.constraints.NotNull=org.apache.bval.constraints.NotNullValidator
javax.validation.constraints.Null=org.apache.bval.constraints.NullValidator
-javax.validation.constraints.Past=org.apache.bval.constraints.PastValidatorForDate,\
- org.apache.bval.constraints.PastValidatorForCalendar
+
+javax.validation.constraints.Past=\
+ org.apache.bval.constraints.PastValidator$ForCalendar,\
+ org.apache.bval.constraints.PastValidator$ForDate,\
+ org.apache.bval.constraints.PastValidator$ForChronoLocalDate,\
+ org.apache.bval.constraints.PastValidator$ForChronoLocalDateTime,\
+ org.apache.bval.constraints.PastValidator$ForChronoZonedDateTime,\
+ org.apache.bval.constraints.PastValidator$ForInstant,\
+ org.apache.bval.constraints.PastValidator$ForLocalTime,\
+ org.apache.bval.constraints.PastValidator$ForMonthDay,\
+ org.apache.bval.constraints.PastValidator$ForOffsetDateTime,\
+ org.apache.bval.constraints.PastValidator$ForOffsetTime,\
+ org.apache.bval.constraints.PastValidator$ForYear,\
+ org.apache.bval.constraints.PastValidator$ForYearMonth
+
+javax.validation.constraints.PastOrPresent=\
+ org.apache.bval.constraints.PastOrPresentValidator$ForCalendar,\
+ org.apache.bval.constraints.PastOrPresentValidator$ForDate,\
+ org.apache.bval.constraints.PastOrPresentValidator$ForChronoLocalDate,\
+ org.apache.bval.constraints.PastOrPresentValidator$ForChronoLocalDateTime,\
+ org.apache.bval.constraints.PastOrPresentValidator$ForChronoZonedDateTime,\
+ org.apache.bval.constraints.PastOrPresentValidator$ForInstant,\
+ org.apache.bval.constraints.PastOrPresentValidator$ForLocalTime,\
+ org.apache.bval.constraints.PastOrPresentValidator$ForMonthDay,\
+ org.apache.bval.constraints.PastOrPresentValidator$ForOffsetDateTime,\
+ org.apache.bval.constraints.PastOrPresentValidator$ForOffsetTime,\
+ org.apache.bval.constraints.PastOrPresentValidator$ForYear,\
+ org.apache.bval.constraints.PastOrPresentValidator$ForYearMonth
+
+javax.validation.constraints.Positive=org.apache.bval.constraints.NumberSignValidator$ForPositive
+javax.validation.constraints.PositiveOrZero=org.apache.bval.constraints.NumberSignValidator$ForPositive$OrZero
+
javax.validation.constraints.Size=org.apache.bval.constraints.SizeValidatorForCharSequence,\
org.apache.bval.constraints.SizeValidatorForMap,\
org.apache.bval.constraints.SizeValidatorForCollection,\
@@ -50,4 +122,5 @@ javax.validation.constraints.Size=org.apache.bval.constraints.SizeValidatorForCh
org.apache.bval.constraints.SizeValidatorForArrayOfLong,\
org.apache.bval.constraints.SizeValidatorForArrayOfObject,\
org.apache.bval.constraints.SizeValidatorForArrayOfShort
+
javax.validation.constraints.Pattern=org.apache.bval.constraints.PatternValidator
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/resources/org/apache/bval/jsr/valueextraction/DefaultExtractors.properties
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/resources/org/apache/bval/jsr/valueextraction/DefaultExtractors.properties b/bval-jsr/src/main/resources/org/apache/bval/jsr/valueextraction/DefaultExtractors.properties
new file mode 100644
index 0000000..9d9b768
--- /dev/null
+++ b/bval-jsr/src/main/resources/org/apache/bval/jsr/valueextraction/DefaultExtractors.properties
@@ -0,0 +1,25 @@
+# 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.
+
+javax.validation.valueextraction.ValueExtractor=\
+ org.apache.bval.jsr.valueextraction.IterableElementExtractor,\
+ org.apache.bval.jsr.valueextraction.ListElementExtractor
+
+javax.validation.valueextraction.ValueExtractor.container=\
+ org.apache.bval.jsr.valueextraction.MapExtractor,\
+ org.apache.bval.jsr.valueextraction.OptionalExtractor,\
+ org.apache.bval.jsr.valueextraction.FxExtractor
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/xjb/binding-customization.xjb
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/xjb/binding-customization.xjb b/bval-jsr/src/main/xjb/binding-customization.xjb
index 598bd3c..762a058 100644
--- a/bval-jsr/src/main/xjb/binding-customization.xjb
+++ b/bval-jsr/src/main/xjb/binding-customization.xjb
@@ -19,7 +19,7 @@
-->
<jxb:bindings version="1.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc">
- <jxb:bindings schemaLocation="../xsd/validation-mapping-1.1.xsd" node="/xs:schema">
+ <jxb:bindings schemaLocation="../xsd/validation-mapping-2.0.xsd" node="/xs:schema">
<jxb:globalBindings>
<xjc:javaType name="java.lang.String" xmlType="xs:string"
adapter="javax.xml.bind.annotation.adapters.CollapsedStringAdapter"/>
@@ -29,7 +29,7 @@
<jxb:property name="classType"/>
</jxb:bindings>
</jxb:bindings>
- <jxb:bindings schemaLocation="../xsd/validation-configuration-1.1.xsd" node="/xs:schema">
+ <jxb:bindings schemaLocation="../xsd/validation-configuration-2.0.xsd" node="/xs:schema">
<jxb:bindings node="//xs:element[@name='executable-type']">
<jxb:javaType name="javax.validation.executable.ExecutableType"
parseMethod="javax.validation.executable.ExecutableType.valueOf"/>
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/xsd/validation-configuration-2.0.xsd
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/xsd/validation-configuration-2.0.xsd b/bval-jsr/src/main/xsd/validation-configuration-2.0.xsd
new file mode 100644
index 0000000..6fd7874
--- /dev/null
+++ b/bval-jsr/src/main/xsd/validation-configuration-2.0.xsd
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<xs:schema attributeFormDefault="unqualified"
+ elementFormDefault="qualified"
+ targetNamespace="http://xmlns.jcp.org/xml/ns/javax/validation/configuration"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:config="http://xmlns.jcp.org/xml/ns/javax/validation/configuration"
+ version="2.0">
+ <xs:element name="validation-config" type="config:validation-configType" />
+ <xs:complexType name="validation-configType">
+ <xs:sequence>
+ <xs:element type="xs:string" name="default-provider" minOccurs="0" />
+ <xs:element type="xs:string" name="message-interpolator" minOccurs="0" />
+ <xs:element type="xs:string" name="traversable-resolver" minOccurs="0" />
+ <xs:element type="xs:string" name="constraint-validator-factory" minOccurs="0" />
+ <xs:element type="xs:string" name="parameter-name-provider" minOccurs="0" />
+ <xs:element type="xs:string" name="clock-provider" minOccurs="0" />
+ <xs:element type="xs:string" name="value-extractor" maxOccurs="unbounded" minOccurs="0" />
+ <xs:element type="config:executable-validationType" name="executable-validation" minOccurs="0" />
+ <xs:element type="xs:string" name="constraint-mapping" maxOccurs="unbounded" minOccurs="0" />
+ <xs:element type="config:propertyType" name="property" maxOccurs="unbounded" minOccurs="0" />
+ </xs:sequence>
+ <xs:attribute name="version" type="config:versionType" fixed="2.0" /> <!-- use="required" -->
+ </xs:complexType>
+ <xs:complexType name="executable-validationType">
+ <xs:sequence>
+ <xs:element type="config:default-validated-executable-typesType" name="default-validated-executable-types" minOccurs="0" />
+ </xs:sequence>
+ <xs:attribute name="enabled" use="optional" type="xs:boolean" default="true" />
+ </xs:complexType>
+ <xs:complexType name="default-validated-executable-typesType">
+ <xs:sequence>
+ <xs:element name="executable-type" maxOccurs="unbounded" minOccurs="1">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="NONE" />
+ <xs:enumeration value="CONSTRUCTORS" />
+ <xs:enumeration value="NON_GETTER_METHODS" />
+ <xs:enumeration value="GETTER_METHODS" />
+ <xs:enumeration value="ALL" />
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="propertyType">
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute name="name" use="required" type="xs:string" />
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:simpleType name="versionType">
+ <xs:restriction base="xs:token">
+ <xs:pattern value="[0-9]+(\.[0-9]+)*" />
+ </xs:restriction>
+ </xs:simpleType>
+</xs:schema>
[10/11] bval git commit: implement BV 2.0 against existing BVal unit
tests
Posted by mb...@apache.org.
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/EAN13CheckDigitTest.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/EAN13CheckDigitTest.java b/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/EAN13CheckDigitTest.java
index 83cbf63..052a1c9 100644
--- a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/EAN13CheckDigitTest.java
+++ b/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/EAN13CheckDigitTest.java
@@ -25,7 +25,7 @@ import java.lang.annotation.Annotation;
public class EAN13CheckDigitTest extends AbstractCheckDigitTest {
@Override
- protected ConstraintValidator<? extends Annotation, String> getConstraint() {
+ protected ConstraintValidator<? extends Annotation, ? super String> getConstraint() {
return new EAN13Validator();
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/IBANCheckDigitTest.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/IBANCheckDigitTest.java b/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/IBANCheckDigitTest.java
index c0ea8e6..04cfd73 100644
--- a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/IBANCheckDigitTest.java
+++ b/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/IBANCheckDigitTest.java
@@ -35,7 +35,7 @@ public class IBANCheckDigitTest extends AbstractCheckDigitTest {
}
@Override
- protected ConstraintValidator<? extends Annotation, String> getConstraint() {
+ protected ConstraintValidator<? extends Annotation, ? super String> getConstraint() {
return new IBANValidator();
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/ISBN10CheckDigitTest.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/ISBN10CheckDigitTest.java b/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/ISBN10CheckDigitTest.java
index f03e7a1..4940c8b 100644
--- a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/ISBN10CheckDigitTest.java
+++ b/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/ISBN10CheckDigitTest.java
@@ -25,7 +25,7 @@ import java.lang.annotation.Annotation;
public class ISBN10CheckDigitTest extends AbstractCheckDigitTest {
@Override
- protected ConstraintValidator<? extends Annotation, String> getConstraint() {
+ protected ConstraintValidator<? extends Annotation, ? super String> getConstraint() {
return new ISBN10Validator();
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/LuhnCheckDigitTest.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/LuhnCheckDigitTest.java b/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/LuhnCheckDigitTest.java
index 06263e7..2b09d50 100644
--- a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/LuhnCheckDigitTest.java
+++ b/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/LuhnCheckDigitTest.java
@@ -37,7 +37,7 @@ public class LuhnCheckDigitTest extends AbstractCheckDigitTest {
private static final String VALID_DINERS = "30569309025904";
@Override
- protected ConstraintValidator<? extends Annotation, String> getConstraint() {
+ protected ConstraintValidator<? extends Annotation, ? super String> getConstraint() {
return new LuhnValidator();
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/SedolCheckDigitTest.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/SedolCheckDigitTest.java b/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/SedolCheckDigitTest.java
index 73ea523..55d1f51 100644
--- a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/SedolCheckDigitTest.java
+++ b/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/SedolCheckDigitTest.java
@@ -25,7 +25,7 @@ import java.lang.annotation.Annotation;
public class SedolCheckDigitTest extends AbstractCheckDigitTest {
@Override
- protected ConstraintValidator<? extends Annotation, String> getConstraint() {
+ protected ConstraintValidator<? extends Annotation, ? super String> getConstraint() {
return new SedolValidator();
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/VerhoeffCheckDigitTest.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/VerhoeffCheckDigitTest.java b/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/VerhoeffCheckDigitTest.java
index 2c6e982..fbd3c7f 100644
--- a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/VerhoeffCheckDigitTest.java
+++ b/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/VerhoeffCheckDigitTest.java
@@ -28,7 +28,7 @@ import java.lang.annotation.Annotation;
public class VerhoeffCheckDigitTest extends AbstractCheckDigitTest {
@Override
- protected ConstraintValidator<? extends Annotation, String> getConstraint() {
+ protected ConstraintValidator<? extends Annotation, ? super String> getConstraint() {
return new VerhoeffValidator();
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/test/java/org/apache/bval/extras/constraints/net/InetAddressValidatorTest.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/test/java/org/apache/bval/extras/constraints/net/InetAddressValidatorTest.java b/bval-extras/src/test/java/org/apache/bval/extras/constraints/net/InetAddressValidatorTest.java
index 9eba6ec..a79430d 100644
--- a/bval-extras/src/test/java/org/apache/bval/extras/constraints/net/InetAddressValidatorTest.java
+++ b/bval-extras/src/test/java/org/apache/bval/extras/constraints/net/InetAddressValidatorTest.java
@@ -27,7 +27,7 @@ import static org.junit.Assert.assertTrue;
/**
* Test cases for InetAddressValidator.
*
- * @version $Revision$
+ * @version $Revision: 1766546 $
*/
public class InetAddressValidatorTest {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-json/pom.xml
----------------------------------------------------------------------
diff --git a/bval-json/pom.xml b/bval-json/pom.xml
index a489071..59dcb17 100644
--- a/bval-json/pom.xml
+++ b/bval-json/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.apache.bval</groupId>
<artifactId>bval-parent</artifactId>
- <version>1.1.3-SNAPSHOT</version>
+ <version>2.0.0-SNAPSHOT</version>
</parent>
<artifactId>bval-json</artifactId>
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/pom.xml
----------------------------------------------------------------------
diff --git a/bval-jsr/pom.xml b/bval-jsr/pom.xml
index e716645..561d2d4 100644
--- a/bval-jsr/pom.xml
+++ b/bval-jsr/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.bval</groupId>
<artifactId>bval-parent</artifactId>
- <version>1.1.3-SNAPSHOT</version>
+ <version>2.0.0-SNAPSHOT</version>
</parent>
<artifactId>bval-jsr</artifactId>
@@ -38,7 +38,7 @@
</properties>
<profiles>
<!--
- default profile using geronimo-validation_1.0_spec.jar active when
+ default profile using geronimo-validation_2.0_spec.jar active when
property "ri" is not present.
-->
<profile>
@@ -51,7 +51,7 @@
<dependencies>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
- <artifactId>geronimo-validation_1.1_spec</artifactId>
+ <artifactId>geronimo-validation_2.0_spec</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
@@ -215,6 +215,10 @@
<version>1.0</version>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>com.oracle</groupId>
+ <artifactId>javafx</artifactId>
+ </dependency>
<!-- Testing dependencies -->
<dependency>
@@ -244,10 +248,10 @@
</resources>
<plugins>
- <plugin> <!-- http://jira.codehaus.org/browse/MJAXB-37 -->
+ <plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
- <version>1.4</version>
+ <version>2.3.1</version>
<executions>
<execution>
<goals>
@@ -258,8 +262,11 @@
<configuration>
<packageName>org.apache.bval.jsr.xml</packageName>
<extension>true</extension>
- <schemaFiles>validation-configuration-1.1.xsd,validation-mapping-1.1.xsd</schemaFiles>
<enableIntrospection>true</enableIntrospection>
+ <sources>
+ <source>${project.basedir}/src/main/xsd/validation-configuration-2.0.xsd</source>
+ <source>${project.basedir}/src/main/xsd/validation-mapping-2.0.xsd</source>
+ </sources>
</configuration>
</plugin>
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/cdi/AnyLiteral.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/cdi/AnyLiteral.java b/bval-jsr/src/main/java/org/apache/bval/cdi/AnyLiteral.java
index 2b62c1e..1e14f1e 100644
--- a/bval-jsr/src/main/java/org/apache/bval/cdi/AnyLiteral.java
+++ b/bval-jsr/src/main/java/org/apache/bval/cdi/AnyLiteral.java
@@ -19,7 +19,6 @@
package org.apache.bval.cdi;
import javax.enterprise.inject.Any;
-import javax.enterprise.util.AnnotationLiteral;
public class AnyLiteral extends EmptyAnnotationLiteral<Any> implements Any {
private static final long serialVersionUID = 1L;
@@ -31,7 +30,7 @@ public class AnyLiteral extends EmptyAnnotationLiteral<Any> implements Any {
@Override
public String toString() {
- return "@javax.enterprise.inject.Any()";
+ return String.format("@%s()", Any.class.getName());
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/cdi/BValAnnotatedType.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/cdi/BValAnnotatedType.java b/bval-jsr/src/main/java/org/apache/bval/cdi/BValAnnotatedType.java
index a143a5b..2b08fe6 100644
--- a/bval-jsr/src/main/java/org/apache/bval/cdi/BValAnnotatedType.java
+++ b/bval-jsr/src/main/java/org/apache/bval/cdi/BValAnnotatedType.java
@@ -18,17 +18,16 @@
*/
package org.apache.bval.cdi;
-import javax.enterprise.inject.spi.AnnotatedConstructor;
-import javax.enterprise.inject.spi.AnnotatedField;
-import javax.enterprise.inject.spi.AnnotatedMethod;
-import javax.enterprise.inject.spi.AnnotatedType;
-import javax.enterprise.util.AnnotationLiteral;
-
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.HashSet;
import java.util.Set;
+import javax.enterprise.inject.spi.AnnotatedConstructor;
+import javax.enterprise.inject.spi.AnnotatedField;
+import javax.enterprise.inject.spi.AnnotatedMethod;
+import javax.enterprise.inject.spi.AnnotatedType;
+
public class BValAnnotatedType<A> implements AnnotatedType<A> {
private final AnnotatedType<A> delegate;
private final Set<Annotation> annotations;
@@ -36,8 +35,7 @@ public class BValAnnotatedType<A> implements AnnotatedType<A> {
public BValAnnotatedType(final AnnotatedType<A> annotatedType) {
delegate = annotatedType;
- annotations = new HashSet<Annotation>(annotatedType.getAnnotations().size());
- annotations.addAll(annotatedType.getAnnotations());
+ annotations = new HashSet<>(annotatedType.getAnnotations());
annotations.add(BValBindingLiteral.INSTANCE);
}
@@ -73,14 +71,8 @@ public class BValAnnotatedType<A> implements AnnotatedType<A> {
@Override
public <T extends Annotation> T getAnnotation(final Class<T> annotationType) {
- for (final Annotation ann : annotations) {
- if (ann.annotationType().equals(annotationType)) {
- @SuppressWarnings("unchecked")
- final T result = (T) ann;
- return result;
- }
- }
- return null;
+ return annotations.stream().filter(ann -> ann.annotationType().equals(annotationType)).map(annotationType::cast)
+ .findFirst().orElse(null);
}
@Override
@@ -90,12 +82,7 @@ public class BValAnnotatedType<A> implements AnnotatedType<A> {
@Override
public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
- for (final Annotation ann : annotations) {
- if (ann.annotationType().equals(annotationType)) {
- return true;
- }
- }
- return false;
+ return annotations.stream().anyMatch(ann -> ann.annotationType().equals(annotationType));
}
public static class BValBindingLiteral extends EmptyAnnotationLiteral<BValBinding> implements BValBinding {
@@ -105,7 +92,7 @@ public class BValAnnotatedType<A> implements AnnotatedType<A> {
@Override
public String toString() {
- return "@org.apache.bval.cdi.BValBinding()";
+ return String.format("@%s()", BValBinding.class.getName());
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/cdi/BValExtension.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/cdi/BValExtension.java b/bval-jsr/src/main/java/org/apache/bval/cdi/BValExtension.java
index f84074e..e10a9ba 100644
--- a/bval-jsr/src/main/java/org/apache/bval/cdi/BValExtension.java
+++ b/bval-jsr/src/main/java/org/apache/bval/cdi/BValExtension.java
@@ -59,13 +59,7 @@ import org.apache.bval.util.Validate;
public class BValExtension implements Extension {
private static final Logger LOGGER = Logger.getLogger(BValExtension.class.getName());
- private static final AnnotatedTypeFilter DEFAULT_ANNOTATED_TYPE_FILTER = new AnnotatedTypeFilter() {
-
- @Override
- public boolean accept(AnnotatedType<?> annotatedType) {
- return !annotatedType.getJavaClass().getName().startsWith("org.apache.bval.");
- }
- };
+ private static final AnnotatedTypeFilter DEFAULT_ANNOTATED_TYPE_FILTER = annotatedType -> !annotatedType.getJavaClass().getName().startsWith("org.apache.bval.");
private static AnnotatedTypeFilter annotatedTypeFilter = DEFAULT_ANNOTATED_TYPE_FILTER;
@@ -183,8 +177,7 @@ public class BValExtension implements Extension {
&& !classConstraints.getConstrainedMethods(MethodType.NON_GETTER).isEmpty()
|| validGetterMethods
&& !classConstraints.getConstrainedMethods(MethodType.GETTER).isEmpty())) {
- final BValAnnotatedType<A> bValAnnotatedType = new BValAnnotatedType<A>(annotatedType);
- pat.setAnnotatedType(bValAnnotatedType);
+ pat.setAnnotatedType(new BValAnnotatedType<A>(annotatedType));
}
} catch (final NoClassDefFoundError ncdfe) {
// skip
@@ -199,12 +192,7 @@ public class BValExtension implements Extension {
private static <A> boolean hasValidationAnnotation(
final Collection<? extends AnnotatedCallable<? super A>> methods) {
- for (final AnnotatedCallable<? super A> m : methods) {
- if (m.isAnnotationPresent(ValidateOnExecution.class)) {
- return true;
- }
- }
- return false;
+ return methods.stream().anyMatch(m -> m.isAnnotationPresent(ValidateOnExecution.class));
}
public <A> void processBean(final @Observes ProcessBean<A> processBeanEvent) {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/cdi/BValInterceptor.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/cdi/BValInterceptor.java b/bval-jsr/src/main/java/org/apache/bval/cdi/BValInterceptor.java
index 3a7f000..7bf7709 100644
--- a/bval-jsr/src/main/java/org/apache/bval/cdi/BValInterceptor.java
+++ b/bval-jsr/src/main/java/org/apache/bval/cdi/BValInterceptor.java
@@ -18,8 +18,7 @@
*/
package org.apache.bval.cdi;
-import org.apache.bval.jsr.util.ClassHelper;
-import org.apache.bval.jsr.util.Proxies;
+import static java.util.Arrays.asList;
import java.io.Serializable;
import java.lang.reflect.Constructor;
@@ -33,6 +32,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+
import javax.annotation.Priority;
import javax.enterprise.inject.spi.AnnotatedConstructor;
import javax.enterprise.inject.spi.AnnotatedMethod;
@@ -53,18 +53,20 @@ import javax.validation.executable.ValidateOnExecution;
import javax.validation.metadata.ConstructorDescriptor;
import javax.validation.metadata.MethodDescriptor;
-import static java.util.Arrays.asList;
+import org.apache.bval.jsr.util.ClassHelper;
+import org.apache.bval.jsr.util.Proxies;
/**
* Interceptor class for the {@link BValBinding} {@link InterceptorBinding}.
*/
+@SuppressWarnings("serial")
@Interceptor
@BValBinding
@Priority(4800)
// TODO: maybe add it through ASM to be compliant with CDI 1.0 containers using simply this class as a template to
// generate another one for CDI 1.1 impl
public class BValInterceptor implements Serializable {
- private transient volatile Map<Method, Boolean> methodConfiguration = new ConcurrentHashMap<Method, Boolean>();
+ private transient volatile Map<Method, Boolean> methodConfiguration = new ConcurrentHashMap<>();
private transient volatile Set<ExecutableType> classConfiguration;
private transient volatile Boolean constructorValidated;
@@ -204,7 +206,7 @@ public class BValInterceptor implements Serializable {
methodConfig = methodConfiguration.get(method);
if (methodConfig == null) {
final List<Class<?>> classHierarchy =
- ClassHelper.fillFullClassHierarchyAsList(new LinkedList<Class<?>>(), targetClass);
+ ClassHelper.fillFullClassHierarchyAsList(new LinkedList<>(), targetClass);
Collections.reverse(classHierarchy);
// search on method @ValidateOnExecution
@@ -213,19 +215,19 @@ public class BValInterceptor implements Serializable {
for (final Class<?> c : classHierarchy) {
final AnnotatedType<?> annotatedType = CDI.current().getBeanManager().createAnnotatedType(c);
AnnotatedMethod<?> annotatedMethod = null;
+
for (final AnnotatedMethod<?> m : annotatedType.getMethods()) {
- if (!m.getJavaMember().getName().equals(method.getName())
- || !asList(method.getGenericParameterTypes())
+ if (m.getJavaMember().getName().equals(method.getName())
+ && asList(method.getGenericParameterTypes())
.equals(asList(m.getJavaMember().getGenericParameterTypes()))) {
- continue;
+ annotatedMethod = m;
+ break;
}
- annotatedMethod = m;
- break;
+ }
+ if (annotatedMethod == null) {
+ continue;
}
try {
- if (annotatedMethod == null) {
- continue;
- }
if (validateOnExecutionType == null) {
final ValidateOnExecution vat = annotatedType.getAnnotation(ValidateOnExecution.class);
if (vat != null) {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/cdi/BValInterceptorBean.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/cdi/BValInterceptorBean.java b/bval-jsr/src/main/java/org/apache/bval/cdi/BValInterceptorBean.java
index 8a0c95e..e8f7e1d 100644
--- a/bval-jsr/src/main/java/org/apache/bval/cdi/BValInterceptorBean.java
+++ b/bval-jsr/src/main/java/org/apache/bval/cdi/BValInterceptorBean.java
@@ -43,12 +43,12 @@ public class BValInterceptorBean implements Bean<BValInterceptor>, PassivationCa
private final InjectionTarget<BValInterceptor> injectionTarget;
public BValInterceptorBean(final BeanManager bm) {
- final Set<Type> t = new HashSet<Type>();
+ final Set<Type> t = new HashSet<>();
t.add(BValInterceptor.class);
t.add(Object.class);
types = Collections.unmodifiableSet(t);
- final Set<Annotation> q = new HashSet<Annotation>();
+ final Set<Annotation> q = new HashSet<>();
q.add(DefaultLiteral.INSTANCE);
q.add(AnyLiteral.INSTANCE);
qualifiers = Collections.unmodifiableSet(q);
@@ -120,7 +120,7 @@ public class BValInterceptorBean implements Bean<BValInterceptor>, PassivationCa
@Override
public String getId() {
- return "BValInterceptor-" + hashCode();
+ return String.format("%s-%d",BValInterceptor.class.getSimpleName(), hashCode());
}
private static class BValInterceptorInjectionPoint implements InjectionPoint {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/cdi/DefaultLiteral.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/cdi/DefaultLiteral.java b/bval-jsr/src/main/java/org/apache/bval/cdi/DefaultLiteral.java
index 07b2246..e86db31 100644
--- a/bval-jsr/src/main/java/org/apache/bval/cdi/DefaultLiteral.java
+++ b/bval-jsr/src/main/java/org/apache/bval/cdi/DefaultLiteral.java
@@ -19,7 +19,6 @@
package org.apache.bval.cdi;
import javax.enterprise.inject.Default;
-import javax.enterprise.util.AnnotationLiteral;
public class DefaultLiteral extends EmptyAnnotationLiteral<Default> implements Default {
private static final long serialVersionUID = 1L;
@@ -28,6 +27,6 @@ public class DefaultLiteral extends EmptyAnnotationLiteral<Default> implements D
@Override
public String toString() {
- return "@javax.enterprise.inject.Default()";
+ return String.format("@%s()", Default.class.getName());
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/cdi/EmptyAnnotationLiteral.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/cdi/EmptyAnnotationLiteral.java b/bval-jsr/src/main/java/org/apache/bval/cdi/EmptyAnnotationLiteral.java
index 6866551..e9e9f1a 100644
--- a/bval-jsr/src/main/java/org/apache/bval/cdi/EmptyAnnotationLiteral.java
+++ b/bval-jsr/src/main/java/org/apache/bval/cdi/EmptyAnnotationLiteral.java
@@ -29,6 +29,7 @@ import javax.enterprise.util.AnnotationLiteral;
* Taken from Apache OpenWebBeans.
* @param <T>
*/
+@SuppressWarnings("serial")
public abstract class EmptyAnnotationLiteral<T extends Annotation> extends AnnotationLiteral<T> {
private Class<T> annotationType;
@@ -77,11 +78,10 @@ public abstract class EmptyAnnotationLiteral<T extends Annotation> extends Annot
private Class<T> getAnnotationType(Class<?> definedClazz) {
Type superClazz = definedClazz.getGenericSuperclass();
- Class<T> clazz = null;
-
- if (superClazz.equals(Object.class)) {
- throw new RuntimeException("Super class must be parametrized type!");
- } else if (superClazz instanceof ParameterizedType) {
+ if (Object.class.equals(superClazz)) {
+ throw new RuntimeException("Super class must be parameterized type!");
+ }
+ if (superClazz instanceof ParameterizedType) {
ParameterizedType paramType = (ParameterizedType) superClazz;
Type[] actualArgs = paramType.getActualTypeArguments();
@@ -89,17 +89,15 @@ public abstract class EmptyAnnotationLiteral<T extends Annotation> extends Annot
//Actual annotation type
Type type = actualArgs[0];
- if (type instanceof Class) {
- clazz = (Class<T>) type;
+ if (type instanceof Class<?>) {
+ @SuppressWarnings("unchecked")
+ Class<T> clazz = (Class<T>) type;
return clazz;
- } else {
- throw new RuntimeException("Not class type!");
}
- } else {
- throw new RuntimeException("More than one parametric type!");
+ throw new RuntimeException("Not class type!");
}
- } else {
- return getAnnotationType((Class<?>) superClazz);
+ throw new RuntimeException("More than one parametric type!");
}
+ return getAnnotationType((Class<?>) superClazz);
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/cdi/ValidatorBean.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/cdi/ValidatorBean.java b/bval-jsr/src/main/java/org/apache/bval/cdi/ValidatorBean.java
index c551d72..cd17fae 100644
--- a/bval-jsr/src/main/java/org/apache/bval/cdi/ValidatorBean.java
+++ b/bval-jsr/src/main/java/org/apache/bval/cdi/ValidatorBean.java
@@ -44,12 +44,12 @@ public class ValidatorBean implements Bean<Validator>, PassivationCapable {
this.factory = factory;
this.instance = validator;
- final Set<Type> t = new HashSet<Type>();
+ final Set<Type> t = new HashSet<>();
t.add(Validator.class);
t.add(Object.class);
types = Collections.unmodifiableSet(t);
- final Set<Annotation> q = new HashSet<Annotation>();
+ final Set<Annotation> q = new HashSet<>();
q.add(DefaultLiteral.INSTANCE);
q.add(AnyLiteral.INSTANCE);
qualifiers = Collections.unmodifiableSet(q);
@@ -119,6 +119,6 @@ public class ValidatorBean implements Bean<Validator>, PassivationCapable {
@Override
public String getId() {
- return "BValValidator-" + hashCode();
+ return String.format("BVal%s-%d", Validator.class.getSimpleName(), hashCode());
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/cdi/ValidatorFactoryBean.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/cdi/ValidatorFactoryBean.java b/bval-jsr/src/main/java/org/apache/bval/cdi/ValidatorFactoryBean.java
index aeffd81..0a8c2e5 100644
--- a/bval-jsr/src/main/java/org/apache/bval/cdi/ValidatorFactoryBean.java
+++ b/bval-jsr/src/main/java/org/apache/bval/cdi/ValidatorFactoryBean.java
@@ -41,12 +41,12 @@ public class ValidatorFactoryBean implements Bean<ValidatorFactory>, Passivation
public ValidatorFactoryBean(final ValidatorFactory validatorFactory) {
this.instance = validatorFactory;
- final Set<Type> t = new HashSet<Type>();
+ final Set<Type> t = new HashSet<>();
t.add(ValidatorFactory.class);
t.add(Object.class);
types = Collections.unmodifiableSet(t);
- final Set<Annotation> q = new HashSet<Annotation>();
+ final Set<Annotation> q = new HashSet<>();
q.add(DefaultLiteral.INSTANCE);
q.add(AnyLiteral.INSTANCE);
qualifiers = Collections.unmodifiableSet(q);
@@ -109,6 +109,6 @@ public class ValidatorFactoryBean implements Bean<ValidatorFactory>, Passivation
@Override
public String getId() {
- return "BValValidatorFactory-" + hashCode();
+ return String.format("BVal%s-%d", ValidatorFactory.class.getSimpleName(), hashCode());
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/AssertFalseValidator.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/AssertFalseValidator.java b/bval-jsr/src/main/java/org/apache/bval/constraints/AssertFalseValidator.java
index 9eb4a14..143b76a 100644
--- a/bval-jsr/src/main/java/org/apache/bval/constraints/AssertFalseValidator.java
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/AssertFalseValidator.java
@@ -28,12 +28,8 @@ import javax.validation.constraints.AssertFalse;
public class AssertFalseValidator implements ConstraintValidator<AssertFalse, Boolean> {
@Override
- public void initialize(AssertFalse annotation) {
- }
-
- @Override
public boolean isValid(Boolean value, ConstraintValidatorContext context) {
- return value == null || Boolean.FALSE.equals(value);
+ return !Boolean.TRUE.equals(value);
}
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/AssertTrueValidator.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/AssertTrueValidator.java b/bval-jsr/src/main/java/org/apache/bval/constraints/AssertTrueValidator.java
index 47ee7f6..93ae933 100644
--- a/bval-jsr/src/main/java/org/apache/bval/constraints/AssertTrueValidator.java
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/AssertTrueValidator.java
@@ -28,12 +28,8 @@ import javax.validation.constraints.AssertTrue;
public class AssertTrueValidator implements ConstraintValidator<AssertTrue, Boolean> {
@Override
- public void initialize(AssertTrue annotation) {
- }
-
- @Override
public boolean isValid(Boolean value, ConstraintValidatorContext context) {
- return value == null || Boolean.TRUE.equals(value);
+ return !Boolean.FALSE.equals(value);
}
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/DecimalMaxValidatorForNumber.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/DecimalMaxValidatorForNumber.java b/bval-jsr/src/main/java/org/apache/bval/constraints/DecimalMaxValidatorForNumber.java
index dd0c210..725613c 100644
--- a/bval-jsr/src/main/java/org/apache/bval/constraints/DecimalMaxValidatorForNumber.java
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/DecimalMaxValidatorForNumber.java
@@ -43,12 +43,14 @@ public class DecimalMaxValidatorForNumber implements ConstraintValidator<Decimal
if (value == null) {
return true;
}
+ BigDecimal bigValue;
if (value instanceof BigDecimal) {
- return ((BigDecimal) value).compareTo(maxValue) != 1;
+ bigValue = (BigDecimal) value;
+ } else if (value instanceof BigInteger) {
+ bigValue = new BigDecimal((BigInteger) value);
+ } else {
+ bigValue = new BigDecimal(value.doubleValue());
}
- if (value instanceof BigInteger) {
- return (new BigDecimal((BigInteger) value)).compareTo(maxValue) != 1;
- }
- return (new BigDecimal(value.doubleValue()).compareTo(maxValue)) != 1;
+ return bigValue.compareTo(maxValue) < 1;
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/DecimalMaxValidatorForString.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/DecimalMaxValidatorForString.java b/bval-jsr/src/main/java/org/apache/bval/constraints/DecimalMaxValidatorForString.java
index a247297..cb0e232 100644
--- a/bval-jsr/src/main/java/org/apache/bval/constraints/DecimalMaxValidatorForString.java
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/DecimalMaxValidatorForString.java
@@ -46,7 +46,7 @@ public class DecimalMaxValidatorForString implements ConstraintValidator<Decimal
return true;
}
try {
- return new BigDecimal(value).compareTo(maxValue) != 1;
+ return new BigDecimal(value).compareTo(maxValue) < 1;
} catch (NumberFormatException nfe) {
return false;
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/DecimalMinValidatorForNumber.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/DecimalMinValidatorForNumber.java b/bval-jsr/src/main/java/org/apache/bval/constraints/DecimalMinValidatorForNumber.java
index 74ed17a..17c6c38 100644
--- a/bval-jsr/src/main/java/org/apache/bval/constraints/DecimalMinValidatorForNumber.java
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/DecimalMinValidatorForNumber.java
@@ -43,12 +43,14 @@ public class DecimalMinValidatorForNumber implements ConstraintValidator<Decimal
if (value == null) {
return true;
}
+ BigDecimal bigValue;
if (value instanceof BigDecimal) {
- return ((BigDecimal) value).compareTo(minValue) != -1;
+ bigValue = (BigDecimal) value;
+ } else if (value instanceof BigInteger) {
+ bigValue = new BigDecimal((BigInteger) value);
+ } else {
+ bigValue = new BigDecimal(value.doubleValue());
}
- if (value instanceof BigInteger) {
- return (new BigDecimal((BigInteger) value)).compareTo(minValue) != -1;
- }
- return (new BigDecimal(value.doubleValue()).compareTo(minValue)) != -1;
+ return bigValue.compareTo(minValue) >= 0;
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/DecimalMinValidatorForString.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/DecimalMinValidatorForString.java b/bval-jsr/src/main/java/org/apache/bval/constraints/DecimalMinValidatorForString.java
index 8110f8e..ef62387 100644
--- a/bval-jsr/src/main/java/org/apache/bval/constraints/DecimalMinValidatorForString.java
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/DecimalMinValidatorForString.java
@@ -48,7 +48,7 @@ public class DecimalMinValidatorForString implements ConstraintValidator<Decimal
return true;
}
try {
- return new BigDecimal(value).compareTo(minValue) != -1;
+ return new BigDecimal(value).compareTo(minValue) >= 0;
} catch (NumberFormatException nfe) {
return false;
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/Email.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/Email.java b/bval-jsr/src/main/java/org/apache/bval/constraints/Email.java
index 2d66d28..f1f9435 100644
--- a/bval-jsr/src/main/java/org/apache/bval/constraints/Email.java
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/Email.java
@@ -19,34 +19,41 @@
package org.apache.bval.constraints;
import javax.validation.Constraint;
+import javax.validation.OverridesAttribute;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* <p>
* --
- * TODO - This class is NOT part of the bean_validation spec and might disappear
- * as soon as a final version of the specification contains a similar functionality.
+ * NOTE - This constraint predates the equivalent version from the bean_validation spec.
* --
* </p>
* Description: annotation to validate an email address (by pattern)<br/>
*/
+@Deprecated
@Documented
-@Constraint(validatedBy = EmailValidator.class)
-@Target({ METHOD, FIELD, ANNOTATION_TYPE, PARAMETER })
+@Constraint(validatedBy = {})
+@javax.validation.constraints.Email
+@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface Email {
+ @OverridesAttribute(constraint = javax.validation.constraints.Email.class, name = "groups")
Class<?>[] groups() default {};
+ @OverridesAttribute(constraint = javax.validation.constraints.Email.class, name = "message")
String message() default "{org.apache.bval.constraints.Email.message}";
+ @OverridesAttribute(constraint = javax.validation.constraints.Email.class, name = "payload")
Class<? extends Payload>[] payload() default {};
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/EmailValidator.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/EmailValidator.java b/bval-jsr/src/main/java/org/apache/bval/constraints/EmailValidator.java
index bcdf0fe..b20806b 100644
--- a/bval-jsr/src/main/java/org/apache/bval/constraints/EmailValidator.java
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/EmailValidator.java
@@ -26,15 +26,10 @@ import javax.validation.ConstraintValidatorContext;
/**
* Description: <br/>
*/
-public class EmailValidator implements ConstraintValidator<Email, CharSequence> {
+public class EmailValidator implements ConstraintValidator<javax.validation.constraints.Email, CharSequence> {
@Override
public boolean isValid(CharSequence value, ConstraintValidatorContext context) {
return EMailValidationUtils.isValid(value);
}
-
- @Override
- public void initialize(Email parameters) {
- // do nothing (as long as Email has no properties)
- }
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/FutureOrPresentValidator.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/FutureOrPresentValidator.java b/bval-jsr/src/main/java/org/apache/bval/constraints/FutureOrPresentValidator.java
new file mode 100644
index 0000000..4cc85b1
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/FutureOrPresentValidator.java
@@ -0,0 +1,138 @@
+/*
+ * 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.constraints;
+
+import java.time.Clock;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.MonthDay;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+import java.time.Year;
+import java.time.YearMonth;
+import java.time.ZonedDateTime;
+import java.time.chrono.ChronoLocalDate;
+import java.time.chrono.ChronoLocalDateTime;
+import java.time.chrono.ChronoZonedDateTime;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.function.Function;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.constraints.FutureOrPresent;
+
+/**
+ * Defines built-in {@link ConstraintValidator} implementations for {@link FutureOrPresent}.
+ *
+ * @param <T>
+ * validated type
+ */
+public abstract class FutureOrPresentValidator<T extends Comparable<T>> extends TimeValidator<FutureOrPresent, T> {
+
+ public static class ForDate extends FutureOrPresentValidator<Date> {
+
+ public ForDate() {
+ super(clock -> Date.from(clock.instant()));
+ }
+ }
+
+ public static class ForCalendar extends FutureOrPresentValidator<Calendar> {
+
+ public ForCalendar() {
+ super(clock -> GregorianCalendar.from(clock.instant().atZone(clock.getZone())));
+ }
+ }
+
+ public static class ForInstant extends FutureOrPresentValidator<Instant> {
+
+ public ForInstant() {
+ super(Instant::now);
+ }
+ }
+
+ public static class ForChronoLocalDate extends FutureOrPresentValidator<ChronoLocalDate> {
+
+ public ForChronoLocalDate() {
+ super(LocalDate::now);
+ }
+ }
+
+ public static class ForChronoLocalDateTime extends FutureOrPresentValidator<ChronoLocalDateTime<?>> {
+
+ public ForChronoLocalDateTime() {
+ super(LocalDateTime::now);
+ }
+ }
+
+ public static class ForLocalTime extends FutureOrPresentValidator<LocalTime> {
+
+ public ForLocalTime() {
+ super(LocalTime::now);
+ }
+ }
+
+ public static class ForOffsetDateTime extends FutureOrPresentValidator<OffsetDateTime> {
+
+ public ForOffsetDateTime() {
+ super(OffsetDateTime::now);
+ }
+ }
+
+ public static class ForOffsetTime extends FutureOrPresentValidator<OffsetTime> {
+
+ public ForOffsetTime() {
+ super(OffsetTime::now);
+ }
+ }
+
+ public static class ForChronoZonedDateTime extends FutureOrPresentValidator<ChronoZonedDateTime<?>> {
+
+ public ForChronoZonedDateTime() {
+ super(ZonedDateTime::now);
+ }
+ }
+
+ public static class ForMonthDay extends FutureOrPresentValidator<MonthDay> {
+
+ public ForMonthDay() {
+ super(MonthDay::now);
+ }
+ }
+
+ public static class ForYear extends FutureOrPresentValidator<Year> {
+
+ public ForYear() {
+ super(Year::now);
+ }
+ }
+
+ public static class ForYearMonth extends FutureOrPresentValidator<YearMonth> {
+
+ public ForYearMonth() {
+ super(YearMonth::now);
+ }
+ }
+
+ protected FutureOrPresentValidator(Function<Clock, T> now) {
+ super(now, n -> n >= 0);
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/FutureValidator.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/FutureValidator.java b/bval-jsr/src/main/java/org/apache/bval/constraints/FutureValidator.java
new file mode 100644
index 0000000..dd6116b
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/FutureValidator.java
@@ -0,0 +1,138 @@
+/*
+ * 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.constraints;
+
+import java.time.Clock;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.MonthDay;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+import java.time.Year;
+import java.time.YearMonth;
+import java.time.ZonedDateTime;
+import java.time.chrono.ChronoLocalDate;
+import java.time.chrono.ChronoLocalDateTime;
+import java.time.chrono.ChronoZonedDateTime;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.function.Function;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.constraints.Future;
+
+/**
+ * Defines built-in {@link ConstraintValidator} implementations for {@link Future}.
+ *
+ * @param <T>
+ * validated type
+ */
+public abstract class FutureValidator<T extends Comparable<T>> extends TimeValidator<Future, T> {
+
+ public static class ForDate extends FutureValidator<Date> {
+
+ public ForDate() {
+ super(clock -> Date.from(clock.instant()));
+ }
+ }
+
+ public static class ForCalendar extends FutureValidator<Calendar> {
+
+ public ForCalendar() {
+ super(clock -> GregorianCalendar.from(clock.instant().atZone(clock.getZone())));
+ }
+ }
+
+ public static class ForInstant extends FutureValidator<Instant> {
+
+ public ForInstant() {
+ super(Instant::now);
+ }
+ }
+
+ public static class ForChronoLocalDate extends FutureValidator<ChronoLocalDate> {
+
+ public ForChronoLocalDate() {
+ super(LocalDate::now);
+ }
+ }
+
+ public static class ForChronoLocalDateTime extends FutureValidator<ChronoLocalDateTime<?>> {
+
+ public ForChronoLocalDateTime() {
+ super(LocalDateTime::now);
+ }
+ }
+
+ public static class ForLocalTime extends FutureValidator<LocalTime> {
+
+ public ForLocalTime() {
+ super(LocalTime::now);
+ }
+ }
+
+ public static class ForOffsetDateTime extends FutureValidator<OffsetDateTime> {
+
+ public ForOffsetDateTime() {
+ super(OffsetDateTime::now);
+ }
+ }
+
+ public static class ForOffsetTime extends FutureValidator<OffsetTime> {
+
+ public ForOffsetTime() {
+ super(OffsetTime::now);
+ }
+ }
+
+ public static class ForChronoZonedDateTime extends FutureValidator<ChronoZonedDateTime<?>> {
+
+ public ForChronoZonedDateTime() {
+ super(ZonedDateTime::now);
+ }
+ }
+
+ public static class ForMonthDay extends FutureValidator<MonthDay> {
+
+ public ForMonthDay() {
+ super(MonthDay::now);
+ }
+ }
+
+ public static class ForYear extends FutureValidator<Year> {
+
+ public ForYear() {
+ super(Year::now);
+ }
+ }
+
+ public static class ForYearMonth extends FutureValidator<YearMonth> {
+
+ public ForYearMonth() {
+ super(YearMonth::now);
+ }
+ }
+
+ protected FutureValidator(Function<Clock, T> now) {
+ super(now, n -> n > 0);
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/MaxValidatorForNumber.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/MaxValidatorForNumber.java b/bval-jsr/src/main/java/org/apache/bval/constraints/MaxValidatorForNumber.java
index 78524f9..0ad81a8 100644
--- a/bval-jsr/src/main/java/org/apache/bval/constraints/MaxValidatorForNumber.java
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/MaxValidatorForNumber.java
@@ -43,10 +43,10 @@ public class MaxValidatorForNumber implements ConstraintValidator<Max, Number> {
return true;
}
if (value instanceof BigDecimal) {
- return ((BigDecimal) value).compareTo(BigDecimal.valueOf(max)) != 1;
+ return ((BigDecimal) value).compareTo(BigDecimal.valueOf(max)) < 1;
}
if (value instanceof BigInteger) {
- return ((BigInteger) value).compareTo(BigInteger.valueOf(max)) != 1;
+ return ((BigInteger) value).compareTo(BigInteger.valueOf(max)) < 1;
}
return value.longValue() <= max;
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/MaxValidatorForString.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/MaxValidatorForString.java b/bval-jsr/src/main/java/org/apache/bval/constraints/MaxValidatorForString.java
index 4170a5c..f14f8e7 100644
--- a/bval-jsr/src/main/java/org/apache/bval/constraints/MaxValidatorForString.java
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/MaxValidatorForString.java
@@ -42,7 +42,7 @@ public class MaxValidatorForString implements ConstraintValidator<Max, String> {
return true;
}
try {
- return new BigDecimal(value).compareTo(BigDecimal.valueOf(max)) != 1;
+ return new BigDecimal(value).compareTo(BigDecimal.valueOf(max)) < 1;
} catch (NumberFormatException nfe) {
return false;
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/MinValidatorForNumber.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/MinValidatorForNumber.java b/bval-jsr/src/main/java/org/apache/bval/constraints/MinValidatorForNumber.java
index b5aeaad..c467de2 100644
--- a/bval-jsr/src/main/java/org/apache/bval/constraints/MinValidatorForNumber.java
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/MinValidatorForNumber.java
@@ -42,10 +42,10 @@ public class MinValidatorForNumber implements ConstraintValidator<Min, Number> {
return true;
}
if (value instanceof BigDecimal) {
- return ((BigDecimal) value).compareTo(BigDecimal.valueOf(minValue)) != -1;
+ return ((BigDecimal) value).compareTo(BigDecimal.valueOf(minValue)) >= 0;
}
if (value instanceof BigInteger) {
- return ((BigInteger) value).compareTo(BigInteger.valueOf(minValue)) != -1;
+ return ((BigInteger) value).compareTo(BigInteger.valueOf(minValue)) >= 0;
}
return value.longValue() >= minValue;
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/MinValidatorForString.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/MinValidatorForString.java b/bval-jsr/src/main/java/org/apache/bval/constraints/MinValidatorForString.java
index bd3a4dd..5d45fc2 100644
--- a/bval-jsr/src/main/java/org/apache/bval/constraints/MinValidatorForString.java
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/MinValidatorForString.java
@@ -42,7 +42,7 @@ public class MinValidatorForString implements ConstraintValidator<Min, String> {
return true;
}
try {
- return new BigDecimal(value).compareTo(BigDecimal.valueOf(minValue)) != -1;
+ return new BigDecimal(value).compareTo(BigDecimal.valueOf(minValue)) >= 0;
} catch (NumberFormatException nfe) {
return false;
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/NotBlankValidator.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/NotBlankValidator.java b/bval-jsr/src/main/java/org/apache/bval/constraints/NotBlankValidator.java
new file mode 100644
index 0000000..e201c0d
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/NotBlankValidator.java
@@ -0,0 +1,34 @@
+/*
+ * 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.constraints;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+import javax.validation.constraints.NotBlank;
+
+/**
+ * Validate {@link NotBlank} for {@link CharSequence}.
+ */
+public class NotBlankValidator implements ConstraintValidator<NotBlank, CharSequence> {
+
+ @Override
+ public boolean isValid(CharSequence value, ConstraintValidatorContext context) {
+ return value == null || value.length() > 0 && !value.chars().allMatch(Character::isWhitespace);
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmpty.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmpty.java b/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmpty.java
index ffa8cf8..00497ea 100644
--- a/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmpty.java
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmpty.java
@@ -18,18 +18,22 @@
*/
package org.apache.bval.constraints;
-import javax.validation.Constraint;
-import javax.validation.Payload;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.OverridesAttribute;
+import javax.validation.Payload;
+
/**
* <pre>
* This class is NOT part of the bean_validation spec and might disappear
@@ -37,14 +41,20 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
* </pre>
*/
@Documented
-@Constraint(validatedBy = { NotEmptyValidatorForCollection.class, NotEmptyValidatorForMap.class,
- NotEmptyValidatorForString.class, NotEmptyValidator.class })
-@Target({ METHOD, FIELD, ANNOTATION_TYPE, PARAMETER })
+@Constraint(validatedBy = {})
+@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
+@javax.validation.constraints.NotEmpty
+@Deprecated
public @interface NotEmpty {
Class<?>[] groups() default {};
+ @OverridesAttribute(constraint = javax.validation.constraints.NotEmpty.class, name = "message")
String message() default "{org.apache.bval.constraints.NotEmpty.message}";
Class<? extends Payload>[] payload() default {};
+
+ public @interface List {
+ NotEmpty[] value();
+ }
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidator.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidator.java b/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidator.java
index 4316b39..92c8739 100644
--- a/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidator.java
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidator.java
@@ -25,14 +25,10 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
- * Description: Check the non emptyness of an
+ * Description: Check the non emptiness of an
* any object that has a public isEmpty():boolean or a valid toString() method
*/
-public class NotEmptyValidator implements ConstraintValidator<NotEmpty, Object> {
- @Override
- public void initialize(NotEmpty constraintAnnotation) {
- // do nothing
- }
+public class NotEmptyValidator implements ConstraintValidator<javax.validation.constraints.NotEmpty, Object> {
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
@@ -45,15 +41,12 @@ public class NotEmptyValidator implements ConstraintValidator<NotEmpty, Object>
try {
final Method isEmptyMethod = value.getClass().getMethod("isEmpty");
if (isEmptyMethod != null) {
- return !((Boolean) isEmptyMethod.invoke(value)).booleanValue();
+ return !Boolean.TRUE.equals(isEmptyMethod.invoke(value));
}
- } catch (IllegalAccessException iae) {
- // do nothing
- } catch (NoSuchMethodException nsme) {
- // do nothing
- } catch (InvocationTargetException ite) {
+ } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException iae) {
// do nothing
}
- return !value.toString().isEmpty();
+ final String s = value.toString();
+ return s != null && !s.isEmpty();
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidatorForCharSequence.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidatorForCharSequence.java b/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidatorForCharSequence.java
new file mode 100644
index 0000000..320c105
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidatorForCharSequence.java
@@ -0,0 +1,34 @@
+/*
+ * 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.constraints;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+/**
+ * Description: <br/>
+ */
+public class NotEmptyValidatorForCharSequence
+ implements ConstraintValidator<javax.validation.constraints.NotEmpty, CharSequence> {
+
+ @Override
+ public boolean isValid(CharSequence value, ConstraintValidatorContext context) {
+ return value == null || value.length() > 0;
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidatorForCollection.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidatorForCollection.java b/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidatorForCollection.java
index 5faab13..da0c438 100644
--- a/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidatorForCollection.java
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidatorForCollection.java
@@ -25,11 +25,8 @@ import java.util.Collection;
/**
* Description: <br/>
*/
-public class NotEmptyValidatorForCollection implements ConstraintValidator<NotEmpty, Collection<?>> {
- @Override
- public void initialize(NotEmpty constraintAnnotation) {
- // do nothing
- }
+public class NotEmptyValidatorForCollection
+ implements ConstraintValidator<javax.validation.constraints.NotEmpty, Collection<?>> {
@Override
public boolean isValid(Collection<?> value, ConstraintValidatorContext context) {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidatorForMap.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidatorForMap.java b/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidatorForMap.java
index b5a4f49..6a5221e 100644
--- a/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidatorForMap.java
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidatorForMap.java
@@ -25,11 +25,7 @@ import java.util.Map;
/**
* Description: <br/>
*/
-public class NotEmptyValidatorForMap implements ConstraintValidator<NotEmpty, Map<?, ?>> {
- @Override
- public void initialize(NotEmpty constraintAnnotation) {
- // do nothing
- }
+public class NotEmptyValidatorForMap implements ConstraintValidator<javax.validation.constraints.NotEmpty, Map<?, ?>> {
@Override
public boolean isValid(Map<?, ?> value, ConstraintValidatorContext context) {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidatorForString.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidatorForString.java b/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidatorForString.java
deleted file mode 100644
index 9fc3023..0000000
--- a/bval-jsr/src/main/java/org/apache/bval/constraints/NotEmptyValidatorForString.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.constraints;
-
-import javax.validation.ConstraintValidator;
-import javax.validation.ConstraintValidatorContext;
-
-/**
- * Description: <br/>
- */
-public class NotEmptyValidatorForString implements ConstraintValidator<NotEmpty, String> {
- @Override
- public void initialize(NotEmpty constraintAnnotation) {
- // do nothing
- }
-
- @Override
- public boolean isValid(String value, ConstraintValidatorContext context) {
- return value == null || !value.isEmpty();
- }
-}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/NotNullValidator.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/NotNullValidator.java b/bval-jsr/src/main/java/org/apache/bval/constraints/NotNullValidator.java
index b39d493..c14cff2 100644
--- a/bval-jsr/src/main/java/org/apache/bval/constraints/NotNullValidator.java
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/NotNullValidator.java
@@ -24,10 +24,6 @@ import javax.validation.constraints.NotNull;
/** valid when object is NOT null */
public class NotNullValidator implements ConstraintValidator<NotNull, Object> {
- @Override
- public void initialize(NotNull constraintAnnotation) {
- // do nothing
- }
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/NullValidator.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/NullValidator.java b/bval-jsr/src/main/java/org/apache/bval/constraints/NullValidator.java
index 7c16296..523ef75 100644
--- a/bval-jsr/src/main/java/org/apache/bval/constraints/NullValidator.java
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/NullValidator.java
@@ -28,11 +28,6 @@ import javax.validation.constraints.Null;
public class NullValidator implements ConstraintValidator<Null, Object> {
@Override
- public void initialize(Null annotation) {
- // do nothing
- }
-
- @Override
public boolean isValid(Object object, ConstraintValidatorContext context) {
return object == null;
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/NumberSignValidator.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/NumberSignValidator.java b/bval-jsr/src/main/java/org/apache/bval/constraints/NumberSignValidator.java
new file mode 100644
index 0000000..fe8f59c
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/NumberSignValidator.java
@@ -0,0 +1,68 @@
+/*
+ * 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.constraints;
+
+import java.util.function.IntPredicate;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+import javax.validation.constraints.Negative;
+
+import org.apache.bval.util.Validate;
+
+/**
+ * Description: validate positive/negative number values.
+ */
+public abstract class NumberSignValidator implements ConstraintValidator<Negative, Number> {
+ public static class ForPositive extends NumberSignValidator {
+ public static class OrZero extends NumberSignValidator {
+ public OrZero() {
+ super(n -> n >= 0);
+ }
+ }
+
+ public ForPositive() {
+ super(n -> n > 0);
+ }
+ }
+
+ public static class ForNegative extends NumberSignValidator {
+ public static class OrZero extends NumberSignValidator {
+ public OrZero() {
+ super(n -> n <= 0);
+ }
+ }
+
+ public ForNegative() {
+ super(n -> n < 0);
+ }
+ }
+
+ private final IntPredicate comparisonTest;
+
+ protected NumberSignValidator(IntPredicate comparisonTest) {
+ super();
+ this.comparisonTest = Validate.notNull(comparisonTest);
+ }
+
+ @Override
+ public boolean isValid(Number value, ConstraintValidatorContext context) {
+ return value == null || comparisonTest.test(Double.compare(value.doubleValue(), 0.0));
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/PastOrPresentValidator.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/PastOrPresentValidator.java b/bval-jsr/src/main/java/org/apache/bval/constraints/PastOrPresentValidator.java
new file mode 100644
index 0000000..d1e3e19
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/PastOrPresentValidator.java
@@ -0,0 +1,138 @@
+/*
+ * 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.constraints;
+
+import java.time.Clock;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.MonthDay;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+import java.time.Year;
+import java.time.YearMonth;
+import java.time.ZonedDateTime;
+import java.time.chrono.ChronoLocalDate;
+import java.time.chrono.ChronoLocalDateTime;
+import java.time.chrono.ChronoZonedDateTime;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.function.Function;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.constraints.PastOrPresent;
+
+/**
+ * Defines built-in {@link ConstraintValidator} implementations for {@link PastOrPresent}.
+ *
+ * @param <T>
+ * validated type
+ */
+public abstract class PastOrPresentValidator<T extends Comparable<T>> extends TimeValidator<PastOrPresent, T> {
+
+ public static class ForDate extends PastOrPresentValidator<Date> {
+
+ public ForDate() {
+ super(clock -> Date.from(clock.instant()));
+ }
+ }
+
+ public static class ForCalendar extends PastOrPresentValidator<Calendar> {
+
+ public ForCalendar() {
+ super(clock -> GregorianCalendar.from(clock.instant().atZone(clock.getZone())));
+ }
+ }
+
+ public static class ForInstant extends PastOrPresentValidator<Instant> {
+
+ public ForInstant() {
+ super(Instant::now);
+ }
+ }
+
+ public static class ForChronoLocalDate extends PastOrPresentValidator<ChronoLocalDate> {
+
+ public ForChronoLocalDate() {
+ super(LocalDate::now);
+ }
+ }
+
+ public static class ForChronoLocalDateTime extends PastOrPresentValidator<ChronoLocalDateTime<?>> {
+
+ public ForChronoLocalDateTime() {
+ super(LocalDateTime::now);
+ }
+ }
+
+ public static class ForLocalTime extends PastOrPresentValidator<LocalTime> {
+
+ public ForLocalTime() {
+ super(LocalTime::now);
+ }
+ }
+
+ public static class ForOffsetDateTime extends PastOrPresentValidator<OffsetDateTime> {
+
+ public ForOffsetDateTime() {
+ super(OffsetDateTime::now);
+ }
+ }
+
+ public static class ForOffsetTime extends PastOrPresentValidator<OffsetTime> {
+
+ public ForOffsetTime() {
+ super(OffsetTime::now);
+ }
+ }
+
+ public static class ForChronoZonedDateTime extends PastOrPresentValidator<ChronoZonedDateTime<?>> {
+
+ public ForChronoZonedDateTime() {
+ super(ZonedDateTime::now);
+ }
+ }
+
+ public static class ForMonthDay extends PastOrPresentValidator<MonthDay> {
+
+ public ForMonthDay() {
+ super(MonthDay::now);
+ }
+ }
+
+ public static class ForYear extends PastOrPresentValidator<Year> {
+
+ public ForYear() {
+ super(Year::now);
+ }
+ }
+
+ public static class ForYearMonth extends PastOrPresentValidator<YearMonth> {
+
+ public ForYearMonth() {
+ super(YearMonth::now);
+ }
+ }
+
+ protected PastOrPresentValidator(Function<Clock, T> now) {
+ super(now, n -> n <= 0);
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/PastValidator.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/PastValidator.java b/bval-jsr/src/main/java/org/apache/bval/constraints/PastValidator.java
new file mode 100644
index 0000000..0136d83
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/PastValidator.java
@@ -0,0 +1,138 @@
+/*
+ * 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.constraints;
+
+import java.time.Clock;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.MonthDay;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+import java.time.Year;
+import java.time.YearMonth;
+import java.time.ZonedDateTime;
+import java.time.chrono.ChronoLocalDate;
+import java.time.chrono.ChronoLocalDateTime;
+import java.time.chrono.ChronoZonedDateTime;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.function.Function;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.constraints.Past;
+
+/**
+ * Defines built-in {@link ConstraintValidator} implementations for {@link Past}.
+ *
+ * @param <T>
+ * validated type
+ */
+public abstract class PastValidator<T extends Comparable<T>> extends TimeValidator<Past, T> {
+
+ public static class ForDate extends PastValidator<Date> {
+
+ public ForDate() {
+ super(clock -> Date.from(clock.instant()));
+ }
+ }
+
+ public static class ForCalendar extends PastValidator<Calendar> {
+
+ public ForCalendar() {
+ super(clock -> GregorianCalendar.from(clock.instant().atZone(clock.getZone())));
+ }
+ }
+
+ public static class ForInstant extends PastValidator<Instant> {
+
+ public ForInstant() {
+ super(Instant::now);
+ }
+ }
+
+ public static class ForChronoLocalDate extends PastValidator<ChronoLocalDate> {
+
+ public ForChronoLocalDate() {
+ super(LocalDate::now);
+ }
+ }
+
+ public static class ForChronoLocalDateTime extends PastValidator<ChronoLocalDateTime<?>> {
+
+ public ForChronoLocalDateTime() {
+ super(LocalDateTime::now);
+ }
+ }
+
+ public static class ForLocalTime extends PastValidator<LocalTime> {
+
+ public ForLocalTime() {
+ super(LocalTime::now);
+ }
+ }
+
+ public static class ForOffsetDateTime extends PastValidator<OffsetDateTime> {
+
+ public ForOffsetDateTime() {
+ super(OffsetDateTime::now);
+ }
+ }
+
+ public static class ForOffsetTime extends PastValidator<OffsetTime> {
+
+ public ForOffsetTime() {
+ super(OffsetTime::now);
+ }
+ }
+
+ public static class ForChronoZonedDateTime extends PastValidator<ChronoZonedDateTime<?>> {
+
+ public ForChronoZonedDateTime() {
+ super(ZonedDateTime::now);
+ }
+ }
+
+ public static class ForMonthDay extends PastValidator<MonthDay> {
+
+ public ForMonthDay() {
+ super(MonthDay::now);
+ }
+ }
+
+ public static class ForYear extends PastValidator<Year> {
+
+ public ForYear() {
+ super(Year::now);
+ }
+ }
+
+ public static class ForYearMonth extends PastValidator<YearMonth> {
+
+ public ForYearMonth() {
+ super(YearMonth::now);
+ }
+ }
+
+ protected PastValidator(Function<Clock, T> now) {
+ super(now, n -> n < 0);
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/PatternValidator.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/PatternValidator.java b/bval-jsr/src/main/java/org/apache/bval/constraints/PatternValidator.java
index 9534e6b..8a53062 100644
--- a/bval-jsr/src/main/java/org/apache/bval/constraints/PatternValidator.java
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/PatternValidator.java
@@ -27,7 +27,7 @@ import java.util.regex.PatternSyntaxException;
* validator using a regular expression,
* based on the jsr Pattern constraint annotation.
*/
-public class PatternValidator implements ConstraintValidator<Pattern, String> {
+public class PatternValidator implements ConstraintValidator<Pattern, CharSequence> {
protected java.util.regex.Pattern pattern;
@Override
@@ -46,7 +46,7 @@ public class PatternValidator implements ConstraintValidator<Pattern, String> {
}
@Override
- public boolean isValid(String value, ConstraintValidatorContext context) {
+ public boolean isValid(CharSequence value, ConstraintValidatorContext context) {
return value == null || pattern.matcher(value).matches();
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/constraints/TimeValidator.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/TimeValidator.java b/bval-jsr/src/main/java/org/apache/bval/constraints/TimeValidator.java
new file mode 100644
index 0000000..02e3836
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/constraints/TimeValidator.java
@@ -0,0 +1,44 @@
+/*
+ * 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.constraints;
+
+import java.lang.annotation.Annotation;
+import java.time.Clock;
+import java.util.function.Function;
+import java.util.function.IntPredicate;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+public abstract class TimeValidator<A extends Annotation, T extends Comparable<T>> implements ConstraintValidator<A, T> {
+
+ private final Function<Clock, T> now;
+ private final IntPredicate test;
+
+ protected TimeValidator(Function<Clock, T> now, IntPredicate test) {
+ super();
+ this.now = now;
+ this.test = test;
+ }
+
+ @Override
+ public final boolean isValid(T value, ConstraintValidatorContext context) {
+ return value == null || test.test(value.compareTo(now.apply(context.getClockProvider().getClock())));
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/context/ValidationContext.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/context/ValidationContext.java b/bval-jsr/src/main/java/org/apache/bval/context/ValidationContext.java
new file mode 100644
index 0000000..37415ba
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/context/ValidationContext.java
@@ -0,0 +1,125 @@
+package org.apache.bval.context;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.validation.ClockProvider;
+import javax.validation.ConstraintValidatorContext;
+import javax.validation.Path;
+import javax.validation.ValidationException;
+import javax.validation.metadata.CascadableDescriptor;
+import javax.validation.metadata.ContainerDescriptor;
+import javax.validation.metadata.ElementDescriptor;
+
+import org.apache.bval.jsr.ApacheValidatorFactory;
+import org.apache.bval.jsr.descriptor.BeanD;
+import org.apache.bval.jsr.util.PathImpl;
+import org.apache.bval.model.ValidationListener;
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.Validate;
+
+/**
+ * Context for a single validation call over one object or graph.
+ */
+public class ValidationContext {
+
+ abstract class ElementContext<D> {
+
+ class ValidatorContext implements ConstraintValidatorContext {
+ private final List<ValidationListener.Error> errorMessages = new LinkedList<>();
+ private boolean disableDefaultConstraintViolation;
+
+ /**
+ * Get the queued error messages.
+ *
+ * @return List
+ */
+ List<ValidationListener.Error> getErrorMessages() {
+ if (disableDefaultConstraintViolation && errorMessages.isEmpty()) {
+ throw new ValidationException(
+ "At least one custom message must be created if the default error message gets disabled.");
+ }
+
+ List<ValidationListener.Error> returnedErrorMessages = new ArrayList<>(errorMessages);
+ if (!disableDefaultConstraintViolation) {
+ returnedErrorMessages
+ .add(new ValidationListener.Error(getDefaultConstraintMessageTemplate(), getPath(), null));
+ }
+ return returnedErrorMessages;
+ }
+
+ @Override
+ public void disableDefaultConstraintViolation() {
+ this.disableDefaultConstraintViolation = true;
+ }
+
+ @Override
+ public String getDefaultConstraintMessageTemplate() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public ConstraintViolationBuilder buildConstraintViolationWithTemplate(String messageTemplate) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public final ClockProvider getClockProvider() {
+ return validatorFactory.getClockProvider();
+ }
+
+ @Override
+ public final <T> T unwrap(Class<T> type) {
+ Exceptions.raiseUnless(type.isInstance(this), ValidationException::new, "Type %s not supported", type);
+ return type.cast(this);
+ }
+ }
+
+ protected final D descriptor;
+
+ ElementContext(D descriptor) {
+ super();
+ this.descriptor = Validate.notNull(descriptor, "descriptor");
+ }
+
+ protected abstract PathImpl getPath();
+ }
+
+ private class BeanContext extends ElementContext<BeanD> {
+ BeanContext(BeanD descriptor) {
+ super(descriptor);
+ }
+
+ @Override
+ protected PathImpl getPath() {
+ return PathImpl.create();
+ }
+ }
+
+ private class CascadableContainerContext<D extends ElementDescriptor & CascadableDescriptor & ContainerDescriptor>
+ extends ElementContext<D> {
+
+ private final PathImpl path;
+
+ CascadableContainerContext(D descriptor, Path path) {
+ super(descriptor);
+ this.path = PathImpl.copy(Validate.notNull(path, "path"));
+ }
+
+ @Override
+ protected PathImpl getPath() {
+ // careful, live
+ return path;
+ }
+ }
+
+ private final ApacheValidatorFactory validatorFactory;
+
+ public ValidationContext(ApacheValidatorFactory validatorFactory) {
+ super();
+ this.validatorFactory = Validate.notNull(validatorFactory, "validatorFactory");
+ }
+}
[07/11] bval git commit: implement BV 2.0 against existing BVal unit
tests
Posted by mb...@apache.org.
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java
new file mode 100644
index 0000000..21816d7
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java
@@ -0,0 +1,74 @@
+/*
+ * 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.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.validation.metadata.BeanDescriptor;
+import javax.validation.metadata.CascadableDescriptor;
+import javax.validation.metadata.ElementDescriptor;
+
+import org.apache.bval.jsr.ApacheValidatorFactory;
+import org.apache.bval.jsr.metadata.AnnotationBehaviorMergeStrategy;
+import org.apache.bval.jsr.metadata.CompositeBuilder;
+import org.apache.bval.jsr.metadata.HierarchyBuilder;
+import org.apache.bval.jsr.metadata.MetadataBuilder;
+import org.apache.bval.jsr.metadata.DualBuilder;
+import org.apache.bval.jsr.metadata.ReflectionBuilder;
+import org.apache.bval.util.Validate;
+
+public class DescriptorManager {
+ public static <D extends ElementDescriptor & CascadableDescriptor> boolean isConstrained(D descriptor) {
+ return descriptor.hasConstraints() || descriptor.isCascaded();
+ }
+
+ private final ApacheValidatorFactory validatorFactory;
+ private final ConcurrentMap<Class<?>, BeanD> beanDescriptors = new ConcurrentHashMap<>();
+ private final ReflectionBuilder reflectionBuilder;
+ private final MetadataReader metadataReader;
+
+ public DescriptorManager(ApacheValidatorFactory validatorFactory) {
+ super();
+ this.validatorFactory = Validate.notNull(validatorFactory, "validatorFactory");
+ this.reflectionBuilder = new ReflectionBuilder(validatorFactory);
+ this.metadataReader = new MetadataReader(validatorFactory);
+ }
+
+ public BeanDescriptor getBeanDescriptor(Class<?> beanClass) {
+ Validate.notNull(beanClass, IllegalArgumentException::new, "beanClass");
+ return beanDescriptors.computeIfAbsent(beanClass, k -> new BeanD(metadataReader.forBean(k, builder(k))));
+ }
+
+ private MetadataBuilder.ForBean builder(Class<?> beanClass) {
+ final MetadataBuilder.ForBean primaryBuilder =
+ new HierarchyBuilder(reflectionBuilder::forBean).forBean(beanClass);
+
+ final MetadataBuilder.ForBean customBuilder = new HierarchyBuilder(this::customBuilder).forBean(beanClass);
+
+ return customBuilder.isEmpty() ? primaryBuilder : DualBuilder.forBean(primaryBuilder, customBuilder);
+ }
+
+ private MetadataBuilder.ForBean customBuilder(Class<?> beanClass) {
+ final List<MetadataBuilder.ForBean> customBuilders =
+ validatorFactory.getMetadataBuilders().getCustomBuilders(beanClass);
+
+ return customBuilders.isEmpty() ? null : customBuilders.stream()
+ .collect(CompositeBuilder.with(AnnotationBehaviorMergeStrategy.consensus()).compose());
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ElementD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ElementD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ElementD.java
new file mode 100644
index 0000000..c139773
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ElementD.java
@@ -0,0 +1,122 @@
+/*
+ * 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.ElementType;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.validation.metadata.ConstraintDescriptor;
+import javax.validation.metadata.ElementDescriptor;
+
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.TypeUtils;
+
+public abstract class ElementD<E extends AnnotatedElement, R extends MetadataReader.ForElement<E, ?>>
+ implements ElementDescriptor {
+
+ public static abstract class NonRoot<P extends ElementD<?, ?>, E extends AnnotatedElement, R extends MetadataReader.ForElement<E, ?>>
+ extends ElementD<E, R> {
+
+ protected final P parent;
+
+ protected NonRoot(R reader, P parent) {
+ super(reader);
+ this.parent = Validate.notNull(parent, "parent");
+ }
+
+ public P getParent() {
+ return parent;
+ }
+
+ @Override
+ public final Type getGenericType() {
+ if (TypeUtils.containsTypeVariables(genericType)) {
+ final Map<TypeVariable<?>, Type> args =
+ TypeUtils.getTypeArguments(parent.getGenericType(), Object.class);
+ return TypeUtils.unrollVariables(args, genericType);
+ }
+ return genericType;
+ }
+
+ @Override
+ final protected BeanD getBean() {
+ return parent.getBean();
+ }
+
+ @Override
+ public final List<Class<?>> getGroupSequence() {
+ return getBean().getGroupSequence();
+ }
+ }
+
+ protected final Type genericType;
+
+ private final E target;
+ private final ElementType elementType;
+ private final Set<ConstraintD<?>> constraints;
+
+ protected ElementD(R reader) {
+ super();
+ Validate.notNull(reader, "reader");
+ this.genericType = reader.meta.getType();
+ this.target = reader.meta.getHost();
+ this.elementType = reader.meta.getElementType();
+ this.constraints = reader.getConstraints();
+ }
+
+ @Override
+ public final boolean hasConstraints() {
+ return !constraints.isEmpty();
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Override
+ public final Set<ConstraintDescriptor<?>> getConstraintDescriptors() {
+ return (Set) constraints;
+ }
+
+ @Override
+ public final ConstraintFinder findConstraints() {
+ return new Finder(this);
+ }
+
+ public final ElementType getElementType() {
+ return elementType;
+ }
+
+ public final E getTarget() {
+ return target;
+ }
+
+ public abstract Type getGenericType();
+
+ public abstract List<Class<?>> getGroupSequence();
+
+ protected abstract BeanD getBean();
+
+ @Override
+ public String toString() {
+ return String.format("%s: %s", getClass().getSimpleName(), target);
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ExecutableD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ExecutableD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ExecutableD.java
new file mode 100644
index 0000000..db3df6c
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ExecutableD.java
@@ -0,0 +1,84 @@
+/*
+ * 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.Executable;
+import java.util.List;
+
+import javax.validation.metadata.CrossParameterDescriptor;
+import javax.validation.metadata.ExecutableDescriptor;
+import javax.validation.metadata.ParameterDescriptor;
+import javax.validation.metadata.ReturnValueDescriptor;
+
+public abstract class ExecutableD<E extends Executable, R extends MetadataReader.ForExecutable<E, R>, SELF extends ExecutableD<E, R, SELF>>
+ extends ElementD.NonRoot<BeanD, E, R> implements ExecutableDescriptor {
+
+ private final String name;
+ private final ReturnValueD<SELF, E> returnValue;
+ private final List<ParameterD<SELF>> parameters;
+ private final CrossParameterD<SELF, E> crossParameter;
+
+ @SuppressWarnings("unchecked")
+ protected ExecutableD(R reader, BeanD parent) {
+ super(reader, parent);
+
+ name = reader.meta.getName();
+
+ returnValue = reader.getReturnValueDescriptor((SELF) this);
+ parameters = reader.getParameterDescriptors((SELF) this);
+ crossParameter = reader.getCrossParameterDescriptor((SELF) this);
+ }
+
+ @Override
+ public final String getName() {
+ return name;
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Override
+ public final List<ParameterDescriptor> getParameterDescriptors() {
+ return (List) parameters;
+ }
+
+ @Override
+ public final CrossParameterDescriptor getCrossParameterDescriptor() {
+ return crossParameter;
+ }
+
+ @Override
+ public final ReturnValueDescriptor getReturnValueDescriptor() {
+ return returnValue;
+ }
+
+ @Override
+ public final boolean hasConstrainedParameters() {
+ return parameters.stream().anyMatch(this::isConstrained);
+ }
+
+ @Override
+ public final boolean hasConstrainedReturnValue() {
+ return isConstrained(returnValue);
+ }
+
+ protected abstract String nameOf(E e);
+
+ private boolean isConstrained(CascadableContainerD<?, ?> child) {
+ return child.isCascaded() || child.hasConstraints();
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/Finder.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/Finder.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/Finder.java
new file mode 100644
index 0000000..c01e069
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/Finder.java
@@ -0,0 +1,103 @@
+/*
+ * 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.ElementType;
+import java.util.EnumSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import javax.validation.groups.Default;
+import javax.validation.metadata.ConstraintDescriptor;
+import javax.validation.metadata.ElementDescriptor;
+import javax.validation.metadata.ElementDescriptor.ConstraintFinder;
+import javax.validation.metadata.Scope;
+
+import org.apache.bval.jsr.util.ToUnmodifiable;
+import org.apache.bval.util.Validate;
+
+class Finder implements ConstraintFinder, Supplier<Stream<ConstraintD<?>>> {
+ private Predicate<ConstraintD<?>> groups = c -> true;
+ private Predicate<ConstraintD<?>> scope;
+ private Predicate<ConstraintD<?>> elements;
+
+ private final ElementDescriptor owner;
+
+ Finder(ElementDescriptor owner) {
+ this.owner = Validate.notNull(owner, "owner");
+ }
+
+ @Override
+ public ConstraintFinder unorderedAndMatchingGroups(Class<?>... groups) {
+ this.groups = c -> Stream.of(groups).anyMatch(t -> {
+ final Set<Class<?>> constraintGroups = c.getGroups();
+ return constraintGroups.contains(t)
+ || constraintGroups.contains(Default.class) && c.getDeclaringClass().isAssignableFrom(t);
+ });
+ return this;
+ }
+
+ @Override
+ public ConstraintFinder lookingAt(Scope scope) {
+ this.scope = scope == Scope.HIERARCHY ? null : c -> c.getScope() == scope;
+ return this;
+ }
+
+ @Override
+ public ConstraintFinder declaredOn(ElementType... types) {
+ this.elements = c -> Stream.of(types).filter(Objects::nonNull)
+ .collect(Collectors.toCollection(() -> EnumSet.noneOf(ElementType.class))).contains(c.getDeclaredOn());
+
+ return this;
+ }
+
+ @Override
+ public Set<ConstraintDescriptor<?>> getConstraintDescriptors() {
+ return get().collect(ToUnmodifiable.set());
+ }
+
+ @Override
+ public Stream<ConstraintD<?>> get() {
+ return getConstraints().filter(filter());
+ }
+
+ @Override
+ public boolean hasConstraints() {
+ return getConstraints().anyMatch(filter());
+ }
+
+ private Stream<ConstraintD<?>> getConstraints() {
+ return owner.getConstraintDescriptors().stream().<ConstraintD<?>> map(c -> c.unwrap(ConstraintD.class));
+ }
+
+ private Predicate<ConstraintD<?>> filter() {
+ Predicate<ConstraintD<?>> result = groups;
+ if (scope != null) {
+ result = result.and(scope);
+ }
+ if (elements != null) {
+ result = result.and(elements);
+ }
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/GroupConversion.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/GroupConversion.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/GroupConversion.java
new file mode 100644
index 0000000..9ef724e
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/GroupConversion.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.descriptor;
+
+import java.util.Objects;
+import java.util.Optional;
+
+import javax.validation.metadata.GroupConversionDescriptor;
+
+import org.apache.bval.util.Lazy;
+import org.apache.bval.util.LazyInt;
+import org.apache.bval.util.Validate;
+
+public class GroupConversion implements GroupConversionDescriptor {
+ public static class Builder {
+ private final Class<?> from;
+
+ private Builder(Class<?> from) {
+ this.from = from;
+ }
+
+ public GroupConversion to(Class<?> to) {
+ return new GroupConversion(from, to);
+ }
+ }
+
+ public static Builder from(Class<?> from) {
+ return new Builder(from);
+ }
+
+ private final Class<?> from;
+ private final Class<?> to;
+ private final LazyInt hashCode;
+ private final Lazy<String> toString;
+
+ private GroupConversion(Class<?> from, Class<?> to) {
+ super();
+ this.from = Validate.notNull(from, "from");
+ this.to = Validate.notNull(to, "to");
+ this.hashCode = new LazyInt(() -> Objects.hash(this.from, this.to));
+ this.toString = new Lazy<>(
+ () -> String.format("%s from %s to %s", GroupConversion.class.getSimpleName(), this.from, this.to));
+ }
+
+ @Override
+ public Class<?> getFrom() {
+ return from;
+ }
+
+ @Override
+ public Class<?> getTo() {
+ return to;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj == this
+ || Optional.ofNullable(obj).filter(GroupConversion.class::isInstance).map(GroupConversion.class::cast)
+ .filter(gc -> Objects.equals(from, gc.from) && Objects.equals(to, gc.to)).isPresent();
+ }
+
+ @Override
+ public int hashCode() {
+ return hashCode.getAsInt();
+ }
+
+ @Override
+ public String toString() {
+ return toString.get();
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/MetadataReader.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/MetadataReader.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/MetadataReader.java
new file mode 100644
index 0000000..c2f9f0c
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/MetadataReader.java
@@ -0,0 +1,291 @@
+/*
+ * 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.reflect.AnnotatedElement;
+import java.lang.reflect.AnnotatedType;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import javax.validation.GroupDefinitionException;
+import javax.validation.GroupSequence;
+import javax.validation.ParameterNameProvider;
+import javax.validation.groups.Default;
+import javax.validation.metadata.PropertyDescriptor;
+import javax.validation.metadata.Scope;
+
+import org.apache.bval.jsr.ApacheValidatorFactory;
+import org.apache.bval.jsr.metadata.ContainerElementKey;
+import org.apache.bval.jsr.metadata.EmptyBuilder;
+import org.apache.bval.jsr.metadata.MetadataBuilder;
+import org.apache.bval.jsr.metadata.Metas;
+import org.apache.bval.jsr.metadata.Signature;
+import org.apache.bval.jsr.util.Methods;
+import org.apache.bval.jsr.util.ToUnmodifiable;
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.Reflection;
+
+class MetadataReader {
+
+ class ForElement<E extends AnnotatedElement, B extends MetadataBuilder.ForElement<E>> {
+ final Metas<E> meta;
+ protected final B builder;
+
+ ForElement(Metas<E> meta, B builder) {
+ super();
+ this.meta = Validate.notNull(meta, "meta");
+ this.builder = Validate.notNull(builder, "builder");
+ }
+
+ Set<ConstraintD<?>> getConstraints() {
+ return builder.getConstraintsByScope(meta).entrySet().stream()
+ .flatMap(e -> describe(e.getValue(), e.getKey(), meta)).collect(ToUnmodifiable.set());
+ }
+
+ private Stream<ConstraintD<?>> describe(Annotation[] constraints, Scope scope, Metas<?> meta) {
+ return Stream.of(constraints).map(c -> new ConstraintD<>(c, scope, meta, validatorFactory));
+ }
+ }
+
+ class ForBean extends MetadataReader.ForElement<Class<?>, MetadataBuilder.ForClass> {
+ private final MetadataBuilder.ForBean beanBuilder;
+
+ ForBean(Metas<Class<?>> meta, MetadataBuilder.ForBean builder) {
+ super(meta, Validate.notNull(builder, "builder").getClass(meta));
+ this.beanBuilder = builder;
+ }
+
+ Map<String, PropertyDescriptor> getProperties(BeanD parent) {
+ final Map<String, List<PropertyD<?>>> properties = new LinkedHashMap<>();
+ final Function<? super String, ? extends List<PropertyD<?>>> descriptorList = k -> new ArrayList<>();
+
+ beanBuilder.getFields(meta).forEach((f, builder) -> {
+ final Field fld = Reflection.find(meta.getHost(), t -> Reflection.getDeclaredField(t, f));
+ properties.computeIfAbsent(f, descriptorList).add(new PropertyD.ForField(
+ new MetadataReader.ForContainer<>(new Metas.ForField(fld), builder), parent));
+ });
+
+ beanBuilder.getGetters(meta).forEach((g, builder) -> {
+ final Method getter = Reflection.find(meta.getHost(), t -> {
+ return Stream.of(Reflection.getDeclaredMethods(t)).filter(Methods::isGetter)
+ .filter(m -> g.equals(Methods.propertyName(m))).findFirst().orElse(null);
+ });
+ Exceptions.raiseIf(getter == null, IllegalStateException::new,
+ "Getter method for property %s not found", g);
+
+ properties.computeIfAbsent(g, descriptorList).add(new PropertyD.ForMethod(
+ new MetadataReader.ForContainer<>(new Metas.ForMethod(getter), builder), parent));
+ });
+ return properties.entrySet().stream().collect(ToUnmodifiable.map(Map.Entry::getKey, e -> {
+ final List<PropertyD<?>> delegates = e.getValue();
+
+ if (delegates.size() == 1) {
+ return delegates.get(0);
+ }
+ final Set<PropertyD<?>> constrained =
+ delegates.stream().filter(DescriptorManager::isConstrained).collect(Collectors.toSet());
+ if (constrained.isEmpty()) {
+ return delegates.get(0);
+ }
+ if (constrained.size() == 1) {
+ return constrained.iterator().next();
+ }
+ return new ComposedD.ForProperty(delegates);
+ }));
+ }
+
+ Map<Signature, MethodD> getMethods(BeanD parent) {
+ final Map<Signature, MetadataBuilder.ForExecutable<Method>> methodBuilders = beanBuilder.getMethods(meta);
+ if (methodBuilders.isEmpty()) {
+ return Collections.emptyMap();
+ }
+ final Map<Signature, MethodD> result = new LinkedHashMap<>();
+
+ methodBuilders.forEach((sig, builder) -> {
+ final Method m = Reflection.find(meta.getHost(),
+ t -> Reflection.getDeclaredMethod(t, sig.getName(), sig.getParameterTypes()));
+
+ result.put(sig, new MethodD(new MetadataReader.ForMethod(new Metas.ForMethod(m), builder), parent));
+ });
+ return Collections.unmodifiableMap(result);
+ }
+
+ Map<Signature, ConstructorD> getConstructors(BeanD parent) {
+ final Map<Signature, MetadataBuilder.ForExecutable<Constructor<?>>> ctorBuilders =
+ beanBuilder.getConstructors(meta);
+
+ if (ctorBuilders.isEmpty()) {
+ return Collections.emptyMap();
+ }
+ final Map<Signature, ConstructorD> result = new LinkedHashMap<>();
+
+ ctorBuilders.forEach((sig, builder) -> {
+ final Constructor<?> c = Reflection.getDeclaredConstructor(meta.getHost(), sig.getParameterTypes());
+ result.put(sig,
+ new ConstructorD(new MetadataReader.ForConstructor(new Metas.ForConstructor(c), builder), parent));
+ });
+ return Collections.unmodifiableMap(result);
+ }
+
+ List<Class<?>> getGroupSequence() {
+ List<Class<?>> result = builder.getGroupSequence(meta);
+ if (result == null) {
+ // resolve group sequence/Default redefinition up class hierarchy:
+ final Class<?> superclass = meta.getHost().getSuperclass();
+ if (superclass != null) {
+ // attempt to mock parent sequence intent by appending this type immediately after supertype:
+ result = ((ElementD<?, ?>) validatorFactory.getDescriptorManager().getBeanDescriptor(superclass))
+ .getGroupSequence();
+ if (result != null) {
+ result = new ArrayList<>(result);
+ result.add(result.indexOf(superclass) + 1, meta.getHost());
+ }
+ }
+ }
+ if (result != null) {
+ Exceptions.raiseUnless(result.contains(meta.getHost()), GroupDefinitionException::new,
+ "@%s for %s must contain %<s", GroupSequence.class.getSimpleName(), meta.getHost());
+ Exceptions.raiseIf(result.contains(Default.class), GroupDefinitionException::new,
+ "@%s for %s must not contain %s", GroupSequence.class.getSimpleName(), meta.getHost(),
+ Default.class.getName());
+ }
+ return result;
+ }
+ }
+
+ class ForContainer<E extends AnnotatedElement> extends ForElement<E, MetadataBuilder.ForContainer<E>> {
+
+ ForContainer(Metas<E> meta, MetadataBuilder.ForContainer<E> builder) {
+ super(meta, builder);
+ }
+
+ boolean isCascaded() {
+ return builder.isCascade(meta);
+ }
+
+ Set<GroupConversion> getGroupConversions() {
+ return builder.getGroupConversions(meta);
+ }
+
+ Set<ContainerElementTypeD> getContainerElementTypes(CascadableContainerD<?, ?> parent) {
+ final Map<ContainerElementKey, MetadataBuilder.ForContainer<AnnotatedType>> containerElementTypes =
+ builder.getContainerElementTypes(meta);
+
+ if (containerElementTypes.isEmpty()) {
+ return Collections.emptySet();
+ }
+ final Set<ContainerElementTypeD> result =
+ new TreeSet<>(Comparator.comparing(ContainerElementTypeD::getKey));
+
+ containerElementTypes.forEach((k, builder) -> {
+ result.add(new ContainerElementTypeD(k,
+ new MetadataReader.ForContainer<>(new Metas.ForContainerElement(meta, k), builder), parent));
+ });
+ return Collections.unmodifiableSet(result);
+ }
+ }
+
+ abstract class ForExecutable<E extends Executable, SELF extends ForExecutable<E, SELF>>
+ extends ForElement<E, MetadataBuilder.ForElement<E>> {
+ private final MetadataBuilder.ForExecutable<E> executableBuilder;
+
+ ForExecutable(Metas<E> meta, MetadataBuilder.ForExecutable<E> executableBuilder) {
+ super(meta, EmptyBuilder.instance().forElement());
+ this.executableBuilder = Validate.notNull(executableBuilder, "executableBuilder");
+ }
+
+ <X extends ExecutableD<E, SELF, X>> List<ParameterD<X>> getParameterDescriptors(X parent) {
+ final Parameter[] parameters = meta.getHost().getParameters();
+
+ final List<String> parameterNames =
+ getParameterNames(validatorFactory.getParameterNameProvider(), meta.getHost());
+
+ final List<MetadataBuilder.ForContainer<Parameter>> builders = executableBuilder.getParameters(meta);
+
+ return IntStream.range(0, parameters.length).mapToObj(i -> {
+ final Metas.ForParameter param = new Metas.ForParameter(parameters[i], parameterNames.get(i));
+ return new ParameterD<>(param, i, new MetadataReader.ForContainer<>(param, builders.get(i)), parent);
+ }).collect(ToUnmodifiable.list());
+ }
+
+ <X extends ExecutableD<E, SELF, X>> CrossParameterD<X, E> getCrossParameterDescriptor(X parent) {
+ final Metas.ForCrossParameter<E> cp = new Metas.ForCrossParameter<>(meta);
+ return new CrossParameterD<>(new MetadataReader.ForElement<>(cp, executableBuilder.getCrossParameter(cp)),
+ parent);
+ }
+
+ <X extends ExecutableD<E, SELF, X>> ReturnValueD<X, E> getReturnValueDescriptor(X parent) {
+ return new ReturnValueD<>(new MetadataReader.ForContainer<>(meta, executableBuilder.getReturnValue(meta)),
+ parent);
+ }
+
+ abstract List<String> getParameterNames(ParameterNameProvider parameterNameProvider, E host);
+ }
+
+ class ForMethod extends ForExecutable<Method, ForMethod> {
+ ForMethod(Metas<Method> meta, MetadataBuilder.ForExecutable<Method> builder) {
+ super(meta, builder);
+ }
+
+ @Override
+ List<String> getParameterNames(ParameterNameProvider parameterNameProvider, Method host) {
+ return parameterNameProvider.getParameterNames(host);
+ }
+ }
+
+ class ForConstructor extends ForExecutable<Constructor<?>, ForConstructor> {
+
+ ForConstructor(Metas<Constructor<?>> meta, MetadataBuilder.ForExecutable<Constructor<?>> builder) {
+ super(meta, builder);
+ }
+
+ @Override
+ List<String> getParameterNames(ParameterNameProvider parameterNameProvider, Constructor<?> host) {
+ return parameterNameProvider.getParameterNames(host);
+ }
+ }
+
+ private final ApacheValidatorFactory validatorFactory;
+
+ MetadataReader(ApacheValidatorFactory validatorFactory) {
+ super();
+ this.validatorFactory = Validate.notNull(validatorFactory, "validatorFactory");
+ }
+
+ MetadataReader.ForBean forBean(Class<?> beanClass, MetadataBuilder.ForBean builder) {
+ return new MetadataReader.ForBean(new Metas.ForClass(beanClass), builder);
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/MethodD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/MethodD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/MethodD.java
new file mode 100644
index 0000000..647569d
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/MethodD.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.jsr.descriptor;
+
+import java.lang.reflect.Method;
+
+import javax.validation.metadata.MethodDescriptor;
+import javax.validation.metadata.MethodType;
+
+import org.apache.bval.jsr.util.Methods;
+
+class MethodD extends ExecutableD<Method, MetadataReader.ForMethod, MethodD> implements MethodDescriptor {
+ private final MethodType methodType;
+
+ MethodD(MetadataReader.ForMethod reader, BeanD parent) {
+ super(reader, parent);
+ methodType = Methods.isGetter(reader.meta.getHost()) ? MethodType.GETTER : MethodType.NON_GETTER;
+ }
+
+ @Override
+ public Class<?> getElementClass() {
+ return getTarget().getReturnType();
+ }
+
+ MethodType getMethodType() {
+ return methodType;
+ }
+
+ @Override
+ protected String nameOf(Method e) {
+ return e.getName();
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ParameterD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ParameterD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ParameterD.java
new file mode 100644
index 0000000..951eccb
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ParameterD.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.jsr.descriptor;
+
+import java.lang.reflect.Parameter;
+
+import javax.validation.metadata.ParameterDescriptor;
+
+import org.apache.bval.jsr.metadata.Metas;
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.TypeUtils;
+
+public class ParameterD<P extends ExecutableD<?, ?, P>> extends CascadableContainerD<P, Parameter>
+ implements ParameterDescriptor {
+
+ private final int index;
+ private final String name;
+ private final Class<?> type;
+
+ protected ParameterD(Metas.ForParameter meta, int index, MetadataReader.ForContainer<Parameter> reader, P parent) {
+ super(reader, parent);
+
+ Validate.isTrue(index >= 0 && index < meta.getHost().getDeclaringExecutable().getParameterCount(),
+ "Invalid parameter index %d", index);
+
+ this.index = index;
+
+ name = reader.meta.getName();
+ type = TypeUtils.getRawType(reader.meta.getType(), parent.getElementClass());
+ }
+
+ @Override
+ public Class<?> getElementClass() {
+ return type;
+ }
+
+ @Override
+ public int getIndex() {
+ return index;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/PropertyD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/PropertyD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/PropertyD.java
new file mode 100644
index 0000000..818e7e0
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/PropertyD.java
@@ -0,0 +1,106 @@
+/*
+ * 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.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+import javax.validation.metadata.PropertyDescriptor;
+
+import org.apache.bval.jsr.GraphContext;
+import org.apache.bval.jsr.util.Methods;
+import org.apache.bval.jsr.util.NodeImpl;
+import org.apache.bval.util.reflection.Reflection;
+import org.apache.commons.weaver.privilizer.Privilizing;
+import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
+
+@Privilizing(@CallTo(Reflection.class))
+public abstract class PropertyD<E extends AnnotatedElement> extends CascadableContainerD<BeanD, E>
+ implements PropertyDescriptor {
+
+ static class ForField extends PropertyD<Field> {
+
+ ForField(MetadataReader.ForContainer<Field> reader, BeanD parent) {
+ super(reader, parent);
+ }
+
+ @Override
+ public String getPropertyName() {
+ return host.getName();
+ }
+
+ @Override
+ public Object getValue(Object parent) throws Exception {
+ final boolean mustUnset = Reflection.setAccessible(host, true);
+ try {
+ return host.get(parent);
+ } catch (IllegalAccessException e) {
+ throw new IllegalArgumentException(e);
+ } finally {
+ if (mustUnset) {
+ Reflection.setAccessible(host, false);
+ }
+ }
+ }
+ }
+
+ static class ForMethod extends PropertyD<Method> {
+
+ ForMethod(MetadataReader.ForContainer<Method> reader, BeanD parent) {
+ super(reader, parent);
+ }
+
+ @Override
+ public String getPropertyName() {
+ return Methods.propertyName(host);
+ }
+
+ @Override
+ public Object getValue(Object parent) throws Exception {
+ final boolean mustUnset = Reflection.setAccessible(host, true);
+ try {
+ return host.invoke(parent);
+ } catch (IllegalAccessException | InvocationTargetException e) {
+ throw new IllegalArgumentException(e);
+ } finally {
+ if (mustUnset) {
+ Reflection.setAccessible(host, false);
+ }
+ }
+ }
+ }
+
+ protected final E host;
+
+ protected PropertyD(MetadataReader.ForContainer<E> reader, BeanD parent) {
+ super(reader, parent);
+ this.host = reader.meta.getHost();
+ }
+
+ @Override
+ protected Stream<GraphContext> readImpl(GraphContext context) throws Exception {
+ final Supplier<NodeImpl> propertyNode = () -> new NodeImpl.PropertyNodeImpl(getPropertyName());
+ final Object value = getValue(context.getValue());
+ return Stream.of(context.child(propertyNode.get(), value));
+ }
+
+ public abstract Object getValue(Object parent) throws Exception;
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ReturnValueD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ReturnValueD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ReturnValueD.java
new file mode 100644
index 0000000..a2204fc
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ReturnValueD.java
@@ -0,0 +1,36 @@
+/*
+ * 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.Executable;
+
+import javax.validation.metadata.ReturnValueDescriptor;
+
+public class ReturnValueD<P extends ExecutableD<?, ?, P>, E extends Executable> extends CascadableContainerD<P, E>
+ implements ReturnValueDescriptor {
+
+ ReturnValueD(MetadataReader.ForContainer<E> reader, P parent) {
+ super(reader, parent);
+ }
+
+ @Override
+ public Class<?> getElementClass() {
+ return parent.getElementClass();
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/groups/Group.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/groups/Group.java b/bval-jsr/src/main/java/org/apache/bval/jsr/groups/Group.java
index 4f9d10a..6a211ed 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/groups/Group.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/groups/Group.java
@@ -18,6 +18,8 @@
*/
package org.apache.bval.jsr.groups;
+import java.util.Objects;
+
import javax.validation.groups.Default;
/**
@@ -52,7 +54,7 @@ public final class Group {
*/
@Override
public String toString() {
- return "Group{" + "group=" + group + '}';
+ return String.format("%s{group=%s}", Group.class.getSimpleName(), group);
}
/**
@@ -71,13 +73,10 @@ public final class Group {
if (this == o) {
return true;
}
- if (o == null || getClass() != o.getClass()) {
+ if (o == null || !getClass().equals(o.getClass())) {
return false;
}
-
- Group group1 = (Group) o;
-
- return group != null ? group.equals(group1.group) : group1.group == null;
+ return Objects.equals(group, ((Group) o).group);
}
/**
@@ -85,6 +84,6 @@ public final class Group {
*/
@Override
public int hashCode() {
- return (group != null ? group.hashCode() : 0);
+ return Objects.hashCode(group);
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/groups/GroupConversionDescriptorImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/groups/GroupConversionDescriptorImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/groups/GroupConversionDescriptorImpl.java
index ba3a617..6d45ced 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/groups/GroupConversionDescriptorImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/groups/GroupConversionDescriptorImpl.java
@@ -26,10 +26,9 @@ public class GroupConversionDescriptorImpl implements GroupConversionDescriptor
public GroupConversionDescriptorImpl(final Group from, final Group to) {
this.from = from.getGroup();
- if (this.from.getAnnotation(GroupSequence.class) != null) {
+ if (this.from.isAnnotationPresent(GroupSequence.class)) {
throw new ConstraintDeclarationException("from() can't get a group sequence");
}
-
this.to = to.getGroup();
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/groups/Groups.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/groups/Groups.java b/bval-jsr/src/main/java/org/apache/bval/jsr/groups/Groups.java
index 162bb66..3e7f008 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/groups/Groups.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/groups/Groups.java
@@ -18,25 +18,29 @@
*/
package org.apache.bval.jsr.groups;
-import javax.validation.GroupDefinitionException;
-import java.util.LinkedList;
+import java.util.ArrayList;
import java.util.List;
+import javax.validation.GroupDefinitionException;
+
+import org.apache.bval.util.Exceptions;
+
/**
- * Defines the order to validate groups during validation.
- * with some inspiration from reference implementation
+ * Defines the order to validate groups during validation. with some inspiration
+ * from reference implementation
*
* @author Roman Stumm
*/
public class Groups {
- /** The list of single groups. */
- final List<Group> groups = new LinkedList<Group>();
-
/** The list of sequences. */
- final List<List<Group>> sequences = new LinkedList<List<Group>>();
+ private final List<List<Group>> sequences = new ArrayList<>();
+
+ /** The list of single groups. */
+ final List<Group> groups = new ArrayList<>();
/**
* Get the Groups.
+ *
* @return {@link List} of {@link Group}.
*/
public List<Group> getGroups() {
@@ -45,6 +49,7 @@ public class Groups {
/**
* Get the Group sequences.
+ *
* @return {@link List} of {@link List} of {@link Group}
*/
public List<List<Group>> getSequences() {
@@ -53,7 +58,9 @@ public class Groups {
/**
* Insert a {@link Group}.
- * @param group to insert
+ *
+ * @param group
+ * to insert
*/
void insertGroup(Group group) {
if (!groups.contains(group)) {
@@ -63,52 +70,52 @@ public class Groups {
/**
* Insert a sequence.
- * @param groups {@link List} of {@link Group} to insert
+ *
+ * @param groups
+ * {@link List} of {@link Group} to insert
*/
void insertSequence(List<Group> groups) {
- if (groups == null || groups.isEmpty()) {
- return;
- }
-
- if (!sequences.contains(groups)) {
+ if (!(groups == null || groups.isEmpty() || sequences.contains(groups))) {
sequences.add(groups);
}
}
/**
- * Assert that the default group can be expanded to <code>defaultGroups</code>.
+ * Assert that the default group can be expanded to
+ * <code>defaultGroups</code>.
+ *
* @param defaultGroups
*/
public void assertDefaultGroupSequenceIsExpandable(List<Group> defaultGroups) {
for (List<Group> groupList : sequences) {
- int idx = groupList.indexOf(Group.DEFAULT);
- if (idx != -1) {
+ final int idx = groupList.indexOf(Group.DEFAULT);
+ if (idx >= 0) {
ensureExpandable(groupList, defaultGroups, idx);
}
}
}
private void ensureExpandable(List<Group> groupList, List<Group> defaultGroupList, int defaultGroupIndex) {
- for (int i = 0; i < defaultGroupList.size(); i++) {
- Group group = defaultGroupList.get(i);
+ for (int i = 0, sz = defaultGroupList.size(); i < sz; i++) {
+ final Group group = defaultGroupList.get(i);
if (group.isDefault()) {
continue; // the default group is the one we want to replace
}
- int index = groupList.indexOf(group); // sequence contains group of default group sequence
- if (index == -1) {
- continue; // if group is not in the sequence
+ // sequence contains group of default group sequence
+ final int index = groupList.indexOf(group);
+ if (index < 0) {
+ // group is not in the sequence
+ continue;
}
-
if ((i == 0 && index == defaultGroupIndex - 1)
|| (i == defaultGroupList.size() - 1 && index == defaultGroupIndex + 1)) {
- // if we are at the beginning or end of he defaultGroupSequence and the
- // matches are either directly before or after we can continue,
- // since we basically have two groups
+ // if we are at the beginning or end of he defaultGroupSequence
+ // and the matches are either directly before or after we can
+ // continue, since we basically have two groups
continue;
}
- throw new GroupDefinitionException(
- "Unable to expand default group list" + defaultGroupList + " into sequence " + groupList);
+ Exceptions.raise(GroupDefinitionException::new, "Unable to expand default group list %s into sequence %s",
+ defaultGroupList, groupList);
}
}
-
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/groups/GroupsComputer.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/groups/GroupsComputer.java b/bval-jsr/src/main/java/org/apache/bval/jsr/groups/GroupsComputer.java
index 398d6c3..ae6f629 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/groups/GroupsComputer.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/groups/GroupsComputer.java
@@ -18,126 +18,115 @@
*/
package org.apache.bval.jsr.groups;
-import javax.validation.GroupDefinitionException;
-import javax.validation.GroupSequence;
-import javax.validation.ValidationException;
-import javax.validation.groups.Default;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import javax.validation.GroupDefinitionException;
+import javax.validation.GroupSequence;
+import javax.validation.ValidationException;
+import javax.validation.groups.Default;
+
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.Validate;
+
/**
* Description: compute group order, based on the RI behavior as to guarantee
* compatibility with interpretations of the spec.<br/>
* Implementation is thread-safe.
*/
public class GroupsComputer {
- public static final Class<?>[] DEFAULT_GROUP = new Class<?>[] { Default.class };
+ public static final Class<?>[] DEFAULT_GROUP = { Default.class };
- /** The default group array used in case any of the validate methods is called without a group. */
+ /**
+ * The default group array used in case any of the validate methods is
+ * called without a group.
+ */
private static final Groups DEFAULT_GROUPS;
static {
- DEFAULT_GROUPS = new GroupsComputer().computeGroups(Arrays.asList(DEFAULT_GROUP));
+ DEFAULT_GROUPS = new Groups();
+ for (Class<?> g : DEFAULT_GROUP) {
+ DEFAULT_GROUPS.insertGroup(new Group(g));
+ }
}
/** caching resolved groups in a thread-safe map. */
- private final Map<Class<?>, List<Group>> resolvedSequences = new ConcurrentHashMap<Class<?>, List<Group>>();
+ private final Map<Class<?>, List<Group>> resolvedSequences = new ConcurrentHashMap<>();
/**
* Compute groups from an array of group classes.
+ *
* @param groups
* @return {@link Groups}
*/
- public Groups computeGroups(Class<?>[] groups) {
- if (groups == null) {
- throw new IllegalArgumentException("null passed as group");
- }
-
- // if no groups is specified use the default
- if (groups.length == 0) {
- return DEFAULT_GROUPS;
- }
-
+ @SafeVarargs
+ public final Groups computeGroups(Class<?>... groups) {
+ Exceptions.raiseIf(groups == null, IllegalArgumentException::new, "null validation groups specified");
return computeGroups(Arrays.asList(groups));
}
/**
* Main compute implementation.
+ *
* @param groups
* @return {@link Groups}
*/
protected Groups computeGroups(Collection<Class<?>> groups) {
- if (groups == null || groups.size() == 0) {
- throw new IllegalArgumentException("At least one group has to be specified.");
+ Validate.notNull(groups, "groups");
+
+ if (groups.isEmpty() || Arrays.asList(DEFAULT_GROUP).equals(new ArrayList<>(groups))) {
+ return DEFAULT_GROUPS;
}
+ Exceptions.raiseIf(groups.stream().anyMatch(Objects::isNull), IllegalArgumentException::new,
+ "Null group specified");
for (final Class<?> clazz : groups) {
- if (clazz == null) {
- throw new IllegalArgumentException("At least one group has to be specified.");
- }
-
- if (!clazz.isInterface()) {
- throw new ValidationException("A group has to be an interface. " + clazz.getName() + " is not.");
- }
+ Exceptions.raiseUnless(clazz.isInterface(), ValidationException::new,
+ "A group must be an interface. %s is not.", clazz);
}
-
- Groups chain = new Groups();
+ final Groups chain = new Groups();
for (Class<?> clazz : groups) {
- GroupSequence anno = clazz.getAnnotation(GroupSequence.class);
+ final GroupSequence anno = clazz.getAnnotation(GroupSequence.class);
if (anno == null) {
- Group group = new Group(clazz);
- chain.insertGroup(group);
+ chain.insertGroup(new Group(clazz));
insertInheritedGroups(clazz, chain);
- } else {
- insertSequence(clazz, anno, chain);
+ continue;
}
+ chain.insertSequence(
+ resolvedSequences.computeIfAbsent(clazz, g -> resolveSequence(g, anno, new HashSet<>())));
}
-
return chain;
}
private void insertInheritedGroups(Class<?> clazz, Groups chain) {
for (Class<?> extendedInterface : clazz.getInterfaces()) {
- Group group = new Group(extendedInterface);
- chain.insertGroup(group);
+ chain.insertGroup(new Group(extendedInterface));
insertInheritedGroups(extendedInterface, chain);
}
}
- private void insertSequence(Class<?> clazz, GroupSequence anno, Groups chain) {
- List<Group> sequence;
- if (resolvedSequences.containsKey(clazz)) {
- sequence = resolvedSequences.get(clazz);
- } else {
- sequence = resolveSequence(clazz, anno, new HashSet<Class<?>>());
- }
- chain.insertSequence(sequence);
- }
-
private List<Group> resolveSequence(Class<?> group, GroupSequence sequenceAnnotation,
Set<Class<?>> processedSequences) {
- if (processedSequences.contains(group)) {
- throw new GroupDefinitionException("Cyclic dependency in groups definition");
- } else {
- processedSequences.add(group);
- }
- List<Group> resolvedGroupSequence = new LinkedList<Group>();
- Class<?>[] sequenceArray = sequenceAnnotation.value();
- for (Class<?> clazz : sequenceArray) {
- GroupSequence anno = clazz.getAnnotation(GroupSequence.class);
+ Exceptions.raiseUnless(processedSequences.add(group), GroupDefinitionException::new,
+ "Cyclic dependency in groups definition");
+
+ final List<Group> resolvedGroupSequence = new ArrayList<>();
+ for (Class<?> clazz : sequenceAnnotation.value()) {
+ final GroupSequence anno = clazz.getAnnotation(GroupSequence.class);
if (anno == null) {
- resolvedGroupSequence.add(new Group(clazz)); // group part of sequence
+ // group part of sequence
+ resolvedGroupSequence.add(new Group(clazz));
} else {
- List<Group> tmpSequence = resolveSequence(clazz, anno, processedSequences); // recursion!
- resolvedGroupSequence.addAll(tmpSequence);
+ // recursion!
+ resolvedGroupSequence.addAll(resolveSequence(clazz, anno, processedSequences));
}
}
- resolvedSequences.put(group, resolvedGroupSequence);
return resolvedGroupSequence;
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ConstraintValidatorContextImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ConstraintValidatorContextImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ConstraintValidatorContextImpl.java
new file mode 100644
index 0000000..c3cc3a7
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ConstraintValidatorContextImpl.java
@@ -0,0 +1,195 @@
+/*
+ * 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.job;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.validation.ClockProvider;
+import javax.validation.ConstraintValidatorContext;
+import javax.validation.ConstraintViolation;
+import javax.validation.MessageInterpolator;
+import javax.validation.Path;
+import javax.validation.ValidationException;
+import javax.validation.metadata.ConstraintDescriptor;
+import javax.validation.metadata.CrossParameterDescriptor;
+
+import org.apache.bval.jsr.descriptor.ComposedD;
+import org.apache.bval.jsr.descriptor.ConstraintD;
+import org.apache.bval.jsr.descriptor.CrossParameterD;
+import org.apache.bval.jsr.util.ContainerElementNodeBuilderCustomizableContextImpl;
+import org.apache.bval.jsr.util.LeafNodeBuilderCustomizableContextImpl;
+import org.apache.bval.jsr.util.NodeBuilderCustomizableContextImpl;
+import org.apache.bval.jsr.util.NodeBuilderDefinedContextImpl;
+import org.apache.bval.jsr.util.NodeImpl;
+import org.apache.bval.jsr.util.PathImpl;
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.Lazy;
+import org.apache.bval.util.Validate;
+
+public class ConstraintValidatorContextImpl<T> implements ConstraintValidatorContext, MessageInterpolator.Context {
+ private class ConstraintViolationBuilderImpl implements ConstraintValidatorContext.ConstraintViolationBuilder {
+ private final String template;
+ private final PathImpl path;
+
+ ConstraintViolationBuilderImpl(String template, PathImpl path) {
+ this.template = template;
+ this.path = path;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public NodeBuilderDefinedContext addNode(String name) {
+ PathImpl p;
+ if (path.isRootPath()) {
+ p = PathImpl.create();
+ p.getLeafNode().setName(name);
+ } else {
+ p = PathImpl.copy(path);
+ p.addNode(new NodeImpl(name));
+ }
+ return new NodeBuilderDefinedContextImpl(ConstraintValidatorContextImpl.this, template, p);
+ }
+
+ @Override
+ public NodeBuilderCustomizableContext addPropertyNode(String name) {
+ return new NodeBuilderCustomizableContextImpl(ConstraintValidatorContextImpl.this, template, path, name);
+ }
+
+ @Override
+ public LeafNodeBuilderCustomizableContext addBeanNode() {
+ return new LeafNodeBuilderCustomizableContextImpl(ConstraintValidatorContextImpl.this, template, path);
+ }
+
+ @Override
+ public NodeBuilderDefinedContext addParameterNode(int index) {
+ Exceptions.raiseUnless(frame.descriptor instanceof CrossParameterDescriptor, ValidationException::new,
+ "Cannot add parameter node for %s", frame.descriptor.getClass().getName());
+
+ final CrossParameterD<?, ?> crossParameter =
+ ComposedD.unwrap(frame.descriptor, CrossParameterD.class).findFirst().get();
+
+ final String parameterName = crossParameter.getParent().getParameterDescriptors().get(index).getName();
+
+ final NodeImpl node = new NodeImpl.ParameterNodeImpl(parameterName, index);
+ if (!path.isRootPath()) {
+ path.removeLeafNode();
+ }
+ path.addNode(node);
+ return new NodeBuilderDefinedContextImpl(ConstraintValidatorContextImpl.this, template, path);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ConstraintValidatorContext addConstraintViolation() {
+ addError(template, path);
+ return ConstraintValidatorContextImpl.this;
+ }
+
+ @Override
+ public ContainerElementNodeBuilderCustomizableContext addContainerElementNode(String name,
+ Class<?> containerType, Integer typeArgumentIndex) {
+ return new ContainerElementNodeBuilderCustomizableContextImpl(ConstraintValidatorContextImpl.this, template,
+ path, name, containerType, typeArgumentIndex);
+ }
+ }
+
+ private final ValidationJob<T>.Frame<?> frame;
+ private final ConstraintD<?> constraint;
+ private final Lazy<Set<ConstraintViolation<T>>> violations = new Lazy<>(HashSet::new);
+ private boolean defaultConstraintViolationDisabled;
+
+ /**
+ * Temporary for code migration
+ */
+ // TODO delete
+ @Deprecated
+ protected ConstraintValidatorContextImpl() {
+ this.frame = null;
+ this.constraint = null;
+ }
+
+ ConstraintValidatorContextImpl(ValidationJob<T>.Frame<?> frame, ConstraintD<?> constraint) {
+ super();
+ this.frame = Validate.notNull(frame, "frame");
+ this.constraint = Validate.notNull(constraint, "constraint");
+ }
+
+ @Override
+ public void disableDefaultConstraintViolation() {
+ this.defaultConstraintViolationDisabled = true;
+ }
+
+ @Override
+ public String getDefaultConstraintMessageTemplate() {
+ return constraint.getMessageTemplate();
+ }
+
+ @Override
+ public ConstraintViolationBuilder buildConstraintViolationWithTemplate(String messageTemplate) {
+ return new ConstraintViolationBuilderImpl(messageTemplate, frame.context.getPath());
+ }
+
+ @Override
+ public ClockProvider getClockProvider() {
+ return frame.getJob().validatorContext.getClockProvider();
+ }
+
+ @Override
+ public <U> U unwrap(Class<U> type) {
+ try {
+ return type.cast(this);
+ } catch (ClassCastException e) {
+ throw new ValidationException(e);
+ }
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public void addError(String messageTemplate, Path propertyPath) {
+ violations.get().add(((ValidationJob) frame.getJob()).createViolation(messageTemplate, this, propertyPath));
+ }
+
+ ValidationJob<T>.Frame<?> getFrame() {
+ return frame;
+ }
+
+ Set<ConstraintViolation<T>> getRequiredViolations() {
+ if (!violations.optional().isPresent()) {
+ Exceptions.raiseIf(defaultConstraintViolationDisabled, ValidationException::new,
+ "Expected custom constraint violation(s)");
+
+ addError(getDefaultConstraintMessageTemplate(), frame.context.getPath());
+ }
+ return violations.get();
+ }
+
+ @Override
+ public ConstraintDescriptor<?> getConstraintDescriptor() {
+ return constraint;
+ }
+
+ @Override
+ public Object getValidatedValue() {
+ return frame.context.getValue();
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateBean.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateBean.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateBean.java
new file mode 100644
index 0000000..dc3fab5
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateBean.java
@@ -0,0 +1,60 @@
+/*
+ * 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.job;
+
+import javax.validation.Path;
+
+import org.apache.bval.jsr.ApacheFactoryContext;
+import org.apache.bval.jsr.ConstraintViolationImpl;
+import org.apache.bval.jsr.GraphContext;
+import org.apache.bval.jsr.descriptor.BeanD;
+import org.apache.bval.jsr.descriptor.ConstraintD;
+import org.apache.bval.jsr.util.PathImpl;
+import org.apache.bval.util.Validate;
+
+public final class ValidateBean<T> extends ValidationJob<T> {
+
+ private final T bean;
+
+ ValidateBean(ApacheFactoryContext validatorContext, T bean, Class<?>[] groups) {
+ super(validatorContext, groups);
+ this.bean = Validate.notNull(bean, IllegalArgumentException::new, "bean");
+ }
+
+ @Override
+ protected Frame<BeanD> computeBaseFrame() {
+ return new BeanFrame(new GraphContext(validatorContext, PathImpl.create(), bean));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected Class<T> getRootBeanClass() {
+ return (Class<T>) bean.getClass();
+ }
+
+ @Override
+ ConstraintViolationImpl<T> createViolation(String messageTemplate, ConstraintValidatorContextImpl<T> context,
+ Path propertyPath) {
+ final String message = validatorContext.getMessageInterpolator().interpolate(messageTemplate, context);
+
+ return new ConstraintViolationImpl<>(messageTemplate, message, bean, context.getFrame().getBean(), propertyPath,
+ context.getFrame().context.getValue(), context.getConstraintDescriptor(), getRootBeanClass(),
+ context.getConstraintDescriptor().unwrap(ConstraintD.class).getDeclaredOn(), null, null);
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateParameters.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateParameters.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateParameters.java
new file mode 100644
index 0000000..c0d866b
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateParameters.java
@@ -0,0 +1,188 @@
+/*
+ * 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.job;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.stream.IntStream;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.ParameterNameProvider;
+import javax.validation.Path;
+import javax.validation.metadata.ExecutableDescriptor;
+
+import org.apache.bval.jsr.ApacheFactoryContext;
+import org.apache.bval.jsr.ConstraintViolationImpl;
+import org.apache.bval.jsr.GraphContext;
+import org.apache.bval.jsr.descriptor.ConstraintD;
+import org.apache.bval.jsr.descriptor.CrossParameterD;
+import org.apache.bval.jsr.descriptor.ParameterD;
+import org.apache.bval.jsr.util.NodeImpl;
+import org.apache.bval.jsr.util.PathImpl;
+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 abstract class ValidateParameters<E extends Executable, T> extends ValidationJob<T> {
+
+ public static class ForMethod<T> extends ValidateParameters<Method, T> {
+
+ private final T object;
+
+ ForMethod(ApacheFactoryContext validatorContext, T object, Method executable, Object[] parameterValues,
+ Class<?>[] groups) {
+ super(validatorContext, object, executable, parameterValues, groups);
+ this.object = Validate.notNull(object, IllegalArgumentException::new, "object");
+ }
+
+ @Override
+ protected ExecutableDescriptor describe() {
+ return validatorContext.getDescriptorManager().getBeanDescriptor(object.getClass())
+ .getConstraintsForMethod(executable.getName(), executable.getParameterTypes());
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected Class<T> getRootBeanClass() {
+ return (Class<T>) object.getClass();
+ }
+
+ @Override
+ protected List<String> getParameterNames(ParameterNameProvider parameterNameProvider) {
+ return parameterNameProvider.getParameterNames(executable);
+ }
+
+ @Override
+ protected T getRootBean() {
+ return object;
+ }
+ }
+
+ public static class ForConstructor<T> extends ValidateParameters<Constructor<? extends T>, T> {
+
+ ForConstructor(ApacheFactoryContext validatorContext, Constructor<? extends T> executable,
+ Object[] parameterValues, Class<?>[] groups) {
+ super(validatorContext, null, executable, parameterValues, groups);
+ }
+
+ @Override
+ protected ExecutableDescriptor describe() {
+ return validatorContext.getDescriptorManager().getBeanDescriptor(executable.getDeclaringClass())
+ .getConstraintsForConstructor(executable.getParameterTypes());
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected Class<T> getRootBeanClass() {
+ return (Class<T>) executable.getDeclaringClass();
+ }
+
+ @Override
+ protected List<String> getParameterNames(ParameterNameProvider parameterNameProvider) {
+ return parameterNameProvider.getParameterNames(executable);
+ }
+
+ @Override
+ protected T getRootBean() {
+ return null;
+ }
+ }
+
+ class ParametersFrame extends Frame<CrossParameterD<?, ?>> {
+ private final ExecutableDescriptor executableDescriptor;
+
+ protected ParametersFrame(ExecutableDescriptor executableDescriptor, GraphContext context) {
+ super(null, (CrossParameterD<?, ?>) Validate.notNull(executableDescriptor, "executableDescriptor")
+ .getCrossParameterDescriptor(), context);
+ this.executableDescriptor = executableDescriptor;
+ }
+
+ @Override
+ void recurse(Class<?> group, Consumer<ConstraintViolation<T>> sink) {
+ executableDescriptor.getParameterDescriptors().stream()
+ .map(pd -> new SproutFrame<ParameterD<?>>(this, (ParameterD<?>) pd, parameter(pd.getIndex())))
+ .forEach(f -> f.process(group, sink));
+ }
+
+ @Override
+ Object getBean() {
+ return object;
+ }
+ }
+
+ private static final String PARAMETERS_DO_NOT_MATCH = "Parameters do not match";
+
+ protected final T object;
+ protected final E executable;
+ protected final Lazy<List<String>> parameterNames =
+ new Lazy<>(() -> getParameterNames(validatorContext.getParameterNameProvider()));
+
+ private final Object[] parameterValues;
+
+ ValidateParameters(ApacheFactoryContext validatorContext, T object, E executable, Object[] parameterValues,
+ Class<?>[] groups) {
+ super(validatorContext, groups);
+ this.object = object;
+ this.executable = Validate.notNull(executable, IllegalArgumentException::new, "executable");
+ this.parameterValues =
+ Validate.notNull(parameterValues, IllegalArgumentException::new, "parameterValues").clone();
+
+ final Type[] genericParameterTypes = executable.getGenericParameterTypes();
+ Exceptions.raiseUnless(parameterValues.length == genericParameterTypes.length, IllegalArgumentException::new,
+ PARAMETERS_DO_NOT_MATCH);
+ IntStream.range(0, genericParameterTypes.length)
+ .forEach(n -> Exceptions.raiseUnless(TypeUtils.isInstance(parameterValues[n], genericParameterTypes[n]),
+ IllegalArgumentException::new, PARAMETERS_DO_NOT_MATCH));
+ }
+
+ @Override
+ protected Frame<?> computeBaseFrame() {
+ final PathImpl cp = PathImpl.create();
+ cp.addNode(new NodeImpl.CrossParameterNodeImpl());
+ return new ParametersFrame(describe(), new GraphContext(validatorContext, cp, parameterValues));
+ }
+
+ protected abstract ExecutableDescriptor describe();
+
+ protected abstract List<String> getParameterNames(ParameterNameProvider parameterNameProvider);
+
+ protected abstract T getRootBean();
+
+ @Override
+ ConstraintViolationImpl<T> createViolation(String messageTemplate, ConstraintValidatorContextImpl<T> context,
+ Path propertyPath) {
+
+ final String message = validatorContext.getMessageInterpolator().interpolate(messageTemplate, context);
+
+ return new ConstraintViolationImpl<T>(messageTemplate, message, getRootBean(), context.getFrame().getBean(),
+ propertyPath, context.getFrame().context.getValue(), context.getConstraintDescriptor(), getRootBeanClass(),
+ context.getConstraintDescriptor().unwrap(ConstraintD.class).getDeclaredOn(), null, parameterValues);
+ }
+
+ private GraphContext parameter(int i) {
+ final PathImpl path = PathImpl.create();
+ path.addNode(new NodeImpl.ParameterNodeImpl(parameterNames.get().get(i), i));
+ return new GraphContext(validatorContext, path, parameterValues[i]);
+ }
+}
[08/11] bval git commit: implement BV 2.0 against existing BVal unit
tests
Posted by mb...@apache.org.
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;
+ }
+}
[05/11] bval git commit: implement BV 2.0 against existing BVal unit
tests
Posted by mb...@apache.org.
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/DualBuilder.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/DualBuilder.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/DualBuilder.java
new file mode 100644
index 0000000..269d953
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/DualBuilder.java
@@ -0,0 +1,243 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bval.jsr.metadata;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.AnnotatedType;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import org.apache.bval.jsr.descriptor.GroupConversion;
+import org.apache.bval.jsr.util.ToUnmodifiable;
+import org.apache.bval.util.Validate;
+
+/**
+ * Maintains two metadata builds in parallel. The "primary" build is assumed to be the reflection/annotation-based build
+ * and is subject to the {@link AnnotationBehavior} prescribed by the "custom" build.
+ */
+public class DualBuilder {
+
+ private static class Delegator<DELEGATE extends HasAnnotationBehavior> implements HasAnnotationBehavior {
+
+ private final Delegator<?> parent;
+ protected final DELEGATE primaryDelegate;
+ protected final DELEGATE customDelegate;
+
+ Delegator(Delegator<?> parent, DELEGATE primaryDelegate, DELEGATE customDelegate) {
+ this.parent = parent;
+ this.primaryDelegate = Validate.notNull(primaryDelegate, "primaryDelegate");
+ this.customDelegate = Validate.notNull(customDelegate, "customDelegate");
+ }
+
+ AnnotationBehavior getCustomAnnotationBehavior() {
+ final AnnotationBehavior annotationBehavior = customDelegate.getAnnotationBehavior();
+ Validate.validState(annotationBehavior != null, "null %s returned from %s",
+ AnnotationBehavior.class.getSimpleName(), customDelegate);
+ if (annotationBehavior == AnnotationBehavior.ABSTAIN && parent != null) {
+ return parent.getCustomAnnotationBehavior();
+ }
+ return annotationBehavior;
+ }
+
+ protected Stream<DELEGATE> activeDelegates() {
+ return getCustomAnnotationBehavior() == AnnotationBehavior.EXCLUDE ? Stream.of(customDelegate)
+ : Stream.of(primaryDelegate, customDelegate);
+ }
+
+ <K, D> Map<K, D> merge(Function<DELEGATE, Map<K, D>> toMap, BiFunction<D, D, D> parallel,
+ Supplier<D> emptyBuilder) {
+
+ final Map<K, D> primaries = toMap.apply(primaryDelegate);
+ final Map<K, D> customs = toMap.apply(customDelegate);
+
+ if (primaries.isEmpty() && customs.isEmpty()) {
+ return Collections.emptyMap();
+ }
+
+ final Function<? super K, ? extends D> valueMapper = k -> {
+ final D primary = primaries.get(k);
+ final D custom = customs.get(k);
+
+ if (custom == null) {
+ if (primary != null) {
+ switch (getCustomAnnotationBehavior()) {
+ case INCLUDE:
+ case ABSTAIN:
+ return primary;
+ default:
+ break;
+ }
+ }
+ return emptyBuilder.get();
+ }
+ return parallel.apply(primary, custom);
+ };
+ return Stream.of(primaries, customs).map(Map::keySet).flatMap(Collection::stream).distinct()
+ .collect(Collectors.toMap(Function.identity(), valueMapper));
+ }
+ }
+
+ private static class ForBean extends DualBuilder.Delegator<MetadataBuilder.ForBean>
+ implements MetadataBuilder.ForBean {
+
+ ForBean(MetadataBuilder.ForBean primaryDelegate, MetadataBuilder.ForBean customDelegate) {
+ super(null, primaryDelegate, customDelegate);
+ }
+
+ @Override
+ public MetadataBuilder.ForClass getClass(Metas<Class<?>> meta) {
+ return new DualBuilder.ForClass(this, primaryDelegate.getClass(meta), customDelegate.getClass(meta));
+ }
+
+ @Override
+ public Map<String, MetadataBuilder.ForContainer<Field>> getFields(Metas<Class<?>> meta) {
+ return merge(b -> b.getFields(meta), (t, u) -> new DualBuilder.ForContainer<>(this, t, u),
+ EmptyBuilder.instance()::forContainer);
+ }
+
+ @Override
+ public Map<String, MetadataBuilder.ForContainer<Method>> getGetters(Metas<Class<?>> meta) {
+ return merge(b -> b.getGetters(meta), (t, u) -> new DualBuilder.ForContainer<>(this, t, u),
+ EmptyBuilder.instance()::forContainer);
+ }
+
+ @Override
+ public Map<Signature, MetadataBuilder.ForExecutable<Constructor<?>>> getConstructors(Metas<Class<?>> meta) {
+ return merge(b -> b.getConstructors(meta), (t, u) -> new DualBuilder.ForExecutable<>(this, t, u),
+ EmptyBuilder.instance()::forExecutable);
+ }
+
+ @Override
+ public Map<Signature, MetadataBuilder.ForExecutable<Method>> getMethods(Metas<Class<?>> meta) {
+ return merge(b -> b.getMethods(meta), (t, u) -> new DualBuilder.ForExecutable<>(this, t, u),
+ EmptyBuilder.instance()::forExecutable);
+ }
+ }
+
+ private static class ForElement<DELEGATE extends MetadataBuilder.ForElement<E>, E extends AnnotatedElement>
+ extends Delegator<DELEGATE> implements MetadataBuilder.ForElement<E> {
+
+ ForElement(Delegator<?> parent, DELEGATE primaryDelegate, DELEGATE customDelegate) {
+ super(parent, primaryDelegate, customDelegate);
+ }
+
+ @Override
+ public final Annotation[] getDeclaredConstraints(Metas<E> meta) {
+ return activeDelegates().map(d -> d.getDeclaredConstraints(meta)).flatMap(Stream::of)
+ .toArray(Annotation[]::new);
+ }
+ }
+
+ private static class ForClass extends ForElement<MetadataBuilder.ForClass, Class<?>>
+ implements MetadataBuilder.ForClass {
+
+ ForClass(Delegator<?> parent, MetadataBuilder.ForClass primaryDelegate,
+ MetadataBuilder.ForClass customDelegate) {
+ super(parent, primaryDelegate, customDelegate);
+ }
+
+ @Override
+ public List<Class<?>> getGroupSequence(Metas<Class<?>> meta) {
+ final List<Class<?>> customGroupSequence = customDelegate.getGroupSequence(meta);
+ if (customGroupSequence != null) {
+ return customGroupSequence;
+ }
+ return customDelegate.getAnnotationBehavior() == AnnotationBehavior.EXCLUDE ? null
+ : primaryDelegate.getGroupSequence(meta);
+ }
+ }
+
+ private static class ForContainer<DELEGATE extends MetadataBuilder.ForContainer<E>, E extends AnnotatedElement>
+ extends DualBuilder.ForElement<DELEGATE, E> implements MetadataBuilder.ForContainer<E> {
+
+ ForContainer(Delegator<?> parent, DELEGATE primaryDelegate, DELEGATE customDelegate) {
+ super(parent, primaryDelegate, customDelegate);
+ }
+
+ @Override
+ public final boolean isCascade(Metas<E> meta) {
+ return activeDelegates().anyMatch(d -> d.isCascade(meta));
+ }
+
+ @Override
+ public final Set<GroupConversion> getGroupConversions(Metas<E> meta) {
+ return activeDelegates().map(d -> d.getGroupConversions(meta)).flatMap(Collection::stream)
+ .collect(ToUnmodifiable.set());
+ }
+
+ @Override
+ public final Map<ContainerElementKey, MetadataBuilder.ForContainer<AnnotatedType>> getContainerElementTypes(
+ Metas<E> meta) {
+ return merge(b -> b.getContainerElementTypes(meta), (t, u) -> new DualBuilder.ForContainer<>(this, t, u),
+ EmptyBuilder.instance()::forContainer);
+ }
+ }
+
+ private static class ForExecutable<DELEGATE extends MetadataBuilder.ForExecutable<E>, E extends Executable>
+ extends Delegator<DELEGATE> implements MetadataBuilder.ForExecutable<E> {
+
+ ForExecutable(Delegator<?> parent, DELEGATE primaryDelegate, DELEGATE customDelegate) {
+ super(parent, primaryDelegate, customDelegate);
+ }
+
+ @Override
+ public MetadataBuilder.ForContainer<E> getReturnValue(Metas<E> meta) {
+ return new DualBuilder.ForContainer<>(this, primaryDelegate.getReturnValue(meta),
+ customDelegate.getReturnValue(meta));
+ }
+
+ @Override
+ public List<MetadataBuilder.ForContainer<Parameter>> getParameters(Metas<E> meta) {
+
+ final List<MetadataBuilder.ForContainer<Parameter>> primaries = primaryDelegate.getParameters(meta);
+ final List<MetadataBuilder.ForContainer<Parameter>> customs = customDelegate.getParameters(meta);
+
+ Validate.validState(primaries.size() == customs.size(), "Mismatched parameter counts: %d vs. %d",
+ primaries.size(), customs.size());
+
+ return IntStream.range(0, primaries.size())
+ .mapToObj(n -> new DualBuilder.ForContainer<>(this, primaries.get(n), customs.get(n)))
+ .collect(ToUnmodifiable.list());
+ }
+
+ @Override
+ public MetadataBuilder.ForElement<E> getCrossParameter(Metas<E> meta) {
+ return new DualBuilder.ForElement<MetadataBuilder.ForElement<E>, E>(this,
+ primaryDelegate.getCrossParameter(meta), customDelegate.getCrossParameter(meta));
+ }
+ }
+
+ public static MetadataBuilder.ForBean forBean(MetadataBuilder.ForBean primaryDelegate,
+ MetadataBuilder.ForBean customDelegate) {
+ return new DualBuilder.ForBean(primaryDelegate, customDelegate);
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/DualValidationMappingProvider.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/DualValidationMappingProvider.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/DualValidationMappingProvider.java
new file mode 100644
index 0000000..e5b5038
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/DualValidationMappingProvider.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.jsr.metadata;
+
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+
+import org.apache.bval.util.Validate;
+
+public class DualValidationMappingProvider extends ValidatorMappingProvider {
+ private final ValidatorMappingProvider primaryDelegate;
+ private final ValidatorMappingProvider secondaryDelegate;
+
+ public DualValidationMappingProvider(ValidatorMappingProvider primary, ValidatorMappingProvider secondary) {
+ super();
+ this.primaryDelegate = Validate.notNull(primary, "primary delegate");
+ this.secondaryDelegate = Validate.notNull(secondary, "secondary delegate");
+ }
+
+ @Override
+ protected <A extends Annotation> ValidatorMapping<A> doGetValidatorMapping(Class<A> constraintType) {
+
+ final ValidatorMapping<A> secondaryMapping = secondaryDelegate.doGetValidatorMapping(constraintType);
+ if (secondaryMapping == null) {
+ return primaryDelegate.doGetValidatorMapping(constraintType);
+ }
+ final AnnotationBehavior annotationBehavior = secondaryMapping.getAnnotationBehavior();
+
+ if (annotationBehavior == AnnotationBehavior.EXCLUDE) {
+ return secondaryMapping;
+ }
+ return ValidatorMapping.merge(
+ Arrays.asList(primaryDelegate.doGetValidatorMapping(constraintType), secondaryMapping),
+ AnnotationBehaviorMergeStrategy.consensus());
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/EmptyBuilder.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/EmptyBuilder.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/EmptyBuilder.java
new file mode 100644
index 0000000..c95f6d7
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/EmptyBuilder.java
@@ -0,0 +1,183 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bval.jsr.metadata;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.AnnotatedType;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.bval.jsr.descriptor.GroupConversion;
+import org.apache.bval.util.Lazy;
+import org.apache.bval.util.ObjectUtils;
+import org.apache.bval.util.Validate;
+
+public class EmptyBuilder {
+ private static final Map<AnnotationBehavior, EmptyBuilder> INSTANCES = new EnumMap<>(AnnotationBehavior.class);
+
+ public static EmptyBuilder instance() {
+ return instance(AnnotationBehavior.ABSTAIN);
+ }
+
+ public static EmptyBuilder instance(AnnotationBehavior annotationBehavior) {
+ return INSTANCES.computeIfAbsent(annotationBehavior, EmptyBuilder::new);
+ }
+
+ private class Level implements HasAnnotationBehavior {
+
+ @Override
+ public final AnnotationBehavior getAnnotationBehavior() {
+ return annotationBehavior;
+ }
+ }
+
+ private class ForBean extends Level implements MetadataBuilder.ForBean {
+ private final Lazy<EmptyBuilder.ForClass> forClass = new Lazy<>(EmptyBuilder.ForClass::new);
+
+ @Override
+ public MetadataBuilder.ForClass getClass(Metas<Class<?>> meta) {
+ return forClass.get();
+ }
+
+ @Override
+ public Map<String, MetadataBuilder.ForContainer<Field>> getFields(Metas<Class<?>> meta) {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public Map<String, MetadataBuilder.ForContainer<Method>> getGetters(Metas<Class<?>> meta) {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public Map<Signature, MetadataBuilder.ForExecutable<Constructor<?>>> getConstructors(Metas<Class<?>> meta) {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public Map<Signature, MetadataBuilder.ForExecutable<Method>> getMethods(Metas<Class<?>> meta) {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return true;
+ }
+ }
+
+ private class ForElement<E extends AnnotatedElement> extends Level implements MetadataBuilder.ForElement<E> {
+
+ @Override
+ public final Annotation[] getDeclaredConstraints(Metas<E> meta) {
+ return ObjectUtils.EMPTY_ANNOTATION_ARRAY;
+ }
+ }
+
+ private class ForClass extends ForElement<Class<?>> implements MetadataBuilder.ForClass {
+
+ @Override
+ public List<Class<?>> getGroupSequence(Metas<Class<?>> meta) {
+ return null;
+ }
+ }
+
+ private class ForContainer<E extends AnnotatedElement> extends ForElement<E>
+ implements MetadataBuilder.ForContainer<E> {
+
+ @Override
+ public boolean isCascade(Metas<E> meta) {
+ return false;
+ }
+
+ @Override
+ public Set<GroupConversion> getGroupConversions(Metas<E> meta) {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Map<ContainerElementKey, MetadataBuilder.ForContainer<AnnotatedType>> getContainerElementTypes(
+ Metas<E> meta) {
+ return Collections.emptyMap();
+ }
+ }
+
+ private class ForExecutable<E extends Executable> extends Level implements MetadataBuilder.ForExecutable<E> {
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public MetadataBuilder.ForElement<E> getCrossParameter(Metas<E> meta) {
+ return forElement.get();
+ }
+
+ @Override
+ public List<MetadataBuilder.ForContainer<Parameter>> getParameters(Metas<E> meta) {
+ return Collections.emptyList();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public MetadataBuilder.ForContainer<E> getReturnValue(Metas<E> meta) {
+ return forContainer.get();
+ }
+ }
+
+ private final AnnotationBehavior annotationBehavior;
+ private final Lazy<EmptyBuilder.ForBean> forBean;
+ @SuppressWarnings("rawtypes")
+ private final Lazy<EmptyBuilder.ForContainer> forContainer;
+ @SuppressWarnings("rawtypes")
+ private final Lazy<EmptyBuilder.ForExecutable> forExecutable;
+ @SuppressWarnings("rawtypes")
+ private final Lazy<EmptyBuilder.ForElement> forElement;
+
+ private EmptyBuilder(AnnotationBehavior annotationBehavior) {
+ super();
+ this.annotationBehavior = Validate.notNull(annotationBehavior, "annotationBehavior");
+ forBean = new Lazy<>(EmptyBuilder.ForBean::new);
+ forContainer = new Lazy<>(EmptyBuilder.ForContainer::new);
+ forExecutable = new Lazy<>(EmptyBuilder.ForExecutable::new);
+ forElement = new Lazy<>(EmptyBuilder.ForElement::new);
+ }
+
+ public MetadataBuilder.ForBean forBean() {
+ return forBean.get();
+ }
+
+ @SuppressWarnings("unchecked")
+ public <E extends AnnotatedElement> MetadataBuilder.ForContainer<E> forContainer() {
+ return forContainer.get();
+ }
+
+ @SuppressWarnings("unchecked")
+ public <E extends Executable> MetadataBuilder.ForExecutable<E> forExecutable() {
+ return forExecutable.get();
+ }
+
+ @SuppressWarnings("unchecked")
+ public <E extends AnnotatedElement> MetadataBuilder.ForElement<E> forElement() {
+ return forElement.get();
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HasAnnotationBehavior.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HasAnnotationBehavior.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HasAnnotationBehavior.java
new file mode 100644
index 0000000..2060954
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HasAnnotationBehavior.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bval.jsr.metadata;
+
+public interface HasAnnotationBehavior {
+
+ default AnnotationBehavior getAnnotationBehavior() {
+ return AnnotationBehavior.ABSTAIN;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HierarchyBuilder.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HierarchyBuilder.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HierarchyBuilder.java
new file mode 100644
index 0000000..35276ea
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/HierarchyBuilder.java
@@ -0,0 +1,235 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bval.jsr.metadata;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.AnnotatedType;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import javax.validation.metadata.Scope;
+
+import org.apache.bval.jsr.descriptor.GroupConversion;
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.Reflection;
+import org.apache.bval.util.reflection.Reflection.Interfaces;
+import org.apache.commons.weaver.privilizer.Privilizing;
+import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
+
+@Privilizing(@CallTo(Reflection.class))
+public class HierarchyBuilder extends CompositeBuilder {
+ private static abstract class HierarchyDelegate<T> {
+ final T delegate;
+
+ HierarchyDelegate(T delegate) {
+ super();
+ this.delegate = Validate.notNull(delegate, "delegate");
+ }
+
+ static class ForBean extends HierarchyDelegate<MetadataBuilder.ForBean> implements MetadataBuilder.ForBean {
+ final Metas<Class<?>> hierarchyType;
+
+ ForBean(MetadataBuilder.ForBean delegate, Class<?> hierarchyType) {
+ super(delegate);
+ this.hierarchyType = new Metas.ForClass(hierarchyType);
+ }
+
+ @Override
+ public MetadataBuilder.ForClass getClass(Metas<Class<?>> meta) {
+ return new HierarchyDelegate.ForClass(delegate.getClass(hierarchyType), hierarchyType);
+ }
+
+ @Override
+ public Map<String, MetadataBuilder.ForContainer<Field>> getFields(Metas<Class<?>> meta) {
+ return delegate.getFields(hierarchyType);
+ }
+
+ @Override
+ public Map<String, MetadataBuilder.ForContainer<Method>> getGetters(Metas<Class<?>> meta) {
+ return delegate.getGetters(hierarchyType);
+ }
+
+ @Override
+ public Map<Signature, MetadataBuilder.ForExecutable<Constructor<?>>> getConstructors(Metas<Class<?>> meta) {
+ return delegate.getConstructors(hierarchyType);
+ }
+
+ @Override
+ public Map<Signature, MetadataBuilder.ForExecutable<Method>> getMethods(Metas<Class<?>> meta) {
+ final Map<Signature, MetadataBuilder.ForExecutable<Method>> m = delegate.getMethods(hierarchyType);
+
+ return m;
+ }
+ }
+
+ static class ForClass extends HierarchyDelegate<MetadataBuilder.ForClass> implements MetadataBuilder.ForClass {
+
+ final Metas<Class<?>> hierarchyType;
+
+ ForClass(MetadataBuilder.ForClass delegate, Metas<Class<?>> hierarchyType) {
+ super(delegate);
+ this.hierarchyType = hierarchyType;
+ }
+
+ @Override
+ public Annotation[] getDeclaredConstraints(Metas<Class<?>> meta) {
+ return delegate.getDeclaredConstraints(hierarchyType);
+ }
+
+ @Override
+ public List<Class<?>> getGroupSequence(Metas<Class<?>> meta) {
+ return delegate.getGroupSequence(hierarchyType);
+ }
+ }
+
+ static class ForGetter extends HierarchyDelegate<MetadataBuilder.ForContainer<Method>>
+ implements MetadataBuilder.ForContainer<Method> {
+ final Metas.ForMethod meta;
+
+ ForGetter(MetadataBuilder.ForContainer<Method> delegate,
+ org.apache.bval.jsr.metadata.Metas.ForMethod meta) {
+ super(delegate);
+ this.meta = Validate.notNull(meta, "meta");
+ }
+
+ @Override
+ public Annotation[] getDeclaredConstraints(Metas<Method> meta) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean isCascade(Metas<Method> meta) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public Set<GroupConversion> getGroupConversions(Metas<Method> meta) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Map<ContainerElementKey, org.apache.bval.jsr.metadata.MetadataBuilder.ForContainer<AnnotatedType>> getContainerElementTypes(
+ Metas<Method> meta) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+ }
+
+ static class ForMethod extends HierarchyDelegate<MetadataBuilder.ForExecutable<Method>>
+ implements MetadataBuilder.ForExecutable<Method> {
+ final Metas.ForMethod meta;
+
+ public ForMethod(MetadataBuilder.ForExecutable<Method> delegate, Metas.ForMethod meta) {
+ super(delegate);
+ this.meta = Validate.notNull(meta, "meta");
+ }
+
+ @Override
+ public MetadataBuilder.ForContainer<Method> getReturnValue(Metas<Method> meta) {
+
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public MetadataBuilder.ForElement<Method> getCrossParameter(Metas<Method> meta) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public List<MetadataBuilder.ForContainer<Parameter>> getParameters(Metas<Method> meta) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+ }
+ }
+
+ private final Function<Class<?>, MetadataBuilder.ForBean> getBeanBuilder;
+
+ public HierarchyBuilder(Function<Class<?>, MetadataBuilder.ForBean> getBeanBuilder) {
+ super(AnnotationBehaviorMergeStrategy.first());
+ this.getBeanBuilder = Validate.notNull(getBeanBuilder, "getBeanBuilder function was null");
+ }
+
+ public MetadataBuilder.ForBean forBean(Class<?> beanClass) {
+ final List<MetadataBuilder.ForBean> delegates = new ArrayList<>();
+
+ /*
+ * First add the delegate for the requested bean class, forcing to empty if absent. This is important for the
+ * same reason that we use the #first() AnnotationBehaviorMergeStrategy: namely, that custom metadata overrides
+ * only from the immediately available mapping per the BV spec.
+ */
+ delegates.add(Optional.of(beanClass).map(getBeanBuilder).orElseGet(() -> EmptyBuilder.instance().forBean()));
+
+ // iterate the hierarchy, skipping the first (i.e. beanClass handled
+ // above)
+ final Iterator<Class<?>> hierarchy = Reflection.hierarchy(beanClass, Interfaces.INCLUDE).iterator();
+ hierarchy.next();
+
+ // skip Object.class; skip null/empty hierarchy builders, mapping others
+ // to HierarchyDelegate
+ hierarchy
+ .forEachRemaining(t -> Optional.of(t).filter(Predicate.isEqual(Object.class).negate()).map(getBeanBuilder)
+ .filter(b -> !b.isEmpty()).map(b -> new HierarchyDelegate.ForBean(b, t)).ifPresent(delegates::add));
+
+ // if we have nothing but empty builders (which should only happen for
+ // absent custom metadata), return empty:
+ if (delegates.stream().allMatch(MetadataBuilder.ForBean::isEmpty)) {
+ return EmptyBuilder.instance().forBean();
+ }
+ return delegates.stream().collect(compose());
+ }
+
+ @Override
+ protected <E extends AnnotatedElement> Map<Scope, Annotation[]> getConstraintsByScope(
+ CompositeBuilder.ForElement<? extends MetadataBuilder.ForElement<E>, E> composite, Metas<E> meta) {
+
+ final Iterator<? extends MetadataBuilder.ForElement<E>> iter = composite.delegates.iterator();
+
+ final Map<Scope, Annotation[]> result = new EnumMap<>(Scope.class);
+ result.put(Scope.LOCAL_ELEMENT, iter.next().getDeclaredConstraints(meta));
+
+ if (iter.hasNext()) {
+ final List<Annotation> hierarchyConstraints = new ArrayList<>();
+ iter.forEachRemaining(d -> Collections.addAll(hierarchyConstraints, d.getDeclaredConstraints(meta)));
+ result.put(Scope.HIERARCHY, hierarchyConstraints.toArray(new Annotation[hierarchyConstraints.size()]));
+ }
+ return result;
+ }
+
+ @Override
+ protected List<Class<?>> getGroupSequence(CompositeBuilder.ForClass composite, Metas<Class<?>> meta) {
+ return composite.delegates.get(0).getGroupSequence(meta);
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/MetadataBuilder.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/MetadataBuilder.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/MetadataBuilder.java
new file mode 100644
index 0000000..7dbdcbc
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/MetadataBuilder.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bval.jsr.metadata;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.AnnotatedType;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.validation.metadata.Scope;
+
+import org.apache.bval.jsr.descriptor.GroupConversion;
+
+/**
+ * Common interface for populating the Bean Validation descriptors from various sources. Most implementations should
+ * concern themselves with a single level of an inheritance hierarchy.
+ */
+public final class MetadataBuilder {
+
+ public interface ForBean extends HasAnnotationBehavior {
+ MetadataBuilder.ForClass getClass(Metas<Class<?>> meta);
+
+ Map<String, ForContainer<Field>> getFields(Metas<Class<?>> meta);
+
+ /**
+ * Returned keys are property names per XML mapping spec.
+ *
+ * @param meta
+ * @return {@link Map}
+ */
+ Map<String, ForContainer<Method>> getGetters(Metas<Class<?>> meta);
+
+ Map<Signature, ForExecutable<Constructor<?>>> getConstructors(Metas<Class<?>> meta);
+
+ Map<Signature, ForExecutable<Method>> getMethods(Metas<Class<?>> meta);
+
+ default boolean isEmpty() {
+ return false;
+ }
+ }
+
+ public interface ForElement<E extends AnnotatedElement> extends HasAnnotationBehavior {
+
+ Annotation[] getDeclaredConstraints(Metas<E> meta);
+
+ default Map<Scope, Annotation[]> getConstraintsByScope(Metas<E> meta) {
+ return Collections.singletonMap(Scope.LOCAL_ELEMENT, getDeclaredConstraints(meta));
+ }
+ }
+
+ public interface ForClass extends ForElement<Class<?>> {
+
+ List<Class<?>> getGroupSequence(Metas<Class<?>> meta);
+ }
+
+ public interface ForContainer<E extends AnnotatedElement> extends MetadataBuilder.ForElement<E> {
+
+ boolean isCascade(Metas<E> meta);
+
+ Set<GroupConversion> getGroupConversions(Metas<E> meta);
+
+ Map<ContainerElementKey, ForContainer<AnnotatedType>> getContainerElementTypes(Metas<E> meta);
+ }
+
+ public interface ForExecutable<E extends Executable> extends HasAnnotationBehavior {
+
+ MetadataBuilder.ForContainer<E> getReturnValue(Metas<E> meta);
+
+ MetadataBuilder.ForElement<E> getCrossParameter(Metas<E> meta);
+
+ List<ForContainer<Parameter>> getParameters(Metas<E> meta);
+ }
+
+ private MetadataBuilder() {
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/MetadataBuilders.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/MetadataBuilders.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/MetadataBuilders.java
new file mode 100644
index 0000000..aa301a4
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/MetadataBuilders.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.metadata;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.bval.util.Validate;
+
+public class MetadataBuilders {
+
+ private final Map<Class<?>, List<MetadataBuilder.ForBean>> beanBuilders = new ConcurrentHashMap<>();
+
+ public <T> void registerCustomBuilder(Class<?> bean, MetadataBuilder.ForBean builder) {
+ Validate.notNull(bean, "bean");
+ Validate.notNull(builder, "builder");
+ beanBuilders.computeIfAbsent(bean, c -> new ArrayList<>()).add(builder);
+ }
+
+ public List<MetadataBuilder.ForBean> getCustomBuilders(Class<?> bean) {
+ final List<MetadataBuilder.ForBean> list = beanBuilders.get(bean);
+ return list == null ? Collections.emptyList() : Collections.unmodifiableList(list);
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/Metas.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/Metas.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/Metas.java
new file mode 100644
index 0000000..667c404
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/Metas.java
@@ -0,0 +1,324 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.bval.jsr.metadata;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.AnnotatedType;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.lang.reflect.Type;
+import java.util.Objects;
+
+import javax.validation.constraintvalidation.ValidationTarget;
+
+import org.apache.bval.util.Validate;
+
+/**
+ * Validation class model.
+ *
+ * @param <E>
+ */
+// TODO rename to Meta; delete old type of that name
+public abstract class Metas<E extends AnnotatedElement> {
+
+ public static class ForClass extends Metas<Class<?>> {
+
+ public ForClass(Class<?> host) {
+ super(host, ElementType.TYPE);
+ }
+
+ @Override
+ public final Class<?> getDeclaringClass() {
+ return getHost();
+ }
+
+ @Override
+ public Type getType() {
+ return getHost();
+ }
+
+ @Override
+ public AnnotatedType getAnnotatedType() {
+ return new AnnotatedType() {
+
+ @Override
+ public Annotation[] getDeclaredAnnotations() {
+ return getHost().getDeclaredAnnotations();
+ }
+
+ @Override
+ public Annotation[] getAnnotations() {
+ return getHost().getAnnotations();
+ }
+
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
+ return getHost().getAnnotation(annotationClass);
+ }
+
+ @Override
+ public Type getType() {
+ return getHost();
+ }
+ };
+ }
+
+ @Override
+ public String getName() {
+ return getHost().getName();
+ }
+ }
+
+ public static abstract class ForMember<M extends Member & AnnotatedElement> extends Metas<M> {
+
+ protected ForMember(M host, ElementType elementType) {
+ super(host, elementType);
+ }
+
+ @Override
+ public Class<?> getDeclaringClass() {
+ return getHost().getDeclaringClass();
+ }
+ }
+
+ public static class ForField extends ForMember<Field> {
+
+ public ForField(Field host) {
+ super(host, ElementType.FIELD);
+ }
+
+ @Override
+ public Type getType() {
+ return getHost().getGenericType();
+ }
+
+ @Override
+ public AnnotatedType getAnnotatedType() {
+ return getHost().getAnnotatedType();
+ }
+
+ @Override
+ public String getName() {
+ return getHost().getName();
+ }
+ }
+
+ public static abstract class ForExecutable<E extends Executable> extends ForMember<E> {
+
+ protected ForExecutable(E host, ElementType elementType) {
+ super(host, elementType);
+ }
+
+ @Override
+ public AnnotatedType getAnnotatedType() {
+ return getHost().getAnnotatedReturnType();
+ }
+ }
+
+ public static class ForConstructor extends ForExecutable<Constructor<?>> {
+
+ public ForConstructor(Constructor<?> host) {
+ super(host, ElementType.CONSTRUCTOR);
+ }
+
+ @Override
+ public Type getType() {
+ return getHost().getDeclaringClass();
+ }
+
+ @Override
+ public String getName() {
+ return getHost().getDeclaringClass().getSimpleName();
+ }
+ }
+
+ public static class ForMethod extends ForExecutable<Method> {
+
+ public ForMethod(Method host) {
+ super(host, ElementType.METHOD);
+ }
+
+ @Override
+ public Type getType() {
+ return getHost().getGenericReturnType();
+ }
+
+ @Override
+ public String getName() {
+ return getHost().getName();
+ }
+ }
+
+ public static class ForCrossParameter<E extends Executable> extends Metas.ForExecutable<E> {
+
+ public ForCrossParameter(Metas<E> parent) {
+ super(parent.getHost(), parent.getElementType());
+ }
+
+ @Override
+ public Type getType() {
+ return Object[].class;
+ }
+
+ @Override
+ public String getName() {
+ return "<cross parameter>";
+ }
+
+ @Override
+ public ValidationTarget getValidationTarget() {
+ return ValidationTarget.PARAMETERS;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s(%s of %s)", getStringPrefix(), getName(), getHost());
+ }
+ }
+
+ public static class ForParameter extends Metas<Parameter> {
+
+ private final String name;
+
+ public ForParameter(Parameter host, String name) {
+ super(host, ElementType.PARAMETER);
+ this.name = Validate.notNull(name, "name");
+ }
+
+ @Override
+ public Type getType() {
+ return getHost().getType();
+ }
+
+ @Override
+ public Class<?> getDeclaringClass() {
+ return getHost().getDeclaringExecutable().getDeclaringClass();
+ }
+
+ @Override
+ public AnnotatedType getAnnotatedType() {
+ return getHost().getAnnotatedType();
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+
+ public static class ForContainerElement extends Metas<AnnotatedType> {
+
+ private final Metas<?> parent;
+ private final ContainerElementKey key;
+
+ public ForContainerElement(Metas<?> parent, ContainerElementKey key) {
+ super(key.getAnnotatedType(), ElementType.TYPE_USE);
+ this.parent = Validate.notNull(parent, "parent");
+ this.key = Validate.notNull(key, "key");
+ }
+
+ @Override
+ public Type getType() {
+ return getHost().getType();
+ }
+
+ @Override
+ public Class<?> getDeclaringClass() {
+ return parent.getDeclaringClass();
+ }
+
+ @Override
+ public AnnotatedType getAnnotatedType() {
+ return key.getAnnotatedType();
+ }
+
+ public Integer getTypeArgumentIndex() {
+ return Integer.valueOf(key.getTypeArgumentIndex());
+ }
+
+ @Override
+ public String getName() {
+ return key.toString();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s(%s of %s)", getStringPrefix(), key, getHost());
+ }
+ }
+
+ private final E host;
+ private final ElementType elementType;
+
+ protected Metas(E host, ElementType elementType) {
+ super();
+ this.host = Validate.notNull(host, "host");
+ this.elementType = Validate.notNull(elementType, "elementType");
+ }
+
+ public E getHost() {
+ return host;
+ }
+
+ public ElementType getElementType() {
+ return elementType;
+ }
+
+ public abstract Type getType();
+
+ public abstract Class<?> getDeclaringClass();
+
+ public abstract AnnotatedType getAnnotatedType();
+
+ public abstract String getName();
+
+ public ValidationTarget getValidationTarget() {
+ return ValidationTarget.ANNOTATED_ELEMENT;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s(%s)", getStringPrefix(), host);
+ }
+
+ protected String getStringPrefix() {
+ return Metas.class.getSimpleName() + '.' + getClass().getSimpleName();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!obj.getClass().equals(getClass())) {
+ return false;
+ }
+ return Objects.equals(((Metas<?>) obj).getHost(), getHost());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getHost());
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ReflectionBuilder.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ReflectionBuilder.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ReflectionBuilder.java
new file mode 100644
index 0000000..fc21ea7
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ReflectionBuilder.java
@@ -0,0 +1,272 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bval.jsr.metadata;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.AnnotatedParameterizedType;
+import java.lang.reflect.AnnotatedType;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import javax.validation.GroupSequence;
+import javax.validation.Valid;
+import javax.validation.constraintvalidation.ValidationTarget;
+import javax.validation.groups.ConvertGroup;
+
+import org.apache.bval.jsr.ApacheValidatorFactory;
+import org.apache.bval.jsr.ConstraintAnnotationAttributes;
+import org.apache.bval.jsr.descriptor.GroupConversion;
+import org.apache.bval.jsr.util.AnnotationsManager;
+import org.apache.bval.jsr.util.Methods;
+import org.apache.bval.jsr.util.ToUnmodifiable;
+import org.apache.bval.util.ObjectUtils;
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.Reflection;
+import org.apache.commons.weaver.privilizer.Privilizing;
+import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
+
+@Privilizing(@CallTo(Reflection.class))
+public class ReflectionBuilder {
+
+ private class ForBean implements MetadataBuilder.ForBean {
+ private final Metas<Class<?>> meta;
+
+ ForBean(Metas<Class<?>> meta) {
+ super();
+ this.meta = Validate.notNull(meta, "meta");
+ }
+
+ @Override
+ public MetadataBuilder.ForClass getClass(Metas<Class<?>> ignored) {
+ return new ReflectionBuilder.ForClass(meta);
+ }
+
+ @Override
+ public Map<String, MetadataBuilder.ForContainer<Field>> getFields(Metas<Class<?>> ignored) {
+ final Field[] declaredFields = Reflection.getDeclaredFields(meta.getHost());
+ if (declaredFields.length == 0) {
+ return Collections.emptyMap();
+ }
+ return Stream.of(declaredFields).collect(
+ Collectors.toMap(Field::getName, f -> new ReflectionBuilder.ForContainer<>(new Metas.ForField(f))));
+ }
+
+ @Override
+ public Map<String, MetadataBuilder.ForContainer<Method>> getGetters(Metas<Class<?>> ignored) {
+ return Stream.of(Reflection.getDeclaredMethods(meta.getHost())).filter(Methods::isGetter)
+ .collect(ToUnmodifiable.map(Methods::propertyName,
+ g -> new ReflectionBuilder.ForContainer<>(new Metas.ForMethod(g))));
+ }
+
+ @Override
+ public Map<Signature, MetadataBuilder.ForExecutable<Constructor<?>>> getConstructors(Metas<Class<?>> ignored) {
+ final Constructor<?>[] declaredConstructors = Reflection.getDeclaredConstructors(meta.getHost());
+ if (declaredConstructors.length == 0) {
+ return Collections.emptyMap();
+ }
+ return Stream.of(declaredConstructors).collect(
+ Collectors.toMap(Signature::of, c -> new ReflectionBuilder.ForExecutable<>(new Metas.ForConstructor(c),
+ validatorFactory.getParameterNameProvider()::getParameterNames)));
+ }
+
+ @Override
+ public Map<Signature, MetadataBuilder.ForExecutable<Method>> getMethods(Metas<Class<?>> ignored) {
+ final Method[] declaredMethods = Reflection.getDeclaredMethods(meta.getHost());
+ if (declaredMethods.length == 0) {
+ return Collections.emptyMap();
+ }
+ return Stream.of(declaredMethods).filter(((Predicate<Method>) Methods::isGetter).negate()).collect(
+ Collectors.toMap(Signature::of, m -> new ReflectionBuilder.ForExecutable<>(new Metas.ForMethod(m),
+ validatorFactory.getParameterNameProvider()::getParameterNames)));
+ }
+ }
+
+ private abstract class ForElement<E extends AnnotatedElement> implements MetadataBuilder.ForElement<E> {
+ final Metas<E> meta;
+
+ ForElement(Metas<E> meta) {
+ super();
+ this.meta = Validate.notNull(meta, "meta");
+ }
+
+ @Override
+ public Annotation[] getDeclaredConstraints(Metas<E> ignored) {
+ return AnnotationsManager.getDeclaredConstraints(meta);
+ }
+ }
+
+ private class ForClass extends ForElement<Class<?>> implements MetadataBuilder.ForClass {
+
+ ForClass(Metas<Class<?>> meta) {
+ super(meta);
+ }
+
+ @Override
+ public List<Class<?>> getGroupSequence(Metas<Class<?>> ignored) {
+ final GroupSequence groupSequence = meta.getHost().getAnnotation(GroupSequence.class);
+ return groupSequence == null ? null : Collections.unmodifiableList(Arrays.asList(groupSequence.value()));
+ }
+ }
+
+ private class ForContainer<E extends AnnotatedElement> extends ReflectionBuilder.ForElement<E>
+ implements MetadataBuilder.ForContainer<E> {
+
+ ForContainer(Metas<E> meta) {
+ super(meta);
+ }
+
+ @Override
+ public Map<ContainerElementKey, MetadataBuilder.ForContainer<AnnotatedType>> getContainerElementTypes(
+ Metas<E> ignored) {
+ final AnnotatedType annotatedType = meta.getAnnotatedType();
+ if (annotatedType instanceof AnnotatedParameterizedType) {
+
+ final AnnotatedParameterizedType container = (AnnotatedParameterizedType) annotatedType;
+
+ final Map<ContainerElementKey, MetadataBuilder.ForContainer<AnnotatedType>> result = new TreeMap<>();
+
+ final AnnotatedType[] typeArgs = container.getAnnotatedActualTypeArguments();
+ for (int i = 0; i < typeArgs.length; i++) {
+ ContainerElementKey key = new ContainerElementKey(container, i);
+ result.put(key, new ReflectionBuilder.ForContainer<>(new Metas.ForContainerElement(meta, key)));
+ }
+ return result;
+ }
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public boolean isCascade(Metas<E> ignored) {
+ return meta.getHost().isAnnotationPresent(Valid.class);
+ }
+
+ @Override
+ public Set<GroupConversion> getGroupConversions(Metas<E> ignored) {
+ return Stream.of(meta.getHost().getDeclaredAnnotationsByType(ConvertGroup.class))
+ .map(cg -> GroupConversion.from(cg.from()).to(cg.to())).collect(ToUnmodifiable.set());
+ }
+ }
+
+ private class ForExecutable<E extends Executable> implements MetadataBuilder.ForExecutable<E> {
+
+ final Metas<E> meta;
+ final Function<E, List<String>> getParameterNames;
+
+ ForExecutable(Metas<E> meta, Function<E, List<String>> getParameterNames) {
+ super();
+ this.meta = Validate.notNull(meta, "meta");
+ this.getParameterNames = Validate.notNull(getParameterNames, "getParameterNames");
+ }
+
+ @Override
+ public List<MetadataBuilder.ForContainer<Parameter>> getParameters(Metas<E> ignored) {
+ final Parameter[] parameters = meta.getHost().getParameters();
+ if (parameters.length == 0) {
+ return Collections.emptyList();
+ }
+ final List<String> parameterNames = getParameterNames.apply(meta.getHost());
+
+ return IntStream.range(0, parameters.length).mapToObj(
+ n -> new ReflectionBuilder.ForContainer<>(new Metas.ForParameter(parameters[n], parameterNames.get(n))))
+ .collect(ToUnmodifiable.list());
+ }
+
+ @Override
+ public ForContainer<E> getReturnValue(Metas<E> ignored) {
+ return new ReflectionBuilder.ForContainer<E>(meta) {
+
+ @Override
+ public Annotation[] getDeclaredConstraints(Metas<E> meta) {
+ return getConstraints(meta, ValidationTarget.ANNOTATED_ELEMENT);
+ }
+ };
+ }
+
+ @Override
+ public MetadataBuilder.ForElement<E> getCrossParameter(Metas<E> ignored) {
+ return new ReflectionBuilder.ForElement<E>(meta) {
+ @Override
+ public Annotation[] getDeclaredConstraints(Metas<E> meta) {
+ return getConstraints(meta, ValidationTarget.PARAMETERS);
+ }
+ };
+ }
+
+ private Annotation[] getConstraints(Metas<E> ignored, ValidationTarget validationTarget) {
+ return Optional.of(getConstraintsByTarget(meta)).map(m -> m.get(validationTarget))
+ .map(l -> l.toArray(new Annotation[l.size()])).orElse(ObjectUtils.EMPTY_ANNOTATION_ARRAY);
+ }
+
+ private Map<ValidationTarget, List<Annotation>> getConstraintsByTarget(Metas<E> ignored) {
+ final Annotation[] declaredConstraints = AnnotationsManager.getDeclaredConstraints(meta);
+ if (ObjectUtils.isEmpty(declaredConstraints)) {
+ return Collections.emptyMap();
+ }
+ final Map<ValidationTarget, List<Annotation>> result = new EnumMap<>(ValidationTarget.class);
+
+ for (Annotation constraint : declaredConstraints) {
+ final Class<? extends Annotation> constraintType = constraint.annotationType();
+ final Optional<ValidationTarget> explicitTarget =
+ Optional.of(ConstraintAnnotationAttributes.VALIDATION_APPLIES_TO.analyze(constraintType))
+ .filter(ConstraintAnnotationAttributes.Worker::isValid).map(w -> w.read(constraint));
+
+ final ValidationTarget target = explicitTarget.orElseGet(() -> {
+ final Set<ValidationTarget> supportedTargets =
+ validatorFactory.getAnnotationsManager().supportedTargets(constraintType);
+
+ Validate.validState(supportedTargets.size() == 1,
+ "Found %d possible %s types for constraint type %s and no explicit assignment via #%s()",
+ supportedTargets.size(), ValidationTarget.class.getSimpleName(), constraintType.getName(),
+ ConstraintAnnotationAttributes.VALIDATION_APPLIES_TO.getAttributeName());
+
+ return supportedTargets.iterator().next();
+ });
+ result.computeIfAbsent(target, k -> new ArrayList<>()).add(constraint);
+ }
+ return result;
+ }
+ }
+
+ private final ApacheValidatorFactory validatorFactory;
+
+ public ReflectionBuilder(ApacheValidatorFactory validatorFactory) {
+ super();
+ this.validatorFactory = Validate.notNull(validatorFactory, "validatorFactory");
+ }
+
+ public <T> MetadataBuilder.ForBean forBean(Class<?> beanClass) {
+ return new ReflectionBuilder.ForBean(new Metas.ForClass(beanClass));
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/Signature.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/Signature.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/Signature.java
new file mode 100644
index 0000000..8def7ae
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/Signature.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bval.jsr.metadata;
+
+import java.lang.reflect.Executable;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.bval.util.Lazy;
+import org.apache.bval.util.LazyInt;
+import org.apache.bval.util.StringUtils;
+import org.apache.bval.util.Validate;
+
+public final class Signature {
+ public static Signature of(Executable x) {
+ return new Signature(x.getName(), x.getParameterTypes());
+ }
+
+ private final String name;
+ private final Class<?>[] parameterTypes;
+ private final LazyInt hashCode;
+ private final Lazy<String> toString;
+
+ public Signature(String name, Class<?>... parameterTypes) {
+ super();
+ this.name = Validate.notNull(name, "name");
+ Validate.isTrue(StringUtils.isNotBlank(name), "name is blank");
+ this.parameterTypes = Validate.notNull(parameterTypes, "parameterTypes").clone();
+ hashCode = new LazyInt(() -> Arrays.deepHashCode(new Object[] { this.name, this.parameterTypes }));
+ toString = new Lazy<>(() -> String.format("%s: %s(%s)", getClass().getSimpleName(), this.name,
+ Stream.of(this.parameterTypes).map(Class::getName).collect(Collectors.joining(", "))));
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Class<?>[] getParameterTypes() {
+ return parameterTypes.clone();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj == this || Optional.ofNullable(obj).filter(Signature.class::isInstance).map(Signature.class::cast)
+ .filter(sig -> Objects.equals(name, sig.name) && Objects.deepEquals(parameterTypes, sig.parameterTypes))
+ .isPresent();
+ }
+
+ @Override
+ public int hashCode() {
+ return hashCode.getAsInt();
+ }
+
+ @Override
+ public String toString() {
+ return toString.get();
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ValidatorMapping.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ValidatorMapping.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ValidatorMapping.java
new file mode 100644
index 0000000..bd2ce7f
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ValidatorMapping.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bval.jsr.metadata;
+
+import java.lang.annotation.Annotation;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import javax.validation.ConstraintValidator;
+
+import org.apache.bval.util.Validate;
+
+public class ValidatorMapping<A extends Annotation> implements HasAnnotationBehavior {
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ private static final ValidatorMapping EMPTY = new ValidatorMapping("empty", Collections.emptyList());
+
+ @SuppressWarnings("unchecked")
+ public static <A extends Annotation> ValidatorMapping<A> empty() {
+ return EMPTY;
+ }
+
+ public static <A extends Annotation> ValidatorMapping<A> merge(
+ List<? extends ValidatorMapping<A>> validatorMappings,
+ AnnotationBehaviorMergeStrategy annotationBehaviorMergeStrategy) {
+
+ final AnnotationBehavior behavior = annotationBehaviorMergeStrategy.apply(validatorMappings);
+
+ final List<? extends ValidatorMapping<A>> nonEmpty =
+ validatorMappings.stream().filter(m -> !m.isEmpty()).collect(Collectors.toList());
+
+ if (nonEmpty.size() <= 1) {
+ // avoid creating the composite instance if behavior matches:
+ final ValidatorMapping<A> simpleResult = nonEmpty.isEmpty() ? empty() : nonEmpty.get(0);
+
+ if (simpleResult.hasBehavior(behavior)) {
+ return simpleResult;
+ }
+ }
+ final String source =
+ nonEmpty.stream().map(ValidatorMapping::getSource).collect(Collectors.joining(";", "[", "]"));
+
+ return new ValidatorMapping<>(source, nonEmpty.stream().map(ValidatorMapping::getValidatorTypes)
+ .flatMap(Collection::stream).distinct().collect(Collectors.toList()), behavior);
+ }
+
+ private final String source;
+ private final List<Class<? extends ConstraintValidator<A, ?>>> validatorTypes;
+ private final AnnotationBehavior annotationBehavior;
+
+ public ValidatorMapping(String source, List<Class<? extends ConstraintValidator<A, ?>>> validatorTypes) {
+ this(source, validatorTypes, AnnotationBehavior.ABSTAIN);
+ }
+
+ public ValidatorMapping(String source, List<Class<? extends ConstraintValidator<A, ?>>> validatorTypes,
+ AnnotationBehavior annotationBehavior) {
+ this.source = Objects.toString(source, "unspecified");
+ this.validatorTypes = Collections.unmodifiableList(Validate.notNull(validatorTypes, "validatorTypes"));
+ this.annotationBehavior = Validate.notNull(annotationBehavior, "annotationBehavior");
+ }
+
+ public List<Class<? extends ConstraintValidator<A, ?>>> getValidatorTypes() {
+ return validatorTypes;
+ }
+
+ public AnnotationBehavior getAnnotationBehavior() {
+ return annotationBehavior;
+ }
+
+ public boolean isEmpty() {
+ return validatorTypes.isEmpty();
+ }
+
+ public String getSource() {
+ return source;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!getClass().isInstance(obj)) {
+ return false;
+ }
+ final ValidatorMapping<?> other = (ValidatorMapping<?>) obj;
+ return getSource().equals(other.getSource()) && getAnnotationBehavior() == other.getAnnotationBehavior()
+ && getValidatorTypes().equals(other.getValidatorTypes());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getSource(), getAnnotationBehavior(), getValidatorTypes());
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s[source: %s; annotationBehavior: %s; validatorTypes: %s]",
+ ValidatorMapping.class.getSimpleName(), getSource(), getAnnotationBehavior(), getValidatorTypes());
+ }
+
+ public boolean hasBehavior(AnnotationBehavior annotationBehavior) {
+ return getAnnotationBehavior() == annotationBehavior;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ValidatorMappingProvider.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ValidatorMappingProvider.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ValidatorMappingProvider.java
new file mode 100644
index 0000000..8a8cd3f
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ValidatorMappingProvider.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.bval.jsr.metadata;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Optional;
+
+import javax.validation.ConstraintDefinitionException;
+import javax.validation.ConstraintValidator;
+
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.reflection.TypeUtils;
+
+public abstract class ValidatorMappingProvider {
+
+ public final <A extends Annotation> ValidatorMapping<A> getValidatorMapping(Class<A> constraintType) {
+ final Optional<ValidatorMapping<A>> result =
+ Optional.ofNullable(this.<A> doGetValidatorMapping(constraintType));
+ if (result.isPresent()) {
+ for (Class<? extends ConstraintValidator<A, ?>> t : result.get().getValidatorTypes()) {
+ final Type constraintParameter = TypeUtils.getTypeArguments(t, ConstraintValidator.class)
+ .get(ConstraintValidator.class.getTypeParameters()[0]);
+
+ Exceptions.raiseUnless(constraintType.equals(constraintParameter), ConstraintDefinitionException::new,
+ "%s %s expected first type parameter of %s, %s; source %s", ConstraintValidator.class, t,
+ constraintType, constraintParameter, result.get().getSource());
+ }
+ return result.get();
+ }
+ return null;
+ }
+
+ protected abstract <A extends Annotation> ValidatorMapping<A> doGetValidatorMapping(Class<A> constraintType);
+}
[04/11] bval git commit: implement BV 2.0 against existing BVal unit
tests
Posted by mb...@apache.org.
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/XmlBuilder.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/XmlBuilder.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/XmlBuilder.java
new file mode 100644
index 0000000..37082d4
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/XmlBuilder.java
@@ -0,0 +1,694 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bval.jsr.metadata;
+
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.AnnotatedParameterizedType;
+import java.lang.reflect.AnnotatedType;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.math.BigDecimal;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import javax.validation.ConstraintDeclarationException;
+import javax.validation.ConstraintTarget;
+import javax.validation.Payload;
+import javax.validation.ValidationException;
+import javax.xml.bind.JAXBElement;
+
+import org.apache.bval.jsr.ConstraintAnnotationAttributes;
+import org.apache.bval.jsr.descriptor.GroupConversion;
+import org.apache.bval.jsr.util.AnnotationsManager;
+import org.apache.bval.jsr.util.ToUnmodifiable;
+import org.apache.bval.jsr.xml.AnnotationProxyBuilder;
+import org.apache.bval.jsr.xml.AnnotationType;
+import org.apache.bval.jsr.xml.BeanType;
+import org.apache.bval.jsr.xml.ClassType;
+import org.apache.bval.jsr.xml.ConstraintMappingsType;
+import org.apache.bval.jsr.xml.ConstraintType;
+import org.apache.bval.jsr.xml.ConstructorType;
+import org.apache.bval.jsr.xml.ContainerElementTypeType;
+import org.apache.bval.jsr.xml.CrossParameterType;
+import org.apache.bval.jsr.xml.ElementType;
+import org.apache.bval.jsr.xml.FieldType;
+import org.apache.bval.jsr.xml.GetterType;
+import org.apache.bval.jsr.xml.GroupConversionType;
+import org.apache.bval.jsr.xml.GroupSequenceType;
+import org.apache.bval.jsr.xml.GroupsType;
+import org.apache.bval.jsr.xml.MethodType;
+import org.apache.bval.jsr.xml.ParameterType;
+import org.apache.bval.jsr.xml.PayloadType;
+import org.apache.bval.jsr.xml.ReturnValueType;
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.Lazy;
+import org.apache.bval.util.ObjectUtils;
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.Reflection;
+import org.apache.commons.weaver.privilizer.Privilizing;
+import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
+
+@Privilizing(@CallTo(Reflection.class))
+public class XmlBuilder {
+ //@formatter:off
+ public enum Version {
+ v10("1.0"), v11("1.1"), v20("2.0");
+
+ final BigDecimal number;
+ private final String id;
+
+ private Version(String number) {
+ this.id = number;
+ this.number = new BigDecimal(number);
+ }
+
+ public String getId() {
+ return id;
+ }
+ }
+ //@formatter:on
+
+ private class ForBean implements MetadataBuilder.ForBean {
+
+ private final BeanType descriptor;
+
+ ForBean(BeanType descriptor) {
+ super();
+ this.descriptor = Validate.notNull(descriptor, "descriptor");
+ }
+
+ Class<?> getBeanClass() {
+ return resolveClass(descriptor.getClazz());
+ }
+
+ @Override
+ public MetadataBuilder.ForClass getClass(Metas<Class<?>> meta) {
+ return new XmlBuilder.ForClass(descriptor.getClassType());
+ }
+
+ @Override
+ public Map<String, MetadataBuilder.ForContainer<Field>> getFields(Metas<Class<?>> meta) {
+ return descriptor.getField().stream()
+ .collect(ToUnmodifiable.map(FieldType::getName, XmlBuilder.ForField::new));
+ }
+
+ @Override
+ public Map<String, MetadataBuilder.ForContainer<Method>> getGetters(Metas<Class<?>> meta) {
+ return descriptor.getGetter().stream()
+ .collect(ToUnmodifiable.map(GetterType::getName, XmlBuilder.ForGetter::new));
+ }
+
+ @Override
+ public Map<Signature, MetadataBuilder.ForExecutable<Constructor<?>>> getConstructors(Metas<Class<?>> meta) {
+ if (!atLeast(Version.v11)) {
+ return Collections.emptyMap();
+ }
+ final Function<ConstructorType, Class<?>[]> params = ct -> ct.getParameter().stream()
+ .map(ParameterType::getType).map(XmlBuilder.this::resolveClass).toArray(Class[]::new);
+
+ final Function<ConstructorType, Signature> signature =
+ ct -> new Signature(meta.getHost().getSimpleName(), params.apply(ct));
+
+ return descriptor.getConstructor().stream()
+ .collect(Collectors.toMap(signature, XmlBuilder.ForConstructor::new));
+ }
+
+ @Override
+ public Map<Signature, MetadataBuilder.ForExecutable<Method>> getMethods(Metas<Class<?>> meta) {
+ if (!atLeast(Version.v11)) {
+ return Collections.emptyMap();
+ }
+ final Function<MethodType, Class<?>[]> params = mt -> mt.getParameter().stream().map(ParameterType::getType)
+ .map(XmlBuilder.this::resolveClass).toArray(Class[]::new);
+
+ final Function<MethodType, Signature> signature = mt -> new Signature(mt.getName(), params.apply(mt));
+
+ return descriptor.getMethod().stream().collect(Collectors.toMap(signature, XmlBuilder.ForMethod::new));
+ }
+
+ @Override
+ public final AnnotationBehavior getAnnotationBehavior() {
+ return descriptor.getIgnoreAnnotations() ? AnnotationBehavior.EXCLUDE : AnnotationBehavior.INCLUDE;
+ }
+ }
+
+ private class NonRootLevel<SELF extends NonRootLevel<SELF, D>, D> implements HasAnnotationBehavior {
+ protected final D descriptor;
+ private Lazy<Boolean> getIgnoreAnnotations;
+
+ public NonRootLevel(D descriptor) {
+ super();
+ this.descriptor = Validate.notNull(descriptor, "descriptor");
+ }
+
+ @Override
+ public final AnnotationBehavior getAnnotationBehavior() {
+ return Optional.ofNullable(getIgnoreAnnotations).map(Lazy::get)
+ .map(b -> b.booleanValue() ? AnnotationBehavior.EXCLUDE : AnnotationBehavior.INCLUDE)
+ .orElse(AnnotationBehavior.ABSTAIN);
+ }
+
+ @SuppressWarnings("unchecked")
+ final SELF withGetIgnoreAnnotations(Function<D, Boolean> getIgnoreAnnotations) {
+ Validate.notNull(getIgnoreAnnotations);
+ this.getIgnoreAnnotations = new Lazy<>(() -> getIgnoreAnnotations.apply(descriptor));
+ return (SELF) this;
+ }
+ }
+
+ private class ForElement<SELF extends XmlBuilder.ForElement<SELF, E, D>, E extends AnnotatedElement, D>
+ extends NonRootLevel<SELF, D> implements MetadataBuilder.ForElement<E> {
+
+ private Lazy<Annotation[]> getDeclaredConstraints;
+
+ ForElement(D descriptor) {
+ super(descriptor);
+ }
+
+ @Override
+ public final Annotation[] getDeclaredConstraints(Metas<E> meta) {
+ return lazy(getDeclaredConstraints, "getDeclaredConstraints");
+ }
+
+ final SELF withGetConstraintTypes(Function<D, List<ConstraintType>> getConstraintTypes) {
+ return withGetDeclaredConstraints(getConstraintTypes
+ .andThen(l -> l.stream().map(XmlBuilder.this::createConstraint).toArray(Annotation[]::new)));
+ }
+
+ @SuppressWarnings("unchecked")
+ final SELF withGetDeclaredConstraints(Function<D, Annotation[]> getDeclaredConstraints) {
+ this.getDeclaredConstraints = new Lazy<>(() -> getDeclaredConstraints.apply(descriptor));
+ return (SELF) this;
+ }
+ }
+
+ private class ForClass extends ForElement<ForClass, Class<?>, ClassType> implements MetadataBuilder.ForClass {
+
+ ForClass(ClassType descriptor) {
+ super(descriptor);
+ this.withGetConstraintTypes(ct -> ct.getConstraint());
+ }
+
+ @Override
+ public List<Class<?>> getGroupSequence(Metas<Class<?>> meta) {
+ final GroupSequenceType groupSequence = descriptor.getGroupSequence();
+ return groupSequence == null ? null
+ : groupSequence.getValue().stream().map(XmlBuilder.this::resolveClass).collect(ToUnmodifiable.list());
+ }
+ }
+
+ private class ForContainer<SELF extends XmlBuilder.ForContainer<SELF, E, D>, E extends AnnotatedElement, D>
+ extends XmlBuilder.ForElement<SELF, E, D> implements MetadataBuilder.ForContainer<E> {
+
+ private Lazy<Boolean> isCascade;
+ private Lazy<Set<GroupConversion>> getGroupConversions;
+ private Lazy<List<ContainerElementTypeType>> getContainerElementTypes;
+
+ ForContainer(D descriptor) {
+ super(descriptor);
+ }
+
+ @Override
+ public boolean isCascade(Metas<E> meta) {
+ return lazy(isCascade, "isCascade").booleanValue();
+ }
+
+ @Override
+ public Set<GroupConversion> getGroupConversions(Metas<E> meta) {
+ return lazy(getGroupConversions, "getGroupConversions");
+ }
+
+ @Override
+ public Map<ContainerElementKey, MetadataBuilder.ForContainer<AnnotatedType>> getContainerElementTypes(
+ Metas<E> meta) {
+ if (!atLeast(Version.v20)) {
+ return Collections.emptyMap();
+ }
+ final List<ContainerElementTypeType> elements = lazy(getContainerElementTypes, "getContainerElementTypes");
+ final AnnotatedType annotatedType = meta.getAnnotatedType();
+ final E host = meta.getHost();
+
+ if (annotatedType instanceof AnnotatedParameterizedType) {
+ final AnnotatedType[] actualTypeArguments =
+ ((AnnotatedParameterizedType) annotatedType).getAnnotatedActualTypeArguments();
+
+ return elements.stream().collect(ToUnmodifiable.map(cet -> {
+ Integer typeArgumentIndex = cet.getTypeArgumentIndex();
+ if (typeArgumentIndex == null) {
+ Exceptions.raiseIf(actualTypeArguments.length > 1, ValidationException::new,
+ "Missing required type argument index for %s", host);
+ typeArgumentIndex = Integer.valueOf(0);
+ }
+ return new ContainerElementKey((AnnotatedParameterizedType) annotatedType, typeArgumentIndex);
+ }, XmlBuilder.ForContainerElementType::new));
+ }
+ Exceptions.raiseUnless(elements.isEmpty(), ValidationException::new,
+ "Illegally specified %d container element type(s) for %s", elements.size(), host);
+
+ return Collections.emptyMap();
+ }
+
+ @SuppressWarnings("unchecked")
+ SELF withGetValid(Function<D, String> getValid) {
+ Validate.notNull(getValid);
+ this.isCascade = new Lazy<>(() -> getValid.apply(descriptor) != null);
+ return (SELF) this;
+ }
+
+ @SuppressWarnings("unchecked")
+ SELF withGetGroupConversions(Function<D, List<GroupConversionType>> getGroupConversions) {
+ Validate.notNull(getGroupConversions);
+
+ this.getGroupConversions = new Lazy<>(() -> {
+ return getGroupConversions.apply(descriptor).stream().map(gc -> {
+ final Class<?> source = resolveClass(gc.getFrom());
+ final Class<?> target = resolveClass(gc.getTo());
+ return GroupConversion.from(source).to(target);
+ }).collect(ToUnmodifiable.set());
+ });
+ return (SELF) this;
+ }
+
+ @SuppressWarnings("unchecked")
+ SELF withGetContainerElementTypes(Function<D, List<ContainerElementTypeType>> getContainerElementTypes) {
+ Validate.notNull(getContainerElementTypes);
+ this.getContainerElementTypes = new Lazy<>(() -> getContainerElementTypes.apply(descriptor));
+ return (SELF) this;
+ }
+ }
+
+ private class ForContainerElementType
+ extends ForContainer<ForContainerElementType, AnnotatedType, ContainerElementTypeType> {
+
+ ForContainerElementType(ContainerElementTypeType descriptor) {
+ super(descriptor);
+ this.withGetConstraintTypes(ContainerElementTypeType::getConstraint)
+ .withGetValid(ContainerElementTypeType::getValid)
+ .withGetGroupConversions(ContainerElementTypeType::getConvertGroup)
+ .withGetContainerElementTypes(ContainerElementTypeType::getContainerElementType);
+ }
+ }
+
+ private class ForField extends XmlBuilder.ForContainer<ForField, Field, FieldType> {
+
+ ForField(FieldType descriptor) {
+ super(descriptor);
+ this.withGetIgnoreAnnotations(FieldType::getIgnoreAnnotations)
+ .withGetConstraintTypes(FieldType::getConstraint).withGetValid(FieldType::getValid)
+ .withGetGroupConversions(FieldType::getConvertGroup)
+ .withGetContainerElementTypes(FieldType::getContainerElementType);
+ }
+ }
+
+ private class ForGetter extends XmlBuilder.ForContainer<ForGetter, Method, GetterType> {
+
+ ForGetter(GetterType descriptor) {
+ super(descriptor);
+ this.withGetIgnoreAnnotations(GetterType::getIgnoreAnnotations)
+ .withGetConstraintTypes(GetterType::getConstraint).withGetValid(GetterType::getValid)
+ .withGetGroupConversions(GetterType::getConvertGroup)
+ .withGetContainerElementTypes(GetterType::getContainerElementType);
+ }
+ }
+
+ private abstract class ForExecutable<SELF extends ForExecutable<SELF, E, D>, E extends Executable, D>
+ extends NonRootLevel<SELF, D> implements MetadataBuilder.ForExecutable<E> {
+
+ Lazy<ReturnValueType> getReturnValue;
+ Lazy<CrossParameterType> getCrossParameter;
+ Lazy<List<ParameterType>> getParameters;
+
+ ForExecutable(D descriptor) {
+ super(descriptor);
+ }
+
+ @Override
+ public MetadataBuilder.ForElement<E> getCrossParameter(Metas<E> meta) {
+ return new XmlBuilder.ForCrossParameter<>(lazy(getCrossParameter, "getCrossParameter"));
+ }
+
+ @Override
+ public MetadataBuilder.ForContainer<E> getReturnValue(Metas<E> meta) {
+ return new XmlBuilder.ForReturnValue<>(lazy(getReturnValue, "getReturnValue"));
+ }
+
+ @Override
+ public List<MetadataBuilder.ForContainer<Parameter>> getParameters(Metas<E> meta) {
+ return lazy(getParameters, "getParameters").stream().map(XmlBuilder.ForParameter::new)
+ .collect(Collectors.toList());
+ }
+
+ @SuppressWarnings("unchecked")
+ SELF withGetReturnValue(Function<D, ReturnValueType> getReturnValue) {
+ Validate.notNull(getReturnValue);
+ this.getReturnValue = new Lazy<>(() -> getReturnValue.apply(descriptor));
+ return (SELF) this;
+ }
+
+ @SuppressWarnings("unchecked")
+ SELF withGetCrossParameter(Function<D, CrossParameterType> getCrossParameter) {
+ Validate.notNull(getCrossParameter);
+ this.getCrossParameter = new Lazy<>(() -> getCrossParameter.apply(descriptor));
+ return (SELF) this;
+ }
+
+ @SuppressWarnings("unchecked")
+ SELF withGetParameters(Function<D, List<ParameterType>> getParameters) {
+ Validate.notNull(getParameters);
+ this.getParameters = new Lazy<>(() -> getParameters.apply(descriptor));
+ return (SELF) this;
+ }
+ }
+
+ private class ForConstructor extends ForExecutable<ForConstructor, Constructor<?>, ConstructorType> {
+
+ ForConstructor(ConstructorType descriptor) {
+ super(descriptor);
+ this.withGetIgnoreAnnotations(ConstructorType::getIgnoreAnnotations)
+ .withGetReturnValue(ConstructorType::getReturnValue)
+ .withGetCrossParameter(ConstructorType::getCrossParameter)
+ .withGetParameters(ConstructorType::getParameter);
+ }
+ }
+
+ private class ForMethod extends ForExecutable<ForMethod, Method, MethodType> {
+
+ ForMethod(MethodType descriptor) {
+ super(descriptor);
+ this.withGetIgnoreAnnotations(MethodType::getIgnoreAnnotations)
+ .withGetReturnValue(MethodType::getReturnValue).withGetCrossParameter(MethodType::getCrossParameter)
+ .withGetParameters(MethodType::getParameter);
+ }
+ }
+
+ private class ForParameter extends ForContainer<ForParameter, Parameter, ParameterType> {
+
+ ForParameter(ParameterType descriptor) {
+ super(descriptor);
+ this.withGetIgnoreAnnotations(ParameterType::getIgnoreAnnotations)
+ .withGetConstraintTypes(ParameterType::getConstraint).withGetValid(ParameterType::getValid)
+ .withGetGroupConversions(ParameterType::getConvertGroup)
+ .withGetContainerElementTypes(ParameterType::getContainerElementType);
+ }
+ }
+
+ private class ForCrossParameter<E extends Executable>
+ extends ForElement<ForCrossParameter<E>, E, CrossParameterType> {
+
+ ForCrossParameter(CrossParameterType descriptor) {
+ super(descriptor);
+ this.withGetIgnoreAnnotations(CrossParameterType::getIgnoreAnnotations)
+ .withGetDeclaredConstraints(d -> d.getConstraint().stream()
+ .map(ct -> createConstraint(ct, ConstraintTarget.PARAMETERS)).toArray(Annotation[]::new));
+ }
+ }
+
+ private class ForReturnValue<E extends Executable> extends ForContainer<ForReturnValue<E>, E, ReturnValueType> {
+
+ ForReturnValue(ReturnValueType descriptor) {
+ super(descriptor);
+ this.withGetDeclaredConstraints(d -> d.getConstraint().stream()
+ .map(ct -> createConstraint(ct, ConstraintTarget.RETURN_VALUE)).toArray(Annotation[]::new))
+ .withGetContainerElementTypes(d -> d.getContainerElementType());
+ }
+ }
+
+ private static final Set<ConstraintAnnotationAttributes> RESERVED_PARAMS = Collections
+ .unmodifiableSet(EnumSet.of(ConstraintAnnotationAttributes.GROUPS, ConstraintAnnotationAttributes.MESSAGE,
+ ConstraintAnnotationAttributes.PAYLOAD, ConstraintAnnotationAttributes.VALIDATION_APPLIES_TO));
+
+ static final <T> T lazy(Lazy<T> lazy, String name) {
+ Validate.validState(lazy != null, "%s not set", name);
+ return lazy.get();
+ }
+
+ private final ConstraintMappingsType constraintMappings;
+ private final BigDecimal version;
+
+ public XmlBuilder(ConstraintMappingsType constraintMappings) {
+ super();
+ this.constraintMappings = constraintMappings;
+ Validate.notNull(constraintMappings, "constraintMappings");
+
+ BigDecimal v;
+ try {
+ v = new BigDecimal(constraintMappings.getVersion());
+ } catch (NumberFormatException e) {
+ v = Version.v10.number;
+ }
+ this.version = v;
+ }
+
+ public Map<Class<?>, MetadataBuilder.ForBean> forBeans() {
+ return constraintMappings.getBean().stream().map(XmlBuilder.ForBean::new)
+ .collect(ToUnmodifiable.map(XmlBuilder.ForBean::getBeanClass, Function.identity()));
+ }
+
+ public String getDefaultPackage() {
+ return constraintMappings.getDefaultPackage();
+ }
+
+ boolean atLeast(Version v) {
+ return version.compareTo(v.number) >= 0;
+ }
+
+ <T> Class<T> resolveClass(String className) {
+ return loadClass(toQualifiedClassName(className));
+ }
+
+ private String toQualifiedClassName(String className) {
+ if (isQualifiedClass(className)) {
+ return className;
+ }
+ if (className.startsWith("[L") && className.endsWith(";")) {
+ return "[L" + getDefaultPackage() + "." + className.substring(2);
+ }
+ return getDefaultPackage() + "." + className;
+ }
+
+ private boolean isQualifiedClass(String clazz) {
+ return clazz.indexOf('.') >= 0;
+ }
+
+ @SuppressWarnings("unchecked")
+ private <T> Class<T> loadClass(final String fqn) {
+ ClassLoader loader = Reflection.getClassLoader(XmlBuilder.class);
+ if (loader == null) {
+ loader = getClass().getClassLoader();
+ }
+ try {
+ return (Class<T>) Class.forName(fqn, true, loader);
+ } catch (ClassNotFoundException ex) {
+ throw Exceptions.create(ValidationException::new, ex, "Unable to load class: %d", fqn);
+ }
+ }
+
+ private Class<?>[] loadClasses(Supplier<Stream<String>> classNames) {
+ return streamClasses(classNames).toArray(Class[]::new);
+ }
+
+ private Stream<Class<?>> streamClasses(Supplier<Stream<String>> classNames) {
+ return classNames.get().map(this::loadClass);
+ }
+
+ private <A extends Annotation, T> A createConstraint(final ConstraintType constraint) {
+ return createConstraint(constraint, ConstraintTarget.IMPLICIT);
+ }
+
+ @SuppressWarnings("unchecked")
+ private <A extends Annotation, T> A createConstraint(final ConstraintType constraint, ConstraintTarget target) {
+
+ final Class<A> annotationClass = (Class<A>) loadClass(toQualifiedClassName(constraint.getAnnotation()));
+ final AnnotationProxyBuilder<A> annoBuilder = new AnnotationProxyBuilder<A>(annotationClass);
+
+ if (constraint.getMessage() != null) {
+ annoBuilder.setMessage(constraint.getMessage());
+ }
+ annoBuilder.setGroups(getGroups(constraint.getGroups()));
+ annoBuilder.setPayload(getPayload(constraint.getPayload()));
+
+ if (AnnotationsManager.declaresAttribute(annotationClass,
+ ConstraintAnnotationAttributes.VALIDATION_APPLIES_TO.getAttributeName())) {
+ annoBuilder.setValidationAppliesTo(target);
+ }
+
+ for (final ElementType elementType : constraint.getElement()) {
+ final String name = elementType.getName();
+ checkValidName(name);
+
+ final Class<?> returnType = getAnnotationParameterType(annotationClass, name);
+ final Object elementValue = getElementValue(elementType, returnType);
+ annoBuilder.setValue(name, elementValue);
+ }
+ return annoBuilder.createAnnotation();
+ }
+
+ private void checkValidName(String name) {
+ Exceptions.raiseIf(RESERVED_PARAMS.stream().map(ConstraintAnnotationAttributes::getAttributeName)
+ .anyMatch(Predicate.isEqual(name)), ValidationException::new, "%s is a reserved parameter name.", name);
+ }
+
+ private <A extends Annotation> Class<?> getAnnotationParameterType(final Class<A> annotationClass,
+ final String name) {
+ final Method m = Reflection.getPublicMethod(annotationClass, name);
+ Exceptions.raiseIf(m == null, ValidationException::new,
+ "Annotation of type %s does not contain a parameter %s.", annotationClass.getName(), name);
+ return m.getReturnType();
+ }
+
+ private Object getElementValue(ElementType elementType, Class<?> returnType) {
+ removeEmptyContentElements(elementType);
+
+ final List<Serializable> content = elementType.getContent();
+ final int sz = content.size();
+ if (returnType.isArray()) {
+ final Object result = Array.newInstance(returnType.getComponentType(), sz);
+ for (int i = 0; i < sz; i++) {
+ Array.set(result, i, getSingleValue(content.get(i), returnType.getComponentType()));
+ }
+ return result;
+ }
+ Exceptions.raiseIf(sz != 1, ValidationException::new,
+ "Attempt to specify an array where single value is expected.");
+
+ return getSingleValue(content.get(0), returnType);
+ }
+
+ private void removeEmptyContentElements(ElementType elementType) {
+ for (Iterator<Serializable> iter = elementType.getContent().iterator(); iter.hasNext();) {
+ final Serializable content = iter.next();
+ if (content instanceof String && ((String) content).matches("[\\n ].*")) {
+ iter.remove();
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private Object getSingleValue(Serializable serializable, Class<?> returnType) {
+ if (serializable instanceof String) {
+ return convertToResultType(returnType, (String) serializable);
+ }
+ if (serializable instanceof JAXBElement<?>) {
+ final JAXBElement<?> elem = (JAXBElement<?>) serializable;
+ if (String.class.equals(elem.getDeclaredType())) {
+ return convertToResultType(returnType, (String) elem.getValue());
+ }
+ if (AnnotationType.class.equals(elem.getDeclaredType())) {
+ AnnotationType annotationType = (AnnotationType) elem.getValue();
+ try {
+ return createAnnotation(annotationType, (Class<? extends Annotation>) returnType);
+ } catch (ClassCastException e) {
+ throw new ValidationException("Unexpected parameter value");
+ }
+ }
+ }
+ throw new ValidationException("Unexpected parameter value");
+ }
+
+ private Object convertToResultType(Class<?> returnType, String value) {
+ /**
+ * Class is represented by the fully qualified class name of the class. spec: Note that if the raw string is
+ * unqualified, default package is taken into account.
+ */
+ if (String.class.equals(returnType)) {
+ return value;
+ }
+ if (Class.class.equals(returnType)) {
+ return resolveClass(value);
+ }
+ if (returnType.isEnum()) {
+ try {
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ final Enum e = Enum.valueOf(returnType.asSubclass(Enum.class), value);
+ return e;
+ } catch (IllegalArgumentException e) {
+ throw new ConstraintDeclarationException(e);
+ }
+ }
+ if (Byte.class.equals(returnType) || byte.class.equals(returnType)) {
+ // spec mandates it:
+ return Byte.parseByte(value);
+ }
+ if (Short.class.equals(returnType) || short.class.equals(returnType)) {
+ return Short.parseShort(value);
+ }
+ if (Integer.class.equals(returnType) || int.class.equals(returnType)) {
+ return Integer.parseInt(value);
+ }
+ if (Long.class.equals(returnType) || long.class.equals(returnType)) {
+ return Long.parseLong(value);
+ }
+ if (Float.class.equals(returnType) || float.class.equals(returnType)) {
+ return Float.parseFloat(value);
+ }
+ if (Double.class.equals(returnType) || double.class.equals(returnType)) {
+ return Double.parseDouble(value);
+ }
+ if (Boolean.class.equals(returnType) || boolean.class.equals(returnType)) {
+ return Boolean.parseBoolean(value);
+ }
+ if (Character.class.equals(returnType) || char.class.equals(returnType)) {
+ Exceptions.raiseIf(value.length() > 1, ConstraintDeclarationException::new,
+ "a char must have a length of 1");
+ return value.charAt(0);
+ }
+ return Exceptions.raise(ValidationException::new, "Unknown annotation value type %s", returnType.getName());
+ }
+
+ private <A extends Annotation> Annotation createAnnotation(AnnotationType annotationType, Class<A> returnType) {
+ final AnnotationProxyBuilder<A> metaAnnotation = new AnnotationProxyBuilder<>(returnType);
+ for (ElementType elementType : annotationType.getElement()) {
+ final String name = elementType.getName();
+ metaAnnotation.setValue(name, getElementValue(elementType, getAnnotationParameterType(returnType, name)));
+ }
+ return metaAnnotation.createAnnotation();
+ }
+
+ private Class<?>[] getGroups(GroupsType groupsType) {
+ if (groupsType == null) {
+ return ObjectUtils.EMPTY_CLASS_ARRAY;
+ }
+ return loadClasses(groupsType.getValue()::stream);
+ }
+
+ @SuppressWarnings("unchecked")
+ private Class<? extends Payload>[] getPayload(PayloadType payloadType) {
+ if (payloadType == null) {
+ return (Class<? extends Payload>[]) ObjectUtils.EMPTY_CLASS_ARRAY;
+ }
+ return streamClasses(payloadType.getValue()::stream).peek(pc -> {
+ Exceptions.raiseUnless(Payload.class.isAssignableFrom(pc), ConstraintDeclarationException::new,
+ "Specified payload class %s does not implement %s", pc.getName(), Payload.class.getName());
+ }).<Class<? extends Payload>> map(pc -> pc.asSubclass(Payload.class)).toArray(Class[]::new);
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/XmlValidationMappingProvider.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/XmlValidationMappingProvider.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/XmlValidationMappingProvider.java
new file mode 100644
index 0000000..a47d1c6
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/XmlValidationMappingProvider.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bval.jsr.metadata;
+
+import java.lang.annotation.Annotation;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+
+import javax.validation.ConstraintValidator;
+
+import org.apache.bval.jsr.xml.ValidatedByType;
+import org.apache.bval.util.Validate;
+
+public class XmlValidationMappingProvider extends ClassLoadingValidatorMappingProvider {
+ private static final Logger log = Logger.getLogger(XmlValidationMappingProvider.class.getName());
+
+ private final Map<Class<? extends Annotation>, ValidatedByType> config;
+ private final Function<String, String> classNameTransformer;
+
+ public XmlValidationMappingProvider(Map<Class<? extends Annotation>, ValidatedByType> validatorMappings,
+ Function<String, String> classNameTransformer) {
+ super();
+ this.config = Validate.notNull(validatorMappings, "validatorMappings");
+ this.classNameTransformer = Validate.notNull(classNameTransformer, "classNameTransformer");
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Override
+ public <A extends Annotation> ValidatorMapping<A> doGetValidatorMapping(Class<A> constraintType) {
+ final ValidatedByType validatedByType = config.get(constraintType);
+ if (validatedByType == null) {
+ return null;
+ }
+ return new ValidatorMapping<>("XML descriptor",
+ load(validatedByType.getValue().stream().map(String::trim).map(classNameTransformer),
+ (Class<ConstraintValidator<A, ?>>) (Class) ConstraintValidator.class,
+ e -> log.log(Level.SEVERE, "exception loading XML-declared constraint validators", e))
+ .collect(Collectors.toList()),
+ toAnnotationBehavior(validatedByType));
+ }
+
+ private AnnotationBehavior toAnnotationBehavior(ValidatedByType validatedByType) {
+ final Boolean includeExistingValidators = validatedByType.getIncludeExistingValidators();
+ return includeExistingValidators == null ? AnnotationBehavior.ABSTAIN
+ : includeExistingValidators.booleanValue() ? AnnotationBehavior.INCLUDE : AnnotationBehavior.EXCLUDE;
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/parameter/DefaultParameterNameProvider.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/parameter/DefaultParameterNameProvider.java b/bval-jsr/src/main/java/org/apache/bval/jsr/parameter/DefaultParameterNameProvider.java
index 2b43bcd..dec9ae8 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/parameter/DefaultParameterNameProvider.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/parameter/DefaultParameterNameProvider.java
@@ -18,30 +18,29 @@
*/
package org.apache.bval.jsr.parameter;
-import javax.validation.ParameterNameProvider;
import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
import java.lang.reflect.Method;
-import java.util.ArrayList;
+import java.lang.reflect.Parameter;
import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import javax.validation.ParameterNameProvider;
public class DefaultParameterNameProvider implements ParameterNameProvider {
- private static final String ARG = "arg";
+
+ private static List<String> parameterNames(Executable exe) {
+ return Stream.of(exe.getParameters()).map(Parameter::getName).collect(Collectors.toList());
+ }
@Override
public List<String> getParameterNames(Constructor<?> constructor) {
- return names(constructor.getParameterTypes().length);
+ return parameterNames(constructor);
}
@Override
public List<String> getParameterNames(Method method) {
- return names(method.getParameterTypes().length);
- }
-
- private static List<String> names(final int length) {
- final List<String> list = new ArrayList<String>();
- for (int i = 0; i < length; i++) {
- list.add(ARG + i);
- }
- return list;
+ return parameterNames(method);
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/resolver/CachingTraversableResolver.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/resolver/CachingTraversableResolver.java b/bval-jsr/src/main/java/org/apache/bval/jsr/resolver/CachingTraversableResolver.java
index 05639c7..2f212de 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/resolver/CachingTraversableResolver.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/resolver/CachingTraversableResolver.java
@@ -21,6 +21,7 @@ import javax.validation.TraversableResolver;
import java.lang.annotation.ElementType;
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
/**
* Cache results of a delegated traversable resovler to optimize calls
@@ -34,7 +35,7 @@ import java.util.Map;
*/
public class CachingTraversableResolver implements TraversableResolver, CachingRelevant {
private TraversableResolver delegate;
- private Map<CacheEntry, CacheEntry> cache = new HashMap<CacheEntry, CacheEntry>();
+ private Map<CacheEntry, CacheEntry> cache = new HashMap<>();
/**
* Convenience method to check whether caching is necessary on a given {@link TraversableResolver}.
@@ -61,11 +62,8 @@ public class CachingTraversableResolver implements TraversableResolver, CachingR
* @see #needsCaching(TraversableResolver)
*/
public static TraversableResolver cacheFor(TraversableResolver traversableResolver) {
- if (needsCaching(traversableResolver)) {
- return new CachingTraversableResolver(traversableResolver);
- } else {
- return traversableResolver;
- }
+ return needsCaching(traversableResolver) ? new CachingTraversableResolver(traversableResolver)
+ : traversableResolver;
}
/**
@@ -158,15 +156,14 @@ public class CachingTraversableResolver implements TraversableResolver, CachingR
if (this == o) {
return true;
}
- if (o == null || getClass() != o.getClass()) {
+ if (o == null || !getClass().equals(o.getClass())) {
return false;
}
CacheEntry that = (CacheEntry) o;
- return elementType == that.elementType && path.equals(that.path) && type.equals(that.type)
- && !(object != null ? !object.equals(that.object) : that.object != null) && node.equals(that.node);
-
+ return elementType == that.elementType && Objects.equals(path, that.path) && Objects.equals(type, that.type)
+ && Objects.equals(object, that.object) && Objects.equals(node, that.node);
}
/**
@@ -178,12 +175,7 @@ public class CachingTraversableResolver implements TraversableResolver, CachingR
}
private int buildHashCode() {
- int result = object != null ? object.hashCode() : 0;
- result = 31 * result + node.hashCode();
- result = 31 * result + type.hashCode();
- result = 31 * result + path.hashCode();
- result = 31 * result + elementType.hashCode();
- return result;
+ return Objects.hash(object, node, type, path, elementType);
}
}
-}
\ No newline at end of file
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/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/3f287a7a/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/3f287a7a/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/3f287a7a/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/3f287a7a/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/3f287a7a/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/3f287a7a/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/3f287a7a/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/3f287a7a/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/3f287a7a/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/3f287a7a/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);
}
}
[06/11] bval git commit: implement BV 2.0 against existing BVal unit
tests
Posted by mb...@apache.org.
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateProperty.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateProperty.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateProperty.java
new file mode 100644
index 0000000..a8fbdbc
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateProperty.java
@@ -0,0 +1,522 @@
+/*
+ * 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.job;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Path;
+import javax.validation.metadata.BeanDescriptor;
+import javax.validation.metadata.CascadableDescriptor;
+import javax.validation.metadata.ContainerDescriptor;
+import javax.validation.metadata.ContainerElementTypeDescriptor;
+import javax.validation.metadata.ElementDescriptor;
+import javax.validation.metadata.PropertyDescriptor;
+import javax.validation.valueextraction.ValueExtractor;
+import javax.validation.valueextraction.ValueExtractor.ValueReceiver;
+
+import org.apache.bval.jsr.ApacheFactoryContext;
+import org.apache.bval.jsr.ConstraintViolationImpl;
+import org.apache.bval.jsr.GraphContext;
+import org.apache.bval.jsr.descriptor.BeanD;
+import org.apache.bval.jsr.descriptor.CascadableContainerD;
+import org.apache.bval.jsr.descriptor.ComposedD;
+import org.apache.bval.jsr.descriptor.ConstraintD;
+import org.apache.bval.jsr.descriptor.ContainerElementTypeD;
+import org.apache.bval.jsr.descriptor.ElementD;
+import org.apache.bval.jsr.descriptor.PropertyD;
+import org.apache.bval.jsr.metadata.ContainerElementKey;
+import org.apache.bval.jsr.util.PathImpl;
+import org.apache.bval.jsr.util.PathNavigation;
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.ObjectWrapper;
+import org.apache.bval.util.StringUtils;
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.TypeUtils;
+
+public final class ValidateProperty<T> extends ValidationJob<T> {
+
+ interface Strategy<T> {
+ default PathNavigation.Callback<?> callback(PathImpl.Builder pathBuilder, FindDescriptor findDescriptor) {
+ return new PathNavigation.CompositeCallbackProcedure(Arrays.asList(pathBuilder, findDescriptor));
+ }
+
+ default T getRootBean() {
+ return null;
+ }
+
+ ValidateProperty<T>.Frame<?> frame(ValidateProperty<T> job, PathImpl path);
+ }
+
+ static class ForBeanProperty<T> implements Strategy<T> {
+ final ApacheFactoryContext validatorContext;
+ final T rootBean;
+ final GraphContext rootContext;
+ final ObjectWrapper<GraphContext> leafContext;
+ final ObjectWrapper<Object> value;
+
+ ForBeanProperty(ApacheFactoryContext validatorContext, T bean) {
+ super();
+ this.validatorContext = validatorContext;
+ this.rootBean = bean;
+ this.rootContext = new GraphContext(validatorContext, PathImpl.create(), bean);
+ this.leafContext = new ObjectWrapper<>(rootContext);
+ this.value = new ObjectWrapper<>(bean);
+ }
+
+ @Override
+ public PathNavigation.Callback<?> callback(PathImpl.Builder pathBuilder, FindDescriptor findDescriptor) {
+ return new WalkGraph(validatorContext, pathBuilder, findDescriptor, value,
+ (p, v) -> leafContext.accept(p.isRootPath() ? rootContext : rootContext.child(p, v)));
+ }
+
+ @Override
+ public T getRootBean() {
+ return rootBean;
+ }
+
+ public GraphContext baseContext(PathImpl path, ApacheFactoryContext validatorContext) {
+ return new GraphContext(validatorContext, PathImpl.create(), rootBean).child(path, value.get());
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Override
+ public ValidationJob<T>.Frame<?> frame(ValidateProperty<T> job, PathImpl path) {
+ if (job.descriptor instanceof BeanDescriptor) {
+ return job.new LeafFrame(leafContext.get());
+ }
+ return job.new PropertyFrame(job.new BeanFrame(leafContext.get()), job.descriptor,
+ leafContext.get().child(path, value.get()));
+ }
+ }
+
+ static class ForPropertyValue<T> implements Strategy<T> {
+ final Object value;
+
+ ForPropertyValue(Object value) {
+ super();
+ this.value = value;
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Override
+ public ValidationJob<T>.Frame<?> frame(ValidateProperty<T> job, PathImpl path) {
+ final GraphContext context = new GraphContext(job.validatorContext, path, value);
+ if (job.descriptor instanceof BeanDescriptor) {
+ return job.new LeafFrame(context);
+ }
+ return job.new PropertyFrame(null, job.descriptor, context);
+ }
+ }
+
+ private interface Step {
+ Type type();
+
+ ElementD<?, ?> element();
+ }
+
+ private static class DescriptorWrapper implements Step {
+ final ElementD<?, ?> wrapped;
+
+ DescriptorWrapper(ElementDescriptor wrapped) {
+ super();
+ this.wrapped = (ElementD<?, ?>) wrapped;
+ }
+
+ @Override
+ public Type type() {
+ return wrapped.getGenericType();
+ }
+
+ @Override
+ public ElementD<?, ?> element() {
+ return wrapped;
+ }
+ }
+
+ private static class TypeWrapper implements Step {
+ final ApacheFactoryContext validatorContext;
+ final Type type;
+
+ TypeWrapper(ApacheFactoryContext validatorContext, Type type) {
+ super();
+ this.validatorContext = validatorContext;
+ this.type = type;
+ }
+
+ @Override
+ public Type type() {
+ return type;
+ }
+
+ @Override
+ public ElementD<?, ?> element() {
+ final Class<?> beanClass = TypeUtils.getRawType(type, null);
+ return beanClass == null ? null
+ : (BeanD) validatorContext.getDescriptorManager().getBeanDescriptor(beanClass);
+ }
+ }
+
+ private static class FindDescriptor implements PathNavigation.Callback<ElementD<?, ?>> {
+ private final ApacheFactoryContext validatorContext;
+ Step current;
+
+ FindDescriptor(ApacheFactoryContext validatorContext, Class<?> beanClass) {
+ this.validatorContext = validatorContext;
+ this.current = new DescriptorWrapper(validatorContext.getDescriptorManager().getBeanDescriptor(beanClass));
+ }
+
+ @Override
+ public void handleProperty(String name) {
+ final ElementDescriptor element = current.element();
+ final BeanD bean;
+ if (element instanceof BeanD) {
+ bean = (BeanD) element;
+ } else {
+ bean = (BeanD) validatorContext.getDescriptorManager().getBeanDescriptor(element.getElementClass());
+ }
+ final PropertyDescriptor property = bean.getProperty(name);
+ Exceptions.raiseIf(property == null, IllegalArgumentException::new, "Unknown property %s of %s", name,
+ bean.getElementClass());
+ current = new DescriptorWrapper(property);
+ }
+
+ @Override
+ public void handleIndexOrKey(String value) {
+ handleGenericInIterable();
+ }
+
+ @Override
+ public void handleGenericInIterable() {
+ final ElementDescriptor desc = current.element();
+ if (desc instanceof CascadableContainerD<?, ?>) {
+ final Step containerElement = handleContainerElement((CascadableContainerD<?, ?>) desc);
+ if (containerElement != null) {
+ current = containerElement;
+ return;
+ }
+ }
+ current = handleElementByType(current.type());
+ }
+
+ private Step handleContainerElement(CascadableContainerD<?, ?> desc) {
+ final Set<ContainerElementTypeDescriptor> containerElements = desc.getConstrainedContainerElementTypes();
+ if (containerElements.isEmpty()) {
+ return null;
+ }
+ final ContainerElementTypeDescriptor element;
+ if (containerElements.size() == 1) {
+ element = containerElements.iterator().next();
+ } else {
+ final Predicate<ContainerElementKey> wellKnown =
+ k -> k.represents(MAP_VALUE) || k.represents(ITERABLE_ELEMENT);
+
+ final Optional<ContainerElementTypeD> found =
+ containerElements.stream().map(ContainerElementTypeD.class::cast)
+ .filter(d -> d.getKey().getAssignableKeys().stream().anyMatch(wellKnown)).findFirst();
+
+ if (!found.isPresent()) {
+ return null;
+ }
+ element = found.get();
+ }
+ return new DescriptorWrapper(element);
+ }
+
+ private Step handleElementByType(Type type) {
+ Type elementType;
+
+ if (TypeUtils.isArrayType(type)) {
+ elementType = TypeUtils.getArrayComponentType(type);
+ } else if (TypeUtils.isAssignable(type, Map.class)) {
+ elementType =
+ Optional.ofNullable(TypeUtils.getTypeArguments(type, Map.class).get(MAP_VALUE)).orElse(MAP_VALUE);
+ } else if (TypeUtils.isAssignable(type, Iterable.class)) {
+ elementType =
+ Optional.ofNullable(TypeUtils.getTypeArguments(type, Iterable.class).get(ITERABLE_ELEMENT))
+ .orElse(ITERABLE_ELEMENT);
+ } else {
+ elementType = null;
+ }
+ Exceptions.raiseIf(elementType == null, IllegalArgumentException::new,
+ "Unable to resolve element type of %s", type);
+
+ return new TypeWrapper(validatorContext, elementType);
+ }
+
+ @Override
+ public ElementD<?, ?> result() {
+ return current.element();
+ }
+ }
+
+ private static class WalkGraph extends PathNavigation.CallbackProcedure {
+ final ApacheFactoryContext validatorContext;
+ final PathImpl.Builder pathBuilder;
+ final FindDescriptor findDescriptor;
+ final ObjectWrapper<Object> value;
+ final BiConsumer<PathImpl, Object> recordLeaf;
+
+ WalkGraph(ApacheFactoryContext validatorContext, PathImpl.Builder pathBuilder, FindDescriptor findDescriptor,
+ ObjectWrapper<Object> value, BiConsumer<PathImpl, Object> recordLeaf) {
+ this.validatorContext = validatorContext;
+ this.pathBuilder = pathBuilder;
+ this.findDescriptor = findDescriptor;
+ this.value = value;
+ this.recordLeaf = recordLeaf;
+ }
+
+ @Override
+ public void handleProperty(String name) {
+ final PathImpl p = PathImpl.copy(pathBuilder.result());
+ pathBuilder.handleProperty(name);
+ if (value.optional().isPresent()) {
+ recordLeaf.accept(p, value.get());
+
+ findDescriptor.handleProperty(name);
+
+ final PropertyD<?> propertyD =
+ ComposedD.unwrap(findDescriptor.current.element(), PropertyD.class).findFirst().get();
+ try {
+ value.accept(propertyD.getValue(value.get()));
+ } catch (Exception e) {
+ Exceptions.raise(IllegalStateException::new, e, "Unable to get value of property %s",
+ propertyD.getPropertyName());
+ }
+ }
+ }
+
+ @Override
+ public void handleIndexOrKey(final String indexOrKey) {
+ pathBuilder.handleIndexOrKey(indexOrKey);
+ findDescriptor.handleIndexOrKey(indexOrKey);
+ if (value.optional().isPresent()) {
+ ElementDescriptor element = findDescriptor.current.element();
+ if (element instanceof ContainerElementTypeD) {
+ value.accept(handleContainer(value.get(), ((ContainerElementTypeD) element).getKey(), indexOrKey));
+ } else {
+ value.accept(handleBasic(value.get(), indexOrKey));
+
+ if (element == null && value.optional().isPresent()) {
+ // no generic info available at some previous index level; fall back to runtime type of value
+ // and repair structure of findDescriptor:
+ findDescriptor.current = new TypeWrapper(validatorContext, value.get().getClass());
+ element = findDescriptor.current.element();
+ }
+ if (element instanceof BeanDescriptor) {
+ recordLeaf.accept(PathImpl.copy(pathBuilder.result()), value.get());
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private Object handleContainer(Object o, ContainerElementKey key, String indexOrKey) {
+ @SuppressWarnings("rawtypes")
+ final ValueExtractor valueExtractor = validatorContext.getValueExtractors().find(key);
+
+ final ObjectWrapper<Object> result = new ObjectWrapper<>();
+ valueExtractor.extractValues(o, new ValueReceiver() {
+
+ @Override
+ public void indexedValue(String nodeName, int index, Object object) {
+ if (Integer.toString(index).equals(indexOrKey)) {
+ result.accept(object);
+ }
+ }
+
+ @Override
+ public void iterableValue(String nodeName, Object object) {
+ // ?
+ result.accept(object);
+ }
+
+ @Override
+ public void keyedValue(String nodeName, Object key, Object object) {
+ if (String.valueOf(key).equals(indexOrKey)) {
+ result.accept(object);
+ }
+ }
+
+ @Override
+ public void value(String nodeName, Object object) {
+ // ?
+ result.accept(object);
+ }
+ });
+ return result.get();
+ }
+
+ private Object handleBasic(Object o, String indexOrKey) {
+ if (Map.class.isInstance(o)) {
+ for (Map.Entry<?, ?> e : ((Map<?, ?>) o).entrySet()) {
+ if (String.valueOf(e.getKey()).equals(indexOrKey)) {
+ return e.getValue();
+ }
+ }
+ } else {
+ try {
+ final int index = Integer.parseInt(indexOrKey);
+ Exceptions.raiseIf(index < 0, IllegalArgumentException::new, "Invalid index %d", index);
+ if (o != null && TypeUtils.isArrayType(o.getClass())) {
+ if (Array.getLength(o) > index) {
+ return Array.get(o, index);
+ }
+ } else if (List.class.isInstance(o)) {
+ final List<?> l = (List<?>) o;
+ if (l.size() > index) {
+ return l.get(index);
+ }
+ } else if (Iterable.class.isInstance(o)) {
+ int i = -1;
+ for (Object e : (Iterable<?>) o) {
+ if (++i == index) {
+ return e;
+ }
+ }
+ }
+ } catch (NumberFormatException e) {
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void handleGenericInIterable() {
+ throw new UnsupportedOperationException("Cannot resolve generic inIterable against actual object graph");
+ }
+ }
+
+ class LeafFrame extends BeanFrame {
+
+ LeafFrame(GraphContext context) {
+ super(context);
+ }
+
+ @Override
+ protected ValidationJob<T>.Frame<?> propertyFrame(PropertyD<?> d, GraphContext context) {
+ return new PropertyFrame<>(this, d, context);
+ }
+ }
+
+ class PropertyFrame<D extends ElementD<?, ?> & CascadableDescriptor & ContainerDescriptor> extends SproutFrame<D> {
+
+ PropertyFrame(ValidationJob<T>.Frame<?> parent, D descriptor, GraphContext context) {
+ super(parent, descriptor, context);
+ }
+
+ @Override
+ void recurse(Class<?> group, Consumer<ConstraintViolation<T>> sink) {
+ if (cascade) {
+ super.recurse(group, sink);
+ }
+ }
+ }
+
+ private static final TypeVariable<?> MAP_VALUE = Map.class.getTypeParameters()[1];
+ private static final TypeVariable<?> ITERABLE_ELEMENT = Iterable.class.getTypeParameters()[0];
+
+ private final Strategy<T> strategy;
+ private final Class<T> rootBeanClass;
+ private final PathImpl propertyPath;
+ private final T rootBean;
+ private ElementD<?, ?> descriptor;
+ private boolean cascade;
+
+ private ValidateProperty(Strategy<T> strategy, ApacheFactoryContext validatorContext, Class<T> rootBeanClass,
+ String property, Class<?>[] groups) {
+ super(validatorContext, groups);
+
+ Exceptions.raiseIf(StringUtils.isBlank(property), IllegalArgumentException::new,
+ "property cannot be null/empty/blank");
+
+ this.strategy = strategy;
+ this.rootBeanClass = Validate.notNull(rootBeanClass, IllegalArgumentException::new, "rootBeanClass");
+
+ final PathImpl.Builder pathBuilder = new PathImpl.Builder();
+ final FindDescriptor findDescriptor = new FindDescriptor(validatorContext, rootBeanClass);
+
+ PathNavigation.navigate(property, strategy.callback(pathBuilder, findDescriptor));
+
+ this.propertyPath = pathBuilder.result();
+ this.descriptor = findDescriptor.result();
+ this.rootBean = strategy.getRootBean();
+ }
+
+ ValidateProperty(ApacheFactoryContext validatorContext, Class<T> rootBeanClass, String property, Object value,
+ Class<?>[] groups) {
+ this(new ForPropertyValue<>(value), validatorContext, rootBeanClass, property, groups);
+ if (descriptor == null) {
+ // should only occur when the root class is raw
+ descriptor = (ElementD<?, ?>) validatorContext.getDescriptorManager()
+ .getBeanDescriptor(value == null ? Object.class : value.getClass());
+ } else {
+ final Class<?> propertyType = descriptor.getElementClass();
+ Exceptions.raiseUnless(TypeUtils.isInstance(value, propertyType), IllegalArgumentException::new,
+ "%s is not an instance of %s", value, propertyType);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ ValidateProperty(ApacheFactoryContext validatorContext, T bean, String property, Class<?>[] groups)
+ throws Exception {
+ this(new ForBeanProperty<>(validatorContext, bean), validatorContext,
+ (Class<T>) Validate.notNull(bean, IllegalArgumentException::new, "bean").getClass(), property, groups);
+
+ Exceptions.raiseIf(descriptor == null, IllegalArgumentException::new,
+ "Could not resolve property name/path: %s", property);
+ }
+
+ public ValidateProperty<T> cascade(boolean cascade) {
+ this.cascade = cascade;
+ return this;
+ }
+
+ @Override
+ protected Frame<?> computeBaseFrame() {
+ // TODO assign bean as its own property and figure out what to do
+
+ return strategy.frame(this, propertyPath);
+ }
+
+ @Override
+ protected Class<T> getRootBeanClass() {
+ return rootBeanClass;
+ }
+
+ @Override
+ ConstraintViolationImpl<T> createViolation(String messageTemplate, ConstraintValidatorContextImpl<T> context,
+ Path propertyPath) {
+ final String message = validatorContext.getMessageInterpolator().interpolate(messageTemplate, context);
+
+ return new ConstraintViolationImpl<>(messageTemplate, message, rootBean, context.getFrame().getBean(),
+ propertyPath, context.getFrame().context.getValue(), context.getConstraintDescriptor(), rootBeanClass,
+ context.getConstraintDescriptor().unwrap(ConstraintD.class).getDeclaredOn(), null, null);
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java
new file mode 100644
index 0000000..e71e7ae
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java
@@ -0,0 +1,126 @@
+package org.apache.bval.jsr.job;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+
+import javax.validation.Path;
+
+import org.apache.bval.jsr.ApacheFactoryContext;
+import org.apache.bval.jsr.ConstraintViolationImpl;
+import org.apache.bval.jsr.GraphContext;
+import org.apache.bval.jsr.descriptor.ConstraintD;
+import org.apache.bval.jsr.descriptor.ExecutableD;
+import org.apache.bval.jsr.descriptor.ReturnValueD;
+import org.apache.bval.jsr.metadata.Metas;
+import org.apache.bval.jsr.util.NodeImpl;
+import org.apache.bval.jsr.util.PathImpl;
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.TypeUtils;
+
+public abstract class ValidateReturnValue<E extends Executable, T> extends ValidationJob<T> {
+ public static class ForMethod<T> extends ValidateReturnValue<Method, T> {
+ private final T object;
+
+ ForMethod(ApacheFactoryContext validatorContext, T object, Method method, Object returnValue,
+ Class<?>[] groups) {
+ super(validatorContext,
+ new Metas.ForMethod(Validate.notNull(method, IllegalArgumentException::new, "method")), returnValue,
+ groups);
+ this.object = Validate.notNull(object, IllegalArgumentException::new, "object");
+ }
+
+ @Override
+ protected T getRootBean() {
+ return object;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected Class<T> getRootBeanClass() {
+ return (Class<T>) object.getClass();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected ExecutableD<Method, ?, ?> describe() {
+ return (ExecutableD<Method, ?, ?>) validatorContext.getDescriptorManager()
+ .getBeanDescriptor(object.getClass())
+ .getConstraintsForMethod(executable.getName(), executable.getParameterTypes());
+ }
+ }
+
+ public static class ForConstructor<T> extends ValidateReturnValue<Constructor<?>, T> {
+
+ ForConstructor(ApacheFactoryContext validatorContext, Constructor<? extends T> ctor, Object returnValue,
+ Class<?>[] groups) {
+ super(validatorContext,
+ new Metas.ForConstructor(Validate.notNull(ctor, IllegalArgumentException::new, "ctor")), returnValue,
+ groups);
+ }
+
+ @Override
+ protected T getRootBean() {
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected Class<T> getRootBeanClass() {
+ return (Class<T>) executable.getDeclaringClass();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected ExecutableD<Constructor<T>, ?, ?> describe() {
+ return (ExecutableD<Constructor<T>, ?, ?>) validatorContext.getDescriptorManager()
+ .getBeanDescriptor(executable.getDeclaringClass())
+ .getConstraintsForConstructor(executable.getParameterTypes());
+ }
+ }
+
+ protected final E executable;
+ private final Object returnValue;
+
+ ValidateReturnValue(ApacheFactoryContext validatorContext, Metas<E> meta, Object returnValue, Class<?>[] groups) {
+ super(validatorContext, groups);
+
+ final Type type = Validate.notNull(meta, "meta").getType();
+ Exceptions.raiseUnless(TypeUtils.isInstance(returnValue, type), IllegalArgumentException::new,
+ "%s is not an instance of %s", returnValue, type);
+
+ this.executable = meta.getHost();
+ this.returnValue = returnValue;
+ }
+
+ @Override
+ protected Frame<?> computeBaseFrame() {
+ final PathImpl path = PathImpl.create();
+ path.addNode(new NodeImpl.ReturnValueNodeImpl());
+
+ return new SproutFrame<ReturnValueD<?, ?>>((ReturnValueD<?, ?>) describe().getReturnValueDescriptor(),
+ new GraphContext(validatorContext, path, returnValue)) {
+ @Override
+ Object getBean() {
+ return getRootBean();
+ }
+ };
+ }
+
+ @Override
+ ConstraintViolationImpl<T> createViolation(String messageTemplate, ConstraintValidatorContextImpl<T> context,
+ Path propertyPath) {
+
+ final String message = validatorContext.getMessageInterpolator().interpolate(messageTemplate, context);
+
+ return new ConstraintViolationImpl<>(messageTemplate, message, getRootBean(), context.getFrame().getBean(),
+ propertyPath, context.getFrame().context.getValue(), context.getConstraintDescriptor(), getRootBeanClass(),
+ context.getConstraintDescriptor().unwrap(ConstraintD.class).getDeclaredOn(), returnValue, null);
+ }
+
+ protected abstract ExecutableD<?, ?, ?> describe();
+
+ protected abstract T getRootBean();
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java
new file mode 100644
index 0000000..9221184
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java
@@ -0,0 +1,380 @@
+/*
+ * 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.job;
+
+import java.lang.reflect.Array;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintViolation;
+import javax.validation.Path;
+import javax.validation.TraversableResolver;
+import javax.validation.UnexpectedTypeException;
+import javax.validation.ValidationException;
+import javax.validation.groups.Default;
+import javax.validation.metadata.CascadableDescriptor;
+import javax.validation.metadata.ContainerDescriptor;
+import javax.validation.metadata.ElementDescriptor.ConstraintFinder;
+import javax.validation.metadata.PropertyDescriptor;
+
+import org.apache.bval.jsr.ApacheFactoryContext;
+import org.apache.bval.jsr.ConstraintViolationImpl;
+import org.apache.bval.jsr.GraphContext;
+import org.apache.bval.jsr.descriptor.BeanD;
+import org.apache.bval.jsr.descriptor.CascadableContainerD;
+import org.apache.bval.jsr.descriptor.ComposedD;
+import org.apache.bval.jsr.descriptor.ConstraintD;
+import org.apache.bval.jsr.descriptor.ElementD;
+import org.apache.bval.jsr.descriptor.PropertyD;
+import org.apache.bval.jsr.groups.Group;
+import org.apache.bval.jsr.groups.Groups;
+import org.apache.bval.jsr.util.NodeImpl;
+import org.apache.bval.jsr.util.PathImpl;
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.Lazy;
+import org.apache.bval.util.Validate;
+
+public abstract class ValidationJob<T> {
+
+ public abstract class Frame<D extends ElementD<?, ?>> {
+ protected final Frame<?> parent;
+ protected final D descriptor;
+ protected final GraphContext context;
+
+ protected Frame(Frame<?> parent, D descriptor, GraphContext context) {
+ super();
+ this.parent = parent;
+ this.descriptor = Validate.notNull(descriptor, "descriptor");
+ this.context = Validate.notNull(context, "context");
+ }
+
+ final ValidationJob<T> getJob() {
+ return ValidationJob.this;
+ }
+
+ final void process(Class<?> group, Consumer<ConstraintViolation<T>> sink) {
+ Validate.notNull(sink, "sink");
+
+ each(expand(group), this::validateDescriptorConstraints, sink);
+ recurse(group, sink);
+ }
+
+ abstract void recurse(Class<?> group, Consumer<ConstraintViolation<T>> sink);
+
+ abstract Object getBean();
+
+ protected void validateDescriptorConstraints(Class<?> group, Consumer<ConstraintViolation<T>> sink) {
+ constraintsFrom(descriptor.findConstraints().unorderedAndMatchingGroups(group))
+ .forEach(c -> validate(c, sink));
+ }
+
+ @SuppressWarnings("unchecked")
+ private Stream<ConstraintD<?>> constraintsFrom(ConstraintFinder finder) {
+ // our ConstraintFinder implementation is a Stream supplier; reference without exposing it beyond its
+ // package:
+ if (finder instanceof Supplier<?>) {
+ return (Stream<ConstraintD<?>>) ((Supplier<?>) finder).get();
+ }
+ return finder.getConstraintDescriptors().stream().map(ConstraintD.class::cast);
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ private boolean validate(ConstraintD<?> constraint, Consumer<ConstraintViolation<T>> sink) {
+ if (!validatedPathsByConstraint
+ .computeIfAbsent(constraint, k -> new ConcurrentSkipListSet<>(COMPARE_TO_STRING))
+ .add(context.getPath())) {
+ // seen, ignore:
+ return true;
+ }
+ final ConstraintValidatorContextImpl<T> constraintValidatorContext =
+ new ConstraintValidatorContextImpl<>(this, constraint);
+
+ final ConstraintValidator constraintValidator = getConstraintValidator(constraint);
+
+ final boolean valid;
+ if (constraintValidator == null) {
+ // null validator without exception implies composition:
+ valid = true;
+ } else {
+ constraintValidator.initialize(constraint.getAnnotation());
+ valid = constraintValidator.isValid(context.getValue(), constraintValidatorContext);
+ }
+ if (!valid) {
+ constraintValidatorContext.getRequiredViolations().forEach(sink);
+ }
+ if (valid || !constraint.isReportAsSingleViolation()) {
+ final boolean compositionValid = validateComposed(constraint, sink);
+
+ if (!compositionValid) {
+ if (valid && constraint.isReportAsSingleViolation()) {
+ constraintValidatorContext.getRequiredViolations().forEach(sink);
+ }
+ return false;
+ }
+ }
+ return valid;
+ }
+
+ private boolean validateComposed(ConstraintD<?> constraint, Consumer<ConstraintViolation<T>> sink) {
+ if (constraint.getComposingConstraints().isEmpty()) {
+ return true;
+ }
+ final Consumer<ConstraintViolation<T>> effectiveSink = constraint.isReportAsSingleViolation() ? cv -> {
+ } : sink;
+
+ // collect validation results to set of Boolean, ensuring all are evaluated:
+ final Set<Boolean> results = constraint.getComposingConstraints().stream().map(ConstraintD.class::cast)
+ .map(c -> validate(c, effectiveSink)).collect(Collectors.toSet());
+
+ return Collections.singleton(Boolean.TRUE).equals(results);
+ }
+
+ @SuppressWarnings({ "rawtypes" })
+ private ConstraintValidator getConstraintValidator(ConstraintD<?> constraint) {
+ final Class<? extends ConstraintValidator> constraintValidatorClass =
+ constraint.getConstraintValidatorClass();
+
+ if (constraintValidatorClass == null) {
+ Exceptions.raiseIf(constraint.getComposingConstraints().isEmpty(), UnexpectedTypeException::new,
+ "No %s type located for non-composed constraint %s", ConstraintValidator.class.getSimpleName(),
+ constraint);
+ return null;
+ }
+ ConstraintValidator constraintValidator = null;
+ Exception cause = null;
+ try {
+ constraintValidator =
+ validatorContext.getConstraintValidatorFactory().getInstance(constraintValidatorClass);
+ } catch (Exception e) {
+ cause = e;
+ }
+ Exceptions.raiseIf(constraintValidator == null, ValidationException::new, cause,
+ "Unable to get %s instance from %s", constraintValidatorClass.getName(),
+ validatorContext.getConstraintValidatorFactory());
+
+ return constraintValidator;
+ }
+
+ protected Stream<Class<?>> expand(Class<?> group) {
+ if (Default.class.equals(group)) {
+ final List<Class<?>> groupSequence = descriptor.getGroupSequence();
+ if (groupSequence != null) {
+ return groupSequence.stream();
+ }
+ }
+ return Stream.of(group);
+ }
+ }
+
+ public class BeanFrame extends Frame<BeanD> {
+
+ BeanFrame(GraphContext context) {
+ this(null, context);
+ }
+
+ BeanFrame(Frame<?> parent, GraphContext context) {
+ super(parent, getBeanDescriptor(context.getValue()), context);
+ }
+
+ @Override
+ void recurse(Class<?> group, Consumer<ConstraintViolation<T>> sink) {
+ // bean frame has to do some convoluted things to properly handle groups and recursion; skipping
+ // frame#process() on properties:
+ final List<Frame<?>> propertyFrames = propertyFrames();
+
+ each(expand(group), (g, s) -> propertyFrames.forEach(f -> f.validateDescriptorConstraints(g, s)), sink);
+ propertyFrames.forEach(f -> f.recurse(group, sink));
+ }
+
+ protected Frame<?> propertyFrame(PropertyD<?> d, GraphContext context) {
+ return new SproutFrame<>(this, d, context);
+ }
+
+ @Override
+ Object getBean() {
+ return context.getValue();
+ }
+
+ private List<Frame<?>> propertyFrames() {
+ final Stream<PropertyD<?>> properties = descriptor.getConstrainedProperties().stream()
+ .flatMap(d -> ComposedD.unwrap(d, PropertyD.class)).map(d -> (PropertyD<?>) d);
+
+ final TraversableResolver traversableResolver = validatorContext.getTraversableResolver();
+
+ final Stream<PropertyD<?>> reachableProperties =
+ properties.filter(d -> traversableResolver.isReachable(context.getValue(),
+ new NodeImpl.PropertyNodeImpl(d.getPropertyName()), getRootBeanClass(), context.getPath(),
+ d.getElementType()));
+
+ return reachableProperties.flatMap(
+ d -> d.read(context).filter(context -> !context.isRecursive()).map(child -> propertyFrame(d, child)))
+ .collect(Collectors.toList());
+ }
+ }
+
+ public class SproutFrame<D extends ElementD<?, ?> & CascadableDescriptor & ContainerDescriptor> extends Frame<D> {
+
+ public SproutFrame(D descriptor, GraphContext context) {
+ this(null, descriptor, context);
+ }
+
+ public SproutFrame(Frame<?> parent, D descriptor, GraphContext context) {
+ super(parent, descriptor, context);
+ }
+
+ @Override
+ void recurse(Class<?> group, Consumer<ConstraintViolation<T>> sink) {
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ final Stream<CascadableContainerD<?, ?>> containerElements =
+ descriptor.getConstrainedContainerElementTypes().stream()
+ .flatMap(d -> ComposedD.unwrap(d, (Class) CascadableContainerD.class));
+
+ containerElements.flatMap(d -> d.read(context).map(child -> new SproutFrame<>(this, d, child)))
+ .forEach(f -> f.process(group, sink));
+
+ if (!descriptor.isCascaded()) {
+ return;
+ }
+ if (descriptor instanceof PropertyDescriptor) {
+ final TraversableResolver traversableResolver = validatorContext.getTraversableResolver();
+
+ final PathImpl pathToTraversableObject = PathImpl.copy(context.getPath());
+ final NodeImpl traversableProperty = pathToTraversableObject.removeLeafNode();
+
+ if (!traversableResolver.isCascadable(context.getValue(), traversableProperty, getRootBeanClass(),
+ pathToTraversableObject, ((PropertyD<?>) descriptor).getElementType())) {
+ return;
+ }
+ }
+ multiplex().filter(context -> context.getValue() != null).map(context -> new BeanFrame(this, context))
+ .forEach(b -> b.process(group, sink));
+ }
+
+ private Stream<GraphContext> multiplex() {
+ final Object value = context.getValue();
+ if (value == null) {
+ return Stream.empty();
+ }
+ if (Map.class.isInstance(value)) {
+ return ((Map<?, ?>) value).entrySet().stream()
+ .map(e -> context.child(NodeImpl.atKey(e.getKey()), e.getValue()));
+ }
+ if (value.getClass().isArray()) {
+ return IntStream.range(0, Array.getLength(value))
+ .mapToObj(i -> context.child(NodeImpl.atIndex(i), Array.get(value, i)));
+ }
+ if (List.class.isInstance(value)) {
+ final List<?> l = (List<?>) value;
+ return IntStream.range(0, l.size()).mapToObj(i -> context.child(NodeImpl.atIndex(i), l.get(i)));
+ }
+ if (Iterable.class.isInstance(value)) {
+ final Stream.Builder<Object> b = Stream.builder();
+ ((Iterable<?>) value).forEach(b);
+ return b.build().map(o -> context.child(NodeImpl.atIndex(null), o));
+ }
+ return Stream.of(context);
+ }
+
+ @Override
+ Object getBean() {
+ return Optional.ofNullable(parent).map(Frame::getBean).orElse(null);
+ }
+ }
+
+ private static final Comparator<Path> COMPARE_TO_STRING = Comparator.comparing(Object::toString);
+
+ protected final ApacheFactoryContext validatorContext;
+
+ private final Groups groups;
+ private final Lazy<Set<ConstraintViolation<T>>> results = new Lazy<>(LinkedHashSet::new);
+
+ private ConcurrentMap<ConstraintD<?>, Set<Path>> validatedPathsByConstraint;
+
+ ValidationJob(ApacheFactoryContext validatorContext, Class<?>[] groups) {
+ super();
+ this.validatorContext = Validate.notNull(validatorContext, "validatorContext");
+ this.groups = validatorContext.getGroupsComputer().computeGroups(groups);
+ }
+
+ public final Set<ConstraintViolation<T>> getResults() {
+ if (results.optional().isPresent()) {
+ return results.get();
+ }
+ final Frame<?> baseFrame = computeBaseFrame();
+ Validate.validState(baseFrame != null, "%s computed null baseFrame", getClass().getName());
+
+ final Consumer<ConstraintViolation<T>> sink = results.consumer(Set::add);
+
+ validatedPathsByConstraint = new ConcurrentHashMap<>();
+
+ try {
+ groups.getGroups().stream().map(Group::getGroup).forEach(g -> baseFrame.process(g, sink));
+
+ sequences: for (List<Group> seq : groups.getSequences()) {
+ final boolean proceed = each(seq.stream().map(Group::getGroup), baseFrame::process, sink);
+ if (!proceed) {
+ break sequences;
+ }
+ }
+ } finally {
+ validatedPathsByConstraint = null;
+ }
+ return results.optional().map(Collections::unmodifiableSet).orElse(Collections.emptySet());
+ }
+
+ private boolean each(Stream<Class<?>> groupSequence, BiConsumer<Class<?>, Consumer<ConstraintViolation<T>>> closure,
+ Consumer<ConstraintViolation<T>> sink) {
+ final Lazy<Set<ConstraintViolation<T>>> sequenceViolations = new Lazy<>(LinkedHashSet::new);
+ for (Class<?> g : (Iterable<Class<?>>) () -> groupSequence.iterator()) {
+ closure.accept(g, sequenceViolations.consumer(Set::add));
+ if (sequenceViolations.optional().isPresent()) {
+ sequenceViolations.get().forEach(sink);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private BeanD getBeanDescriptor(Object bean) {
+ return (BeanD) validatorContext.getFactory().getDescriptorManager()
+ .getBeanDescriptor(Validate.notNull(bean, "bean").getClass());
+ }
+
+ abstract ConstraintViolationImpl<T> createViolation(String messageTemplate,
+ ConstraintValidatorContextImpl<T> context, Path propertyPath);
+
+ protected abstract Frame<?> computeBaseFrame();
+
+ protected abstract Class<T> getRootBeanClass();
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJobFactory.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJobFactory.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJobFactory.java
new file mode 100644
index 0000000..2a23192
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJobFactory.java
@@ -0,0 +1,112 @@
+/*
+ * 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.job;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+import javax.validation.ValidationException;
+import javax.validation.Validator;
+import javax.validation.executable.ExecutableValidator;
+
+import org.apache.bval.jsr.ApacheFactoryContext;
+import org.apache.bval.util.Validate;
+
+/**
+ * Creates {@link ValidationJob} instances.
+ */
+public class ValidationJobFactory {
+
+ private final ApacheFactoryContext validatorContext;
+
+ /**
+ * Create a new {@link ValidationJobFactory}.
+ *
+ * @param validatorContext
+ */
+ public ValidationJobFactory(ApacheFactoryContext validatorContext) {
+ super();
+ this.validatorContext = Validate.notNull(validatorContext, "validatorContext");
+ }
+
+ /**
+ * @see Validator#validate(Object, Class...)
+ */
+ public <T> ValidateBean<T> validateBean(T bean, Class<?>... groups) {
+ return new ValidateBean<>(validatorContext, bean, groups);
+ }
+
+ /**
+ * @see Validator#validateProperty(Object, String, Class...)
+ */
+ public <T> ValidateProperty<T> validateProperty(T bean, String property, Class<?>... groups) {
+ try {
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ final ValidateProperty<T> result = new ValidateProperty(validatorContext, bean, property, groups);
+ return result;
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ValidationException(e);
+ }
+ }
+
+ /**
+ * @see Validator#validateValue(Class, String, Object, Class...)
+ */
+ public <T> ValidateProperty<T> validateValue(Class<T> rootBeanClass, String property, Object value,
+ Class<?>... groups) {
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ final ValidateProperty<T> result =
+ new ValidateProperty(validatorContext, rootBeanClass, property, value, groups);
+ return result;
+ }
+
+ /**
+ * @see ExecutableValidator#validateParameters(Object, Method, Object[], Class...)
+ */
+ public <T> ValidateParameters.ForMethod<T> validateParameters(T object, Method method, Object[] parameterValues,
+ Class<?>... groups) {
+ return new ValidateParameters.ForMethod<T>(validatorContext, object, method, parameterValues, groups);
+ }
+
+ /**
+ * @see ExecutableValidator#validateReturnValue(Object, Method, Object, Class...)
+ */
+ public <T> ValidateReturnValue.ForMethod<T> validateReturnValue(T object, Method method, Object returnValue,
+ Class<?>... groups) {
+ return new ValidateReturnValue.ForMethod<>(validatorContext, object, method, returnValue, groups);
+ }
+
+ /**
+ * @see ExecutableValidator#validateConstructorParameters(Constructor, Object[], Class...)
+ */
+ public <T> ValidateParameters.ForConstructor<T> validateConstructorParameters(Constructor<? extends T> constructor,
+ Object[] parameterValues, Class<?>... groups) {
+ return new ValidateParameters.ForConstructor<T>(validatorContext, constructor, parameterValues, groups);
+ }
+
+ /**
+ * @see ExecutableValidator#validateConstructorReturnValue(Constructor, Object, Class...)
+ */
+ public <T> ValidateReturnValue.ForConstructor<T> validateConstructorReturnValue(
+ Constructor<? extends T> constructor, T createdObject, Class<?>... groups) {
+ return new ValidateReturnValue.ForConstructor<T>(validatorContext, constructor, createdObject, groups);
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationBehavior.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationBehavior.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationBehavior.java
new file mode 100644
index 0000000..56ed4f0
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationBehavior.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bval.jsr.metadata;
+
+import org.apache.bval.jsr.metadata.MetadataBuilder;
+
+/**
+ * Models the behavior of a {@link MetadataBuilder} with regard to bean validation annotations.
+ *
+ * @see DualBuilder
+ */
+public enum AnnotationBehavior implements AnnotationBehaviorMergeStrategy {
+ //@formatter:off
+ INCLUDE, EXCLUDE, ABSTAIN;
+ //@formatter:on
+
+ @Override
+ public AnnotationBehavior apply(Iterable<? extends HasAnnotationBehavior> t) {
+ return this;
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationBehaviorMergeStrategy.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationBehaviorMergeStrategy.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationBehaviorMergeStrategy.java
new file mode 100644
index 0000000..bfd16c5
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationBehaviorMergeStrategy.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bval.jsr.metadata;
+
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.bval.util.Validate;
+
+@FunctionalInterface
+public interface AnnotationBehaviorMergeStrategy
+ extends Function<Iterable<? extends HasAnnotationBehavior>, AnnotationBehavior> {
+
+ public static AnnotationBehaviorMergeStrategy first() {
+ return coll -> {
+ final Iterator<? extends HasAnnotationBehavior> iterator = coll.iterator();
+ return iterator.hasNext() ? iterator.next().getAnnotationBehavior() : AnnotationBehavior.ABSTAIN;
+ };
+ }
+
+ public static AnnotationBehaviorMergeStrategy consensus() {
+ return coll -> {
+ final Stream.Builder<HasAnnotationBehavior> b = Stream.builder();
+ coll.forEach(b);
+ final Set<AnnotationBehavior> annotationBehaviors =
+ b.build().map(HasAnnotationBehavior::getAnnotationBehavior).filter(Objects::nonNull)
+ .filter(Predicate.isEqual(AnnotationBehavior.ABSTAIN).negate())
+ .collect(Collectors.toCollection(() -> EnumSet.noneOf(AnnotationBehavior.class)));
+ Validate.validState(annotationBehaviors.size() <= 1,
+ "Conflicting annotation inclusion behaviors found among %s", coll);
+ return annotationBehaviors.isEmpty() ? AnnotationBehavior.ABSTAIN : annotationBehaviors.iterator().next();
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationDeclaredValidatorMappingProvider.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationDeclaredValidatorMappingProvider.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationDeclaredValidatorMappingProvider.java
new file mode 100644
index 0000000..b2126ac
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/AnnotationDeclaredValidatorMappingProvider.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bval.jsr.metadata;
+
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.validation.Constraint;
+import javax.validation.ConstraintValidator;
+
+import org.apache.bval.util.Validate;
+
+public class AnnotationDeclaredValidatorMappingProvider extends ValidatorMappingProvider {
+ public static final AnnotationDeclaredValidatorMappingProvider INSTANCE =
+ new AnnotationDeclaredValidatorMappingProvider();
+
+ @Override
+ protected <A extends Annotation> ValidatorMapping<A> doGetValidatorMapping(Class<A> constraintType) {
+ Validate.notNull(constraintType);
+ Validate.isTrue(constraintType.isAnnotationPresent(Constraint.class),
+ "%s does not represent a validation constraint", constraintType);
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ final List<Class<? extends ConstraintValidator<A, ?>>> validatorTypes =
+ (List) Arrays.asList(constraintType.getAnnotation(Constraint.class).validatedBy());
+ return new ValidatorMapping<>("@Constraint.validatedBy()", validatorTypes);
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ClassLoadingValidatorMappingProvider.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ClassLoadingValidatorMappingProvider.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ClassLoadingValidatorMappingProvider.java
new file mode 100644
index 0000000..e636a8a
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ClassLoadingValidatorMappingProvider.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.bval.jsr.metadata;
+
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+import org.apache.bval.util.reflection.Reflection;
+import org.apache.commons.weaver.privilizer.Privilizing;
+import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
+
+@Privilizing(@CallTo(Reflection.class))
+public abstract class ClassLoadingValidatorMappingProvider extends ValidatorMappingProvider {
+
+ protected final <T> Stream<Class<? extends T>> load(Stream<String> classNames, Class<T> assignableTo,
+ Consumer<? super ClassNotFoundException> handleException) {
+ return classNames.map(className -> {
+ try {
+ return Reflection.toClass(className, getClassLoader());
+ } catch (ClassNotFoundException e) {
+ handleException.accept(e);
+ return (Class<?>) null;
+ }
+ }).filter(Objects::nonNull).map(c -> (Class<? extends T>) c.asSubclass(assignableTo));
+ }
+
+ protected ClassLoader getClassLoader() {
+ final ClassLoader classloader = Thread.currentThread().getContextClassLoader();
+ return classloader == null ? getClass().getClassLoader() : classloader;
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/CompositeBuilder.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/CompositeBuilder.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/CompositeBuilder.java
new file mode 100644
index 0000000..52a7407
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/CompositeBuilder.java
@@ -0,0 +1,227 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bval.jsr.metadata;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.AnnotatedType;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import javax.validation.metadata.Scope;
+
+import org.apache.bval.jsr.descriptor.GroupConversion;
+import org.apache.bval.jsr.util.ToUnmodifiable;
+import org.apache.bval.util.Validate;
+
+public class CompositeBuilder {
+
+ class Delegator<DELEGATE extends HasAnnotationBehavior> implements HasAnnotationBehavior {
+
+ protected final List<DELEGATE> delegates;
+
+ Delegator(List<DELEGATE> delegates) {
+ this.delegates = Validate.notNull(delegates, "delegates");
+ Validate.isTrue(!delegates.isEmpty(), "no delegates specified");
+ Validate.isTrue(delegates.stream().noneMatch(Objects::isNull), "One or more supplied delegates was null");
+ }
+
+ @Override
+ public AnnotationBehavior getAnnotationBehavior() {
+ return annotationBehaviorStrategy.apply(delegates);
+ }
+
+ <K, D> Map<K, D> merge(Function<DELEGATE, Map<K, D>> toMap, Function<List<D>, D> merge) {
+ final List<Map<K, D>> maps = delegates.stream().map(toMap).collect(Collectors.toList());
+
+ final Function<? super K, ? extends D> valueMapper = k -> {
+ final List<D> mappedDelegates =
+ maps.stream().map(m -> m.get(k)).filter(Objects::nonNull).collect(Collectors.toList());
+ return mappedDelegates.size() == 1 ? mappedDelegates.get(0) : merge.apply(mappedDelegates);
+ };
+
+ return maps.stream().map(Map::keySet).flatMap(Collection::stream).distinct()
+ .collect(Collectors.toMap(Function.identity(), valueMapper));
+ }
+ }
+
+ private class ForBean extends CompositeBuilder.Delegator<MetadataBuilder.ForBean>
+ implements MetadataBuilder.ForBean {
+
+ ForBean(List<MetadataBuilder.ForBean> delegates) {
+ super(delegates);
+ }
+
+ @Override
+ public MetadataBuilder.ForClass getClass(Metas<Class<?>> meta) {
+ return new CompositeBuilder.ForClass(
+ delegates.stream().map(d -> d.getClass(meta)).collect(Collectors.toList()));
+ }
+
+ @Override
+ public Map<String, MetadataBuilder.ForContainer<Field>> getFields(Metas<Class<?>> meta) {
+ return merge(b -> b.getFields(meta), CompositeBuilder.ForContainer::new);
+ }
+
+ @Override
+ public Map<String, MetadataBuilder.ForContainer<Method>> getGetters(Metas<Class<?>> meta) {
+ return merge(b -> b.getGetters(meta), CompositeBuilder.ForContainer::new);
+ }
+
+ @Override
+ public Map<Signature, MetadataBuilder.ForExecutable<Constructor<?>>> getConstructors(Metas<Class<?>> meta) {
+ return merge(b -> b.getConstructors(meta), CompositeBuilder.ForExecutable::new);
+ }
+
+ @Override
+ public Map<Signature, MetadataBuilder.ForExecutable<Method>> getMethods(Metas<Class<?>> meta) {
+ return merge(b -> b.getMethods(meta), CompositeBuilder.ForExecutable::new);
+ }
+ }
+
+ class ForElement<DELEGATE extends MetadataBuilder.ForElement<E>, E extends AnnotatedElement>
+ extends Delegator<DELEGATE> implements MetadataBuilder.ForElement<E> {
+
+ ForElement(List<DELEGATE> delegates) {
+ super(delegates);
+ }
+
+ @Override
+ public Map<Scope, Annotation[]> getConstraintsByScope(Metas<E> meta) {
+ return CompositeBuilder.this.getConstraintsByScope(this, meta);
+ }
+
+ @Override
+ public final Annotation[] getDeclaredConstraints(Metas<E> meta) {
+ return delegates.stream().map(d -> d.getDeclaredConstraints(meta)).flatMap(Stream::of)
+ .toArray(Annotation[]::new);
+ }
+ }
+
+ class ForClass extends ForElement<MetadataBuilder.ForClass, Class<?>> implements MetadataBuilder.ForClass {
+
+ ForClass(List<MetadataBuilder.ForClass> delegates) {
+ super(delegates);
+ }
+
+ @Override
+ public List<Class<?>> getGroupSequence(Metas<Class<?>> meta) {
+ return CompositeBuilder.this.getGroupSequence(this, meta);
+ }
+ }
+
+ private class ForContainer<DELEGATE extends MetadataBuilder.ForContainer<E>, E extends AnnotatedElement>
+ extends CompositeBuilder.ForElement<DELEGATE, E> implements MetadataBuilder.ForContainer<E> {
+
+ ForContainer(List<DELEGATE> delegates) {
+ super(delegates);
+ }
+
+ @Override
+ public final boolean isCascade(Metas<E> meta) {
+ return delegates.stream().anyMatch(d -> d.isCascade(meta));
+ }
+
+ @Override
+ public final Set<GroupConversion> getGroupConversions(Metas<E> meta) {
+ return delegates.stream().map(d -> d.getGroupConversions(meta)).flatMap(Collection::stream)
+ .collect(ToUnmodifiable.set());
+ }
+
+ @Override
+ public final Map<ContainerElementKey, MetadataBuilder.ForContainer<AnnotatedType>> getContainerElementTypes(
+ Metas<E> meta) {
+ return merge(b -> b.getContainerElementTypes(meta), CompositeBuilder.ForContainer::new);
+ }
+ }
+
+ private class ForExecutable<DELEGATE extends MetadataBuilder.ForExecutable<E>, E extends Executable>
+ extends Delegator<DELEGATE> implements MetadataBuilder.ForExecutable<E> {
+
+ ForExecutable(List<DELEGATE> delegates) {
+ super(delegates);
+ }
+
+ @Override
+ public MetadataBuilder.ForContainer<E> getReturnValue(Metas<E> meta) {
+ return new CompositeBuilder.ForContainer<>(
+ delegates.stream().map(d -> d.getReturnValue(meta)).collect(Collectors.toList()));
+ }
+
+ @Override
+ public List<MetadataBuilder.ForContainer<Parameter>> getParameters(Metas<E> meta) {
+ final List<List<MetadataBuilder.ForContainer<Parameter>>> parameterLists =
+ delegates.stream().map(d -> d.getParameters(meta)).collect(Collectors.toList());
+
+ final Set<Integer> parameterCounts = parameterLists.stream().map(List::size).collect(Collectors.toSet());
+ Validate.validState(parameterCounts.size() == 1, "Mismatched parameter counts: %s", parameterCounts);
+
+ return IntStream.range(0, parameterCounts.iterator().next().intValue())
+ .mapToObj(n -> new CompositeBuilder.ForContainer<>(parameterLists.get(n)))
+ .collect(ToUnmodifiable.list());
+ }
+
+ @Override
+ public MetadataBuilder.ForElement<E> getCrossParameter(Metas<E> meta) {
+ return new CompositeBuilder.ForElement<MetadataBuilder.ForElement<E>, E>(
+ delegates.stream().map(d -> d.getCrossParameter(meta)).collect(Collectors.toList()));
+ }
+ }
+
+ public static CompositeBuilder with(AnnotationBehaviorMergeStrategy annotationBehaviorStrategy) {
+ return new CompositeBuilder(annotationBehaviorStrategy);
+ }
+
+ private final AnnotationBehaviorMergeStrategy annotationBehaviorStrategy;
+
+ CompositeBuilder(AnnotationBehaviorMergeStrategy annotationBehaviorMergeStrategy) {
+ super();
+ this.annotationBehaviorStrategy =
+ Validate.notNull(annotationBehaviorMergeStrategy, "annotationBehaviorMergeStrategy");
+ }
+
+ public Collector<MetadataBuilder.ForBean, ?, MetadataBuilder.ForBean> compose() {
+ return Collectors.collectingAndThen(Collectors.toList(), CompositeBuilder.ForBean::new);
+ }
+
+ protected <E extends AnnotatedElement> Map<Scope, Annotation[]> getConstraintsByScope(
+ CompositeBuilder.ForElement<? extends MetadataBuilder.ForElement<E>, E> composite, Metas<E> meta) {
+ return Collections.singletonMap(Scope.LOCAL_ELEMENT, composite.getDeclaredConstraints(meta));
+ }
+
+ protected List<Class<?>> getGroupSequence(CompositeBuilder.ForClass composite, Metas<Class<?>> meta) {
+ final List<List<Class<?>>> groupSequence =
+ composite.delegates.stream().map(d -> d.getGroupSequence(meta)).collect(Collectors.toList());
+ Validate.validState(groupSequence.size() <= 1,
+ "group sequence returned from multiple composite class metadata builders");
+ return groupSequence.isEmpty() ? null : groupSequence.get(0);
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/CompositeValidatorMappingProvider.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/CompositeValidatorMappingProvider.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/CompositeValidatorMappingProvider.java
new file mode 100644
index 0000000..9808f89
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/CompositeValidatorMappingProvider.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bval.jsr.metadata;
+
+import java.lang.annotation.Annotation;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import org.apache.bval.util.Validate;
+
+public class CompositeValidatorMappingProvider extends ValidatorMappingProvider {
+
+ private final List<ValidatorMappingProvider> delegates;
+
+ public CompositeValidatorMappingProvider(List<ValidatorMappingProvider> delegates) {
+ super();
+ this.delegates = Validate.notNull(delegates, "delegates");
+ Validate.isTrue(!delegates.isEmpty(), "no delegates specified");
+ Validate.isTrue(delegates.stream().noneMatch(Objects::isNull), "One or more supplied delegates was null");
+ }
+
+ @Override
+ protected <A extends Annotation> ValidatorMapping<A> doGetValidatorMapping(Class<A> constraintType) {
+ return ValidatorMapping.merge(delegates.stream().map(d -> d.doGetValidatorMapping(constraintType))
+ .filter(Objects::nonNull).collect(Collectors.toList()), AnnotationBehaviorMergeStrategy.consensus());
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ContainerElementKey.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ContainerElementKey.java b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ContainerElementKey.java
new file mode 100644
index 0000000..322a4ef
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/metadata/ContainerElementKey.java
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bval.jsr.metadata;
+
+import java.lang.reflect.AnnotatedParameterizedType;
+import java.lang.reflect.AnnotatedType;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.TypeVariable;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.logging.Logger;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import javax.validation.valueextraction.ExtractedValue;
+import javax.validation.valueextraction.ValueExtractor;
+import javax.validation.valueextraction.ValueExtractorDefinitionException;
+
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.Lazy;
+import org.apache.bval.util.LazyInt;
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.TypeUtils;
+
+public class ContainerElementKey implements Comparable<ContainerElementKey> {
+ private static Logger log = Logger.getLogger(ContainerElementKey.class.getName());
+
+ public static ContainerElementKey forValueExtractor(ValueExtractor<?> extractor) {
+ @SuppressWarnings("rawtypes")
+ final Class<? extends ValueExtractor> extractorType = extractor.getClass();
+ final Lazy<Set<ContainerElementKey>> result = new Lazy<>(HashSet::new);
+
+ Stream.of(extractorType.getAnnotatedInterfaces()).filter(AnnotatedParameterizedType.class::isInstance)
+ .map(AnnotatedParameterizedType.class::cast)
+ .filter(apt -> ValueExtractor.class.equals(((ParameterizedType) apt.getType()).getRawType()))
+ .forEach(decl -> {
+ final AnnotatedType containerType = decl.getAnnotatedActualTypeArguments()[0];
+
+ if (containerType.isAnnotationPresent(ExtractedValue.class)) {
+ Exceptions.raiseIf(void.class.equals(containerType.getAnnotation(ExtractedValue.class).type()),
+ ValueExtractorDefinitionException::new, "%s does not specify %s type for %s", extractorType,
+ ExtractedValue.class.getSimpleName(), containerType);
+ result.get().add(new ContainerElementKey(containerType, null));
+ }
+ Optional.of(containerType).filter(AnnotatedParameterizedType.class::isInstance)
+ .map(AnnotatedParameterizedType.class::cast)
+ .map(AnnotatedParameterizedType::getAnnotatedActualTypeArguments).ifPresent(args -> {
+ IntStream.range(0, args.length).forEach(n -> {
+ if (args[n].isAnnotationPresent(ExtractedValue.class)) {
+ if (void.class.equals(args[n].getAnnotation(ExtractedValue.class).type())) {
+ log.warning(String.format("Ignoring non-default %s type specified for %s by %s",
+ ExtractedValue.class.getSimpleName(), containerType, extractorType));
+ }
+ result.get().add(new ContainerElementKey(containerType, Integer.valueOf(n)));
+ }
+ });
+ });
+ });
+ return result.optional().filter(s -> s.size() == 1)
+ .orElseThrow(() -> new ValueExtractorDefinitionException(extractorType.getName())).iterator().next();
+ }
+
+ private static Integer validTypeArgumentIndex(Integer typeArgumentIndex, Class<?> containerClass) {
+ if (typeArgumentIndex != null) {
+ final int i = typeArgumentIndex.intValue();
+ Validate.isTrue(i >= 0 && i < containerClass.getTypeParameters().length,
+ "type argument index %d is invalid for container type %s", typeArgumentIndex, containerClass);
+ }
+ return typeArgumentIndex;
+ }
+
+ private final Integer typeArgumentIndex;
+ private final Class<?> containerClass;
+ private final LazyInt hashCode = new LazyInt(() -> Objects.hash(getContainerClass(), getTypeArgumentIndex()));
+ private final Lazy<String> toString = new Lazy<>(() -> String.format("%s: %s<[%d]>",
+ ContainerElementKey.class.getSimpleName(), getContainerClass().getName(), getTypeArgumentIndex()));
+ private final AnnotatedType annotatedType;
+
+ public ContainerElementKey(AnnotatedType containerType, Integer typeArgumentIndex) {
+ super();
+ Validate.notNull(containerType, "containerType");
+ this.containerClass = TypeUtils.getRawType(containerType.getType(), null);
+ this.typeArgumentIndex = validTypeArgumentIndex(typeArgumentIndex, containerClass);
+ this.annotatedType = typeArgumentIndex == null ? containerType : ((AnnotatedParameterizedType) containerType)
+ .getAnnotatedActualTypeArguments()[typeArgumentIndex.intValue()];
+ }
+
+ public Class<?> getContainerClass() {
+ return containerClass;
+ }
+
+ public Integer getTypeArgumentIndex() {
+ return typeArgumentIndex;
+ }
+
+ public AnnotatedType getAnnotatedType() {
+ return annotatedType;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj == this || Optional.ofNullable(obj).filter(ContainerElementKey.class::isInstance)
+ .map(ContainerElementKey.class::cast)
+ .filter(
+ cek -> Objects.equals(containerClass, cek.containerClass) && typeArgumentIndex == cek.typeArgumentIndex)
+ .isPresent();
+ }
+
+ @Override
+ public int hashCode() {
+ return hashCode.getAsInt();
+ }
+
+ @Override
+ public String toString() {
+ return toString.get();
+ }
+
+ @Override
+ public int compareTo(ContainerElementKey o) {
+ return Comparator.comparing(ContainerElementKey::containerClassName)
+ .thenComparing(Comparator.comparing(ContainerElementKey::getTypeArgumentIndex)).compare(this, o);
+ }
+
+ public Set<ContainerElementKey> getAssignableKeys() {
+ final Lazy<Set<ContainerElementKey>> result = new Lazy<>(LinkedHashSet::new);
+
+ if (typeArgumentIndex != null) {
+ final TypeVariable<?> var = containerClass.getTypeParameters()[typeArgumentIndex.intValue()];
+
+ Stream
+ .concat(Stream.of(containerClass.getAnnotatedSuperclass()),
+ Stream.of(containerClass.getAnnotatedInterfaces()))
+ .filter(AnnotatedParameterizedType.class::isInstance).map(AnnotatedParameterizedType.class::cast)
+ .forEach(t -> {
+ final AnnotatedType[] args = t.getAnnotatedActualTypeArguments();
+
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].getType().equals(var)) {
+ result.get().add(new ContainerElementKey(t, Integer.valueOf(i)));
+ }
+ }
+ });
+ }
+ return result.optional().map(Collections::unmodifiableSet).orElseGet(Collections::emptySet);
+ }
+
+ public boolean represents(TypeVariable<?> var) {
+ return Optional.ofNullable(typeArgumentIndex)
+ .map(index -> getContainerClass().getTypeParameters()[index.intValue()]).filter(var::equals).isPresent();
+ }
+
+ private String containerClassName() {
+ return getContainerClass().getName();
+ }
+}
[09/11] bval git commit: implement BV 2.0 against existing BVal unit
tests
Posted by mb...@apache.org.
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/el/ELFacade.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/el/ELFacade.java b/bval-jsr/src/main/java/org/apache/bval/el/ELFacade.java
index 49f236b..9798455 100644
--- a/bval-jsr/src/main/java/org/apache/bval/el/ELFacade.java
+++ b/bval-jsr/src/main/java/org/apache/bval/el/ELFacade.java
@@ -54,10 +54,9 @@ public final class ELFacade implements MessageEvaluator {
if (EXPRESSION_FACTORY != null) {
final BValELContext context = new BValELContext();
final VariableMapper variables = context.getVariableMapper();
- for (final Map.Entry<String, Object> var : annotationParameters.entrySet()) {
- variables.setVariable(var.getKey(),
- EXPRESSION_FACTORY.createValueExpression(var.getValue(), Object.class));
- }
+ annotationParameters.forEach(
+ (k, v) -> variables.setVariable(k, EXPRESSION_FACTORY.createValueExpression(v, Object.class)));
+
variables.setVariable("validatedValue",
EXPRESSION_FACTORY.createValueExpression(validatedValue, Object.class));
@@ -83,13 +82,8 @@ public final class ELFacade implements MessageEvaluator {
}
private static class BValELContext extends ELContext {
- private final FunctionMapper functions;
- private final VariableMapper variables;
-
- public BValELContext() {
- this.variables = new BValVariableMapper();
- this.functions = new BValFunctionMapper();
- }
+ private final FunctionMapper functions = new BValFunctionMapper();
+ private final VariableMapper variables = new BValVariableMapper();
@Override
public ELResolver getELResolver() {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/AbstractConstraintDescriptor.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/AbstractConstraintDescriptor.java b/bval-jsr/src/main/java/org/apache/bval/jsr/AbstractConstraintDescriptor.java
new file mode 100644
index 0000000..4c303ae
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/AbstractConstraintDescriptor.java
@@ -0,0 +1,32 @@
+package org.apache.bval.jsr;
+
+import java.lang.annotation.Annotation;
+import java.util.Set;
+
+import javax.validation.Payload;
+import javax.validation.metadata.ConstraintDescriptor;
+import javax.validation.metadata.ValidateUnwrappedValue;
+import javax.validation.valueextraction.Unwrapping;
+
+abstract class AbstractConstraintDescriptor<T extends Annotation> implements ConstraintDescriptor<T> {
+
+ @Override
+ public ValidateUnwrappedValue getValueUnwrapping() {
+ final Set<Class<? extends Payload>> payload = getPayload();
+ if (payload != null) {
+ if (payload.contains(Unwrapping.Unwrap.class)) {
+ return ValidateUnwrappedValue.UNWRAP;
+ }
+ if (payload.contains(Unwrapping.Skip.class)) {
+ return ValidateUnwrappedValue.SKIP;
+ }
+ }
+ // TODO handle UnwrapByDefault extractors
+ return ValidateUnwrappedValue.DEFAULT;
+ }
+
+ @Override
+ public <U> U unwrap(Class<U> type) {
+ throw new UnsupportedOperationException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/AnnotationConstraintBuilder.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/AnnotationConstraintBuilder.java b/bval-jsr/src/main/java/org/apache/bval/jsr/AnnotationConstraintBuilder.java
index 017cabb..4b15ba7 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/AnnotationConstraintBuilder.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/AnnotationConstraintBuilder.java
@@ -72,7 +72,7 @@ final class AnnotationConstraintBuilder<A extends Annotation> {
final boolean reportFromComposite =
annotation != null && annotation.annotationType().isAnnotationPresent(ReportAsSingleViolation.class);
constraintValidation =
- new ConstraintValidation<A>(validatorClasses, annotation, owner, access, reportFromComposite, target);
+ new ConstraintValidation<>(validatorClasses, annotation, owner, access, reportFromComposite, target);
buildFromAnnotation();
}
@@ -139,7 +139,7 @@ final class AnnotationConstraintBuilder<A extends Annotation> {
if (!foundGroups) {
throw new ConstraintDefinitionException("Annotation " + annotationType.getName() + " has no groups method");
}
- if (validationAppliesTo != null && !ConstraintTarget.IMPLICIT.equals(validationAppliesTo.getDefaultValue())) {
+ if (validationAppliesTo != null && ConstraintTarget.IMPLICIT != validationAppliesTo.getDefaultValue()) {
throw new ConstraintDefinitionException("validationAppliesTo default value should be IMPLICIT");
}
@@ -257,9 +257,9 @@ final class AnnotationConstraintBuilder<A extends Annotation> {
final Set<Class<? extends Payload>> payloadSet;
if (payload_raw == null) {
- payloadSet = Collections.<Class<? extends Payload>> emptySet();
+ payloadSet = Collections.emptySet();
} else {
- payloadSet = new HashSet<Class<? extends Payload>>(payload_raw.length);
+ payloadSet = new HashSet<>(payload_raw.length);
Collections.addAll(payloadSet, payload_raw);
}
constraintValidation.setPayload(payloadSet);
@@ -323,18 +323,13 @@ final class AnnotationConstraintBuilder<A extends Annotation> {
* @return An integer index always >= 0
*/
private int computeIndex(ConstraintValidation<?> composite) {
- int idx = 0;
- for (ConstraintValidation<?> each : constraintValidation.getComposingValidations()) {
- if (each.getAnnotation().annotationType() == composite.getAnnotation().annotationType()) {
- idx++;
- }
- }
- return idx;
+ return (int) constraintValidation.getComposingValidations().stream()
+ .filter(v -> v.getAnnotation().annotationType().equals(composite.getAnnotation().annotationType())).count();
}
/** read overridesAttributes from constraintValidation.annotation */
private void buildOverridesAttributes() {
- overrides = new LinkedList<ConstraintOverrides>();
+ overrides = new LinkedList<>();
for (Method method : constraintValidation.getAnnotation().annotationType().getDeclaredMethods()) {
final OverridesAttribute.List overridesAttributeList = method.getAnnotation(OverridesAttribute.List.class);
if (overridesAttributeList != null) {
@@ -359,12 +354,9 @@ final class AnnotationConstraintBuilder<A extends Annotation> {
}
private ConstraintOverrides findOverride(Class<? extends Annotation> constraint, int constraintIndex) {
- for (ConstraintOverrides each : overrides) {
- if (each.constraintType == constraint && each.constraintIndex == constraintIndex) {
- return each;
- }
- }
- return null;
+ return overrides.stream()
+ .filter(ov -> ov.constraintType.equals(constraint) && ov.constraintIndex == constraintIndex).findFirst()
+ .orElse(null);
}
/**
@@ -381,7 +373,7 @@ final class AnnotationConstraintBuilder<A extends Annotation> {
private ConstraintOverrides(Class<? extends Annotation> constraintType, int constraintIndex) {
this.constraintType = constraintType;
this.constraintIndex = constraintIndex;
- values = new HashMap<String, Object>();
+ values = new HashMap<>();
}
@SuppressWarnings("unchecked")
@@ -392,11 +384,9 @@ final class AnnotationConstraintBuilder<A extends Annotation> {
// And the annotation
final Annotation originalAnnot = composite.getAnnotation();
final AnnotationProxyBuilder<Annotation> apb = new AnnotationProxyBuilder<Annotation>(originalAnnot);
- for (String key : values.keySet()) {
- apb.putValue(key, values.get(key));
- }
- final Annotation newAnnot = apb.createAnnotation();
- ((ConstraintValidation<Annotation>) composite).setAnnotation(newAnnot);
+ values.forEach(apb::putValue);
+
+ ((ConstraintValidation<Annotation>) composite).setAnnotation(apb.createAnnotation());
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/AnnotationProcessor.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/AnnotationProcessor.java b/bval-jsr/src/main/java/org/apache/bval/jsr/AnnotationProcessor.java
index 4bdb331..3c4b046 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/AnnotationProcessor.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/AnnotationProcessor.java
@@ -38,7 +38,9 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
import java.util.Set;
/**
@@ -121,7 +123,7 @@ public final class AnnotationProcessor {
if (!reflection) {
Collection<Annotation> annotations = prop.getFeature(JsrFeatures.Property.ANNOTATIONS_TO_PROCESS);
if (annotations == null) {
- annotations = new ArrayList<Annotation>();
+ annotations = new ArrayList<>();
prop.putFeature(JsrFeatures.Property.ANNOTATIONS_TO_PROCESS, annotations);
}
annotations.add(annotation);
@@ -129,18 +131,19 @@ public final class AnnotationProcessor {
return true;
}
- /**
+ /*
* An annotation is considered a constraint definition if its retention
* policy contains RUNTIME and if the annotation itself is annotated
* with javax.validation.Constraint.
*/
final Constraint vcAnno = annotation.annotationType().getAnnotation(Constraint.class);
if (vcAnno != null) {
- Class<? extends ConstraintValidator<A, ?>>[] validatorClasses;
- validatorClasses = findConstraintValidatorClasses(annotation, vcAnno);
+ Class<? extends ConstraintValidator<A, ?>>[] validatorClasses =
+ findConstraintValidatorClasses(annotation, vcAnno);
return applyConstraint(annotation, validatorClasses, prop, owner, access, appender);
}
- /**
+
+ /*
* Multi-valued constraints: To support this requirement, the bean
* validation provider treats regular annotations (annotations not
* annotated by @Constraint) whose value element has a return type of an
@@ -202,15 +205,14 @@ public final class AnnotationProcessor {
vcAnno = annotation.annotationType().getAnnotation(Constraint.class);
}
final Class<A> annotationType = (Class<A>) annotation.annotationType();
- Class<? extends ConstraintValidator<A, ?>>[] validatorClasses =
- factory.getConstraintsCache().getConstraintValidators(annotationType);
+ List<Class<? extends ConstraintValidator<A, ?>>> validatorClasses =
+ factory.getConstraintsCache().getConstraintValidatorClasses(annotationType);
if (validatorClasses == null) {
- validatorClasses = (Class<? extends ConstraintValidator<A, ?>>[]) vcAnno.validatedBy();
- if (validatorClasses.length == 0) {
- validatorClasses = factory.getDefaultConstraints().getValidatorClasses(annotationType);
+ validatorClasses = Arrays.asList((Class<? extends ConstraintValidator<A, ?>>[]) vcAnno.validatedBy());
+ if (validatorClasses.isEmpty()) {
}
}
- return validatorClasses;
+ return validatorClasses.toArray(new Class[validatorClasses.size()]);
}
/**
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java
index 8f68b9e..1e4b263 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java
@@ -18,46 +18,56 @@
*/
package org.apache.bval.jsr;
-import org.apache.bval.MetaBeanFinder;
-import org.apache.bval.util.reflection.Reflection;
-import org.apache.commons.weaver.privilizer.Privilizing;
-import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
-
+import javax.validation.ClockProvider;
import javax.validation.ConstraintValidatorFactory;
import javax.validation.MessageInterpolator;
import javax.validation.ParameterNameProvider;
import javax.validation.TraversableResolver;
import javax.validation.Validator;
import javax.validation.ValidatorContext;
+import javax.validation.valueextraction.ValueExtractor;
+
+import org.apache.bval.MetaBeanFinder;
+import org.apache.bval.jsr.descriptor.DescriptorManager;
+import org.apache.bval.jsr.groups.GroupsComputer;
+import org.apache.bval.jsr.valueextraction.ValueExtractors;
+import org.apache.bval.util.Lazy;
+import org.apache.bval.util.reflection.Reflection;
+import org.apache.commons.weaver.privilizer.Privilizing;
+import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
/**
- * Description: Represents the context that is used to create
- * {@link ClassValidator} instances.
+ * Description: Represents the context that is used to create {@link ClassValidator} instances.
*/
@Privilizing(@CallTo(Reflection.class))
public class ApacheFactoryContext implements ValidatorContext {
+ private final Lazy<GroupsComputer> groupsComputer = new Lazy<>(GroupsComputer::new);
private final ApacheValidatorFactory factory;
+ private final ValueExtractors valueExtractors;
private volatile MetaBeanFinder metaBeanFinder;
private MessageInterpolator messageInterpolator;
private TraversableResolver traversableResolver;
private ParameterNameProvider parameterNameProvider;
private ConstraintValidatorFactory constraintValidatorFactory;
+ private ClockProvider clockProvider;
/**
* Create a new ApacheFactoryContext instance.
*
- * @param factory validator factory
- * @param metaBeanFinder meta finder
+ * @param factory
+ * validator factory
+ * @param metaBeanFinder
+ * meta finder
*/
public ApacheFactoryContext(ApacheValidatorFactory factory, MetaBeanFinder metaBeanFinder) {
this.factory = factory;
this.metaBeanFinder = metaBeanFinder;
+ valueExtractors = factory.getValueExtractors().createChild();
}
/**
- * Get the {@link ApacheValidatorFactory} used by this
- * {@link ApacheFactoryContext}.
+ * Get the {@link ApacheValidatorFactory} used by this {@link ApacheFactoryContext}.
*
* @return {@link ApacheValidatorFactory}
*/
@@ -75,13 +85,13 @@ public class ApacheFactoryContext implements ValidatorContext {
}
/**
- * Discard cached metadata. Calling this method unnecessarily has the effect of severly
- * limiting performance, therefore only do so when changes have been made that affect
- * validation metadata, i.e. particularly NOT in response to:
+ * Discard cached metadata. Calling this method unnecessarily has the effect of severly limiting performance,
+ * therefore only do so when changes have been made that affect validation metadata, i.e. particularly NOT in
+ * response to:
* <ul>
- * <li>{@link #messageInterpolator(MessageInterpolator)}</li>
- * <li>{@link #traversableResolver(TraversableResolver)}</li>
- * <li>{@link #constraintValidatorFactory(ConstraintValidatorFactory)</li>
+ * <li>{@link #messageInterpolator(MessageInterpolator)}</li>
+ * <li>{@link #traversableResolver(TraversableResolver)}</li>
+ * <li>{@link #constraintValidatorFactory(ConstraintValidatorFactory)</li>
* </ul>
*/
private synchronized void resetMeta() {
@@ -92,7 +102,7 @@ public class ApacheFactoryContext implements ValidatorContext {
* {@inheritDoc}
*/
@Override
- public ValidatorContext messageInterpolator(MessageInterpolator messageInterpolator) {
+ public ApacheFactoryContext messageInterpolator(MessageInterpolator messageInterpolator) {
this.messageInterpolator = messageInterpolator;
return this;
}
@@ -101,7 +111,7 @@ public class ApacheFactoryContext implements ValidatorContext {
* {@inheritDoc}
*/
@Override
- public ValidatorContext traversableResolver(TraversableResolver traversableResolver) {
+ public ApacheFactoryContext traversableResolver(TraversableResolver traversableResolver) {
this.traversableResolver = traversableResolver;
return this;
}
@@ -110,18 +120,30 @@ public class ApacheFactoryContext implements ValidatorContext {
* {@inheritDoc}
*/
@Override
- public ValidatorContext constraintValidatorFactory(ConstraintValidatorFactory constraintValidatorFactory) {
+ public ApacheFactoryContext constraintValidatorFactory(ConstraintValidatorFactory constraintValidatorFactory) {
this.constraintValidatorFactory = constraintValidatorFactory;
return this;
}
@Override
- public ValidatorContext parameterNameProvider(ParameterNameProvider parameterNameProvider) {
+ public ApacheFactoryContext parameterNameProvider(ParameterNameProvider parameterNameProvider) {
this.parameterNameProvider = parameterNameProvider;
resetMeta(); // needed since parameter names are a component of validation metadata
return this;
}
+ @Override
+ public ApacheFactoryContext clockProvider(ClockProvider clockProvider) {
+ this.clockProvider = clockProvider;
+ return this;
+ }
+
+ @Override
+ public ApacheFactoryContext addValueExtractor(ValueExtractor<?> extractor) {
+ valueExtractors.add(extractor);
+ return this;
+ }
+
/**
* Get the {@link ConstraintValidatorFactory}.
*
@@ -137,7 +159,7 @@ public class ApacheFactoryContext implements ValidatorContext {
*/
@Override
public Validator getValidator() {
- return new ClassValidator(this);
+ return new ValidatorImpl(this);
}
/**
@@ -162,6 +184,23 @@ public class ApacheFactoryContext implements ValidatorContext {
return parameterNameProvider == null ? factory.getParameterNameProvider() : parameterNameProvider;
}
+ public ClockProvider getClockProvider() {
+ return clockProvider == null ? factory.getClockProvider() : clockProvider;
+ }
+
+ public ValueExtractors getValueExtractors() {
+ return valueExtractors;
+ }
+
+ public DescriptorManager getDescriptorManager() {
+ // TODO handle context customizations
+ return factory.getDescriptorManager();
+ }
+
+ public GroupsComputer getGroupsComputer() {
+ return groupsComputer.get();
+ }
+
boolean isTreatMapsLikeBeans() {
return Boolean
.parseBoolean(factory.getProperties().get(ApacheValidatorConfiguration.Properties.TREAT_MAPS_LIKE_BEANS));
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorConfiguration.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorConfiguration.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorConfiguration.java
index fb64d4e..81187f3 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorConfiguration.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorConfiguration.java
@@ -32,7 +32,7 @@ public interface ApacheValidatorConfiguration extends Configuration<ApacheValida
/**
* Proprietary property keys for {@link ConfigurationImpl}
*/
- public interface Properties {
+ interface Properties {
/**
* the location where to look for the validation.xml file.
* default: "META-INF/validation.xml"
@@ -91,5 +91,10 @@ public interface ApacheValidatorConfiguration extends Configuration<ApacheValida
* </ol>
*/
String METABEAN_FACTORY_CLASSNAMES = "apache.bval.metabean-factory-classnames";
+
+ /**
+ * Size to use for caching of constraint-related information. Default is {@code 50}.
+ */
+ String CONSTRAINTS_CACHE_SIZE = "apache.bval.constraints-cache-size";
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java
index 5e6a611..b516a73 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java
@@ -18,11 +18,39 @@
*/
package org.apache.bval.jsr;
+import java.io.Closeable;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.validation.ClockProvider;
+import javax.validation.ConstraintValidatorFactory;
+import javax.validation.MessageInterpolator;
+import javax.validation.ParameterNameProvider;
+import javax.validation.TraversableResolver;
+import javax.validation.Validation;
+import javax.validation.ValidationException;
+import javax.validation.Validator;
+import javax.validation.ValidatorFactory;
+import javax.validation.spi.ConfigurationState;
+
import org.apache.bval.IntrospectorMetaBeanFactory;
import org.apache.bval.MetaBeanBuilder;
import org.apache.bval.MetaBeanFactory;
import org.apache.bval.MetaBeanFinder;
import org.apache.bval.MetaBeanManager;
+import org.apache.bval.jsr.descriptor.DescriptorManager;
+import org.apache.bval.jsr.metadata.MetadataBuilders;
+import org.apache.bval.jsr.util.AnnotationsManager;
+import org.apache.bval.jsr.valueextraction.ValueExtractors;
import org.apache.bval.jsr.xml.AnnotationIgnores;
import org.apache.bval.jsr.xml.MetaConstraint;
import org.apache.bval.jsr.xml.ValidationMappingParser;
@@ -37,28 +65,6 @@ import org.apache.commons.weaver.privilizer.Privileged;
import org.apache.commons.weaver.privilizer.Privilizing;
import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
-import javax.validation.ConstraintValidatorFactory;
-import javax.validation.MessageInterpolator;
-import javax.validation.ParameterNameProvider;
-import javax.validation.TraversableResolver;
-import javax.validation.Validation;
-import javax.validation.ValidationException;
-import javax.validation.Validator;
-import javax.validation.ValidatorFactory;
-import javax.validation.spi.ConfigurationState;
-import java.io.Closeable;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
/**
* Description: a factory is a complete configurated object that can create
* validators.<br/>
@@ -68,13 +74,17 @@ import java.util.concurrent.ConcurrentMap;
public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
private static volatile ApacheValidatorFactory DEFAULT_FACTORY;
- private static final ConstraintDefaults DEFAULT_CONSTRAINTS = new ConstraintDefaults();
private MessageInterpolator messageResolver;
private TraversableResolver traversableResolver;
private ConstraintValidatorFactory constraintValidatorFactory;
private ParameterNameProvider parameterNameProvider;
+ private ClockProvider clockProvider;
private final Map<String, String> properties;
+ private final AnnotationsManager annotationsManager;
+ private final DescriptorManager descriptorManager = new DescriptorManager(this);
+ private final MetadataBuilders metadataBuilders = new MetadataBuilders();
+ private final ValueExtractors valueExtractors = new ValueExtractors();
/**
* information from xml parsing
@@ -89,7 +99,7 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
private final ConcurrentMap<Class<?>, List<AccessStrategy>> validAccesses;
private final ConcurrentMap<Class<?>, List<MetaConstraint<?, ? extends Annotation>>> constraintMap;
- private final Collection<Closeable> toClose = new ArrayList<Closeable>();
+ private final Collection<Closeable> toClose = new ArrayList<>();
private final MetaBeanFinder defaultMetaBeanFinder;
/**
@@ -112,7 +122,7 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
* @return a new instance of MetaBeanManager with adequate MetaBeanFactories
*/
protected MetaBeanFinder buildMetaBeanFinder() {
- final List<MetaBeanFactory> builders = new ArrayList<MetaBeanFactory>();
+ final List<MetaBeanFactory> builders = new ArrayList<>();
if (Boolean.parseBoolean(getProperties().get(ApacheValidatorConfiguration.Properties.ENABLE_INTROSPECTOR))) {
builders.add(new IntrospectorMetaBeanFactory());
}
@@ -121,9 +131,8 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
if (factoryClassNames != null) {
for (String clsName : factoryClassNames) {
// cast, relying on #createMetaBeanFactory to throw the exception if incompatible:
- @SuppressWarnings("unchecked")
final Class<? extends MetaBeanFactory> factoryClass =
- (Class<? extends MetaBeanFactory>) loadClass(clsName);
+ loadClass(clsName).asSubclass(MetaBeanFactory.class);
builders.add(createMetaBeanFactory(factoryClass));
}
}
@@ -173,24 +182,27 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
* Create a new ApacheValidatorFactory instance.
*/
public ApacheValidatorFactory(ConfigurationState configuration) {
- properties = new HashMap<String, String>(configuration.getProperties());
- defaultSequences = new HashMap<Class<?>, Class<?>[]>();
- validAccesses = new ConcurrentHashMap<Class<?>, List<AccessStrategy>>();
- constraintMap = new ConcurrentHashMap<Class<?>, List<MetaConstraint<?, ? extends Annotation>>>();
+ properties = new HashMap<>(configuration.getProperties());
+ defaultSequences = new HashMap<>();
+ validAccesses = new ConcurrentHashMap<>();
+ constraintMap = new ConcurrentHashMap<>();
parameterNameProvider = configuration.getParameterNameProvider();
messageResolver = configuration.getMessageInterpolator();
traversableResolver = configuration.getTraversableResolver();
constraintValidatorFactory = configuration.getConstraintValidatorFactory();
+ clockProvider = configuration.getClockProvider();
if (ConfigurationImpl.class.isInstance(configuration)) {
- final ConfigurationImpl impl = ConfigurationImpl.class.cast(configuration);
- toClose.add(impl.getClosable());
+ toClose.add(ConfigurationImpl.class.cast(configuration).getClosable());
}
new ValidationMappingParser(this).processMappingConfig(configuration.getMappingStreams());
defaultMetaBeanFinder = buildMetaBeanFinder();
+
+ configuration.getValueExtractors().forEach(valueExtractors::add);
+ annotationsManager = new AnnotationsManager(this);
}
/**
@@ -203,8 +215,7 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
}
/**
- * Shortcut method to create a new Validator instance with factory's
- * settings
+ * Shortcut method to create a new Validator instance with factory's settings
*
* @return the new validator instance
*/
@@ -271,6 +282,12 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
}
}
+ public void setClockProvider(final ClockProvider clockProvider) {
+ if (clockProvider != null) {
+ this.clockProvider = clockProvider;
+ }
+ }
+
/**
* {@inheritDoc}
*/
@@ -307,6 +324,11 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
}
@Override
+ public ClockProvider getClockProvider() {
+ return clockProvider;
+ }
+
+ @Override
public void close() {
try {
for (final Closeable c : toClose) {
@@ -319,13 +341,14 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
}
/**
- * Return an object of the specified type to allow access to the
- * provider-specific API. If the Bean Validation provider implementation
- * does not support the specified class, the ValidationException is thrown.
+ * Return an object of the specified type to allow access to the provider-specific API. If the Bean Validation
+ * provider implementation does not support the specified class, the ValidationException is thrown.
*
- * @param type the class of the object to be returned.
+ * @param type
+ * the class of the object to be returned.
* @return an instance of the specified class
- * @throws ValidationException if the provider does not support the call.
+ * @throws ValidationException
+ * if the provider does not support the call.
*/
@Override
public <T> T unwrap(final Class<T> type) {
@@ -365,15 +388,6 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
}
/**
- * Get the detected {@link ConstraintDefaults}.
- *
- * @return ConstraintDefaults
- */
- public ConstraintDefaults getDefaultConstraints() {
- return DEFAULT_CONSTRAINTS;
- }
-
- /**
* Get the detected {@link AnnotationIgnores}.
*
* @return AnnotationIgnores
@@ -392,8 +406,34 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
}
/**
- * Add a meta-constraint to this {@link ApacheValidatorFactory}'s runtime
- * customizations.
+ * Get the {@link AnnotationsManager}.
+ *
+ * @return {@link AnnotationsManager}
+ */
+ public AnnotationsManager getAnnotationsManager() {
+ return annotationsManager;
+ }
+
+ /**
+ * Get the {@link DescriptorManager}.
+ *
+ * @return {@link DescriptorManager}
+ */
+ public DescriptorManager getDescriptorManager() {
+ return descriptorManager;
+ }
+
+ /**
+ * Get the {@link ValueExtractors}.
+ *
+ * @return {@link ValueExtractors}
+ */
+ public ValueExtractors getValueExtractors() {
+ return valueExtractors;
+ }
+
+ /**
+ * Add a meta-constraint to this {@link ApacheValidatorFactory}'s runtime customizations.
*
* @param beanClass
* @param metaConstraint
@@ -401,7 +441,7 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
public void addMetaConstraint(final Class<?> beanClass, final MetaConstraint<?, ?> metaConstraint) {
List<MetaConstraint<?, ? extends Annotation>> slot = constraintMap.get(beanClass);
if (slot == null) {
- slot = new ArrayList<MetaConstraint<?, ? extends Annotation>>();
+ slot = new ArrayList<>();
final List<MetaConstraint<?, ? extends Annotation>> old = constraintMap.putIfAbsent(beanClass, slot);
if (old != null) {
slot = old;
@@ -420,7 +460,7 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
public void addValid(Class<?> beanClass, AccessStrategy accessStrategy) {
List<AccessStrategy> slot = validAccesses.get(beanClass);
if (slot == null) {
- slot = new ArrayList<AccessStrategy>();
+ slot = new ArrayList<>();
final List<AccessStrategy> old = validAccesses.putIfAbsent(beanClass, slot);
if (old != null) {
slot = old;
@@ -444,8 +484,7 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
*
* @param <T>
* @param beanClass
- * @return List of {@link MetaConstraint}s applicable to
- * <code>beanClass</code>
+ * @return List of {@link MetaConstraint}s applicable to <code>beanClass</code>
*/
public <T> List<MetaConstraint<T, ? extends Annotation>> getMetaConstraints(Class<T> beanClass) {
final List<MetaConstraint<?, ? extends Annotation>> slot = constraintMap.get(beanClass);
@@ -459,16 +498,15 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
}
/**
- * Get the {@link AccessStrategy} {@link List} indicating nested bean
- * validations that must be triggered in the course of validating a
- * <code>beanClass</code> graph.
+ * Get the {@link AccessStrategy} {@link List} indicating nested bean validations that must be triggered in the
+ * course of validating a <code>beanClass</code> graph.
*
* @param beanClass
* @return {@link List} of {@link AccessStrategy}
*/
public List<AccessStrategy> getValidAccesses(Class<?> beanClass) {
final List<AccessStrategy> slot = validAccesses.get(beanClass);
- return slot == null ? Collections.<AccessStrategy> emptyList() : Collections.unmodifiableList(slot);
+ return slot == null ? Collections.emptyList() : Collections.unmodifiableList(slot);
}
/**
@@ -481,6 +519,10 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
return safeArray(defaultSequences.get(beanClass));
}
+ public MetadataBuilders getMetadataBuilders() {
+ return metadataBuilders;
+ }
+
private static Class<?>[] safeArray(Class<?>... array) {
return array == null || array.length == 0 ? ObjectUtils.EMPTY_CLASS_ARRAY : array.clone();
}
@@ -519,9 +561,8 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
}
/**
- * separate class to prevent the classloader to immediately load optional
- * classes: XMLMetaBeanManager, XMLMetaBeanFactory, XMLMetaBeanBuilder that
- * might not be available in the classpath
+ * separate class to prevent the classloader to immediately load optional classes: XMLMetaBeanManager,
+ * XMLMetaBeanFactory, XMLMetaBeanBuilder that might not be available in the classpath
*/
private static class XMLMetaBeanManagerCreator {
@@ -530,10 +571,10 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
}
/**
- * Create the {@link MetaBeanManager} to process JSR303 XML. Requires
- * bval-xstream at RT.
+ * Create the {@link MetaBeanManager} to process JSR303 XML. Requires bval-xstream at RT.
*
- * @param builders meta bean builders
+ * @param builders
+ * meta bean builders
* @return {@link MetaBeanManager}
*/
// NOTE - We return MetaBeanManager instead of XMLMetaBeanManager to
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/BootstrapConfigurationImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/BootstrapConfigurationImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/BootstrapConfigurationImpl.java
index 3a3abf1..d85ab51 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/BootstrapConfigurationImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/BootstrapConfigurationImpl.java
@@ -34,12 +34,15 @@ public class BootstrapConfigurationImpl implements BootstrapConfiguration {
private String messageInterpolatorClassName;
private String constraintValidatorFactoryClassName;
private String defaultProviderClassName;
+ private String clockProviderClassName;
+ private Set<String> valueExtractorClassNames;
public BootstrapConfigurationImpl(final String defaultProviderClassName,
final String constraintValidatorFactoryClassName, final String messageInterpolatorClassName,
final String traversableResolverClassName, final String parameterNameProviderClassName,
final Set<String> constraintMappingResourcePaths, final boolean executableValidationEnabled,
- final Set<ExecutableType> defaultValidatedExecutableTypes, final Map<String, String> properties) {
+ final Set<ExecutableType> defaultValidatedExecutableTypes, final Map<String, String> properties,
+ final String clockProviderClassName, final Set<String> valueExtractorClassNames) {
this.properties = Collections.unmodifiableMap(properties);
this.defaultValidatedExecutableTypes = Collections.unmodifiableSet(defaultValidatedExecutableTypes);
this.executableValidationEnabled = executableValidationEnabled;
@@ -49,6 +52,8 @@ public class BootstrapConfigurationImpl implements BootstrapConfiguration {
this.messageInterpolatorClassName = messageInterpolatorClassName;
this.constraintValidatorFactoryClassName = constraintValidatorFactoryClassName;
this.defaultProviderClassName = defaultProviderClassName;
+ this.clockProviderClassName = clockProviderClassName;
+ this.valueExtractorClassNames = valueExtractorClassNames;
}
@Override
@@ -78,7 +83,7 @@ public class BootstrapConfigurationImpl implements BootstrapConfiguration {
@Override
public Set<String> getConstraintMappingResourcePaths() {
- return constraintMappingResourcePaths;
+ return Collections.unmodifiableSet(constraintMappingResourcePaths);
}
@Override
@@ -88,11 +93,27 @@ public class BootstrapConfigurationImpl implements BootstrapConfiguration {
@Override
public Set<ExecutableType> getDefaultValidatedExecutableTypes() {
- return defaultValidatedExecutableTypes;
+ return Collections.unmodifiableSet(defaultValidatedExecutableTypes);
}
@Override
public Map<String, String> getProperties() {
- return properties;
+ return Collections.unmodifiableMap(properties);
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public String getClockProviderClassName() {
+ return clockProviderClassName;
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public Set<String> getValueExtractorClassNames() {
+ return Collections.unmodifiableSet(valueExtractorClassNames);
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/CascadingPropertyValidator.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/CascadingPropertyValidator.java b/bval-jsr/src/main/java/org/apache/bval/jsr/CascadingPropertyValidator.java
index ff2e273..f183c12 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/CascadingPropertyValidator.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/CascadingPropertyValidator.java
@@ -18,7 +18,9 @@ package org.apache.bval.jsr;
import javax.validation.ConstraintViolation;
import javax.validation.Valid;
+import javax.validation.ValidationException;
import javax.validation.Validator;
+
import java.util.Set;
/**
@@ -30,38 +32,90 @@ import java.util.Set;
* It should be noted that {@link Validator#validateProperty(Object, String, Class...)}
* and {@link Validator#validateValue(Class, String, Object, Class...)} are assumed
* semantically equivalent to calling the {@link CascadingPropertyValidator}-defined
- * methods with <code>cascade == false</code>.
+ * methods with {@code cascade == false}.
*
* @version $Rev: 993539 $ $Date: 2010-09-07 16:27:50 -0500 (Tue, 07 Sep 2010) $
*/
public interface CascadingPropertyValidator extends Validator {
/**
- * Validates all constraints placed on <code>object</code>'s
- * <code>propertyName</code> property, with optional validation cascading.
- *
- * @param <T>
- * @param object
- * @param propertyName
- * @param cascade
- * @param groups
- * @return the resulting {@link Set} of {@link ConstraintViolation}s.
+ * {@inheritDoc} Validates all constraints placed on the property of {@code object} named {@code propertyName}.
+ *
+ * @param object object to validate
+ * @param propertyName property to validate (i.e. field and getter constraints). Nested
+ * properties may be referenced (e.g. prop[2].subpropA.subpropB)
+ * @param groups group or list of groups targeted for validation (default to
+ * {@link javax.validation.groups.Default})
+ * @return constraint violations or an empty {@link Set} if none
+ * @throws IllegalArgumentException if {@code object} is {@code null}, if {@code propertyName null},
+ * empty or not a valid object property or if {@code null} is
+ * passed to the varargs {@code groups}
+ * @throws ValidationException if a non recoverable error happens during the validation process
+ */
+ @Override
+ default <T> Set<ConstraintViolation<T>> validateProperty(T object, String propertyName, Class<?>... groups) {
+ return validateProperty(object, propertyName, false, groups);
+ }
+
+ /**
+ * Validates all constraints placed on the property of {@code object} named {@code propertyName}.
+ *
+ * @param object object to validate
+ * @param propertyName property to validate (i.e. field and getter constraints). Nested
+ * properties may be referenced (e.g. prop[2].subpropA.subpropB)
+ * @param cascade whether to cascade along {@link Valid} properties
+ * @param groups group or list of groups targeted for validation (default to
+ * {@link javax.validation.groups.Default})
+ * @return constraint violations or an empty {@link Set} if none
+ * @throws IllegalArgumentException if {@code object} is {@code null}, if {@code propertyName null},
+ * empty or not a valid object property or if {@code null} is
+ * passed to the varargs {@code groups}
+ * @throws ValidationException if a non recoverable error happens during the validation process
*/
<T> Set<javax.validation.ConstraintViolation<T>> validateProperty(T object, String propertyName, boolean cascade,
Class<?>... groups);
/**
- * Validates all constraints placed on <code>object</code>'s
- * <code>propertyName</code> property, with optional validation cascading,
- * given a hypothetical property <code>value</code>.
- *
- * @param <T>
- * @param beanType
- * @param propertyName
- * @param value
- * @param cascade
- * @param groups
- * @return the resulting {@link Set} of {@link ConstraintViolation}s.
+ * {@inheritDoc} Validates all constraints placed on the property named {@code propertyName} of the class
+ * {@code beanType} would the property value be {@code value}.
+ * <p/>
+ * {@link ConstraintViolation} objects return {@code null} for {@link ConstraintViolation#getRootBean()} and
+ * {@link ConstraintViolation#getLeafBean()}.
+ *
+ * @param beanType the bean type
+ * @param propertyName property to validate
+ * @param value property value to validate
+ * @param groups group or list of groups targeted for validation (default to
+ * {@link javax.validation.groups.Default})
+ * @return constraint violations or an empty {@link Set} if none
+ * @throws IllegalArgumentException if {@code beanType} is {@code null}, if
+ * {@code propertyName null}, empty or not a valid object
+ * property or if {@code null} is passed to the varargs {@code groups}
+ * @throws ValidationException if a non recoverable error happens during the validation process
+ */
+ @Override
+ default <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value,
+ Class<?>... groups) {
+ return validateValue(beanType, propertyName, value, false, groups);
+ }
+
+ /**
+ * {@inheritDoc} Validates all constraints placed on the property named {@code propertyName} of the class
+ * {@code beanType} would the property value be {@code value}.
+ * <p/>
+ * {@link ConstraintViolation} objects return {@code null} for {@link ConstraintViolation#getRootBean()} and
+ * {@link ConstraintViolation#getLeafBean()}.
+ *
+ * @param beanType the bean type
+ * @param propertyName property to validate
+ * @param value property value to validate
+ * @param groups group or list of groups targeted for validation (default to
+ * {@link javax.validation.groups.Default})
+ * @return constraint violations or an empty {@link Set} if none
+ * @throws IllegalArgumentException if {@code beanType} is {@code null}, if
+ * {@code propertyName null}, empty or not a valid object
+ * property or if {@code null} is passed to the varargs {@code groups}
+ * @throws ValidationException if a non recoverable error happens during the validation process
*/
<T> Set<javax.validation.ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value,
boolean cascade, Class<?>... groups);
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/ConfigurationImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ConfigurationImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ConfigurationImpl.java
index 7c4780f..046d6d2 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ConfigurationImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ConfigurationImpl.java
@@ -19,9 +19,10 @@
package org.apache.bval.jsr;
import java.io.Closeable;
-import java.io.IOException;
import java.io.InputStream;
+import java.time.Clock;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -29,6 +30,7 @@ import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.validation.BootstrapConfiguration;
+import javax.validation.ClockProvider;
import javax.validation.ConstraintValidatorFactory;
import javax.validation.MessageInterpolator;
import javax.validation.ParameterNameProvider;
@@ -40,6 +42,7 @@ import javax.validation.executable.ExecutableType;
import javax.validation.spi.BootstrapState;
import javax.validation.spi.ConfigurationState;
import javax.validation.spi.ValidationProvider;
+import javax.validation.valueextraction.ValueExtractor;
import org.apache.bval.cdi.BValExtension;
import org.apache.bval.jsr.parameter.DefaultParameterNameProvider;
@@ -76,29 +79,33 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
*/
protected MessageInterpolator defaultMessageInterpolator = new DefaultMessageInterpolator();
protected volatile MessageInterpolator messageInterpolator = defaultMessageInterpolator;
- protected Class<? extends MessageInterpolator> messageInterpolatorClass = null;
+ protected Class<? extends MessageInterpolator> messageInterpolatorClass;
/**
* Configured {@link ConstraintValidatorFactory}
*/
protected ConstraintValidatorFactory defaultConstraintValidatorFactory = new DefaultConstraintValidatorFactory();
protected volatile ConstraintValidatorFactory constraintValidatorFactory = defaultConstraintValidatorFactory;
- protected Class<? extends ConstraintValidatorFactory> constraintValidatorFactoryClass = null;
+ protected Class<? extends ConstraintValidatorFactory> constraintValidatorFactoryClass;
protected TraversableResolver defaultTraversableResolver = new DefaultTraversableResolver();
protected volatile TraversableResolver traversableResolver = defaultTraversableResolver;
- protected Class<? extends TraversableResolver> traversableResolverClass = null;
+ protected Class<? extends TraversableResolver> traversableResolverClass;
protected ParameterNameProvider defaultParameterNameProvider = new DefaultParameterNameProvider();
protected volatile ParameterNameProvider parameterNameProvider = defaultParameterNameProvider;
- protected Class<? extends ParameterNameProvider> parameterNameProviderClass = null;
+ protected Class<? extends ParameterNameProvider> parameterNameProviderClass;
protected BootstrapConfiguration bootstrapConfiguration;
protected Collection<ExecutableType> executableValidation;
- private Collection<BValExtension.Releasable<?>> releasables =
- new CopyOnWriteArrayList<BValExtension.Releasable<?>>();
+ private Collection<BValExtension.Releasable<?>> releasables = new CopyOnWriteArrayList<>();
+ protected ClockProvider defaultClockProvider = Clock::systemDefaultZone;
+ protected volatile ClockProvider clockProvider = defaultClockProvider;
+ protected Class<? extends ClockProvider> clockProviderClass;
+
+ protected Set<ValueExtractor<?>> valueExtractors = new HashSet<>();
private boolean beforeCdi = false;
@@ -109,8 +116,8 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
private boolean prepared = false;
// END DEFAULTS
- private Set<InputStream> mappingStreams = new HashSet<InputStream>();
- private Map<String, String> properties = new HashMap<String, String>();
+ private Set<InputStream> mappingStreams = new HashSet<>();
+ private Map<String, String> properties = new HashMap<>();
private boolean ignoreXmlConfiguration = false;
private volatile ValidationParser parser;
@@ -134,6 +141,7 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
} else {
throw new ValidationException("either provider or state are required");
}
+ initializePropertyDefaults();
}
/**
@@ -141,13 +149,11 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
*/
@Override
public ApacheValidatorConfiguration traversableResolver(TraversableResolver resolver) {
- if (resolver == null) {
- return this;
+ if (resolver != null) {
+ this.traversableResolverClass = null;
+ this.traversableResolver = resolver;
+ this.prepared = false;
}
-
- this.traversableResolverClass = null;
- this.traversableResolver = resolver;
- this.prepared = false;
return this;
}
@@ -169,13 +175,11 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
*/
@Override
public ConfigurationImpl messageInterpolator(MessageInterpolator resolver) {
- if (resolver == null) {
- return this;
+ if (resolver != null) {
+ this.messageInterpolatorClass = null;
+ this.messageInterpolator = resolver;
+ this.prepared = false;
}
-
- this.messageInterpolatorClass = null;
- this.messageInterpolator = resolver;
- this.prepared = false;
return this;
}
@@ -184,23 +188,20 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
*/
@Override
public ConfigurationImpl constraintValidatorFactory(ConstraintValidatorFactory constraintFactory) {
- if (constraintFactory == null) {
- return this;
+ if (constraintFactory != null) {
+ this.constraintValidatorFactoryClass = null;
+ this.constraintValidatorFactory = constraintFactory;
+ this.prepared = false;
}
-
- this.constraintValidatorFactoryClass = null;
- this.constraintValidatorFactory = constraintFactory;
- this.prepared = false;
return this;
}
@Override
public ApacheValidatorConfiguration parameterNameProvider(ParameterNameProvider parameterNameProvider) {
- if (parameterNameProvider == null) {
- return this;
+ if (parameterNameProvider != null) {
+ this.parameterNameProviderClass = null;
+ this.parameterNameProvider = parameterNameProvider;
}
- this.parameterNameProviderClass = null;
- this.parameterNameProvider = parameterNameProvider;
return this;
}
@@ -213,10 +214,9 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
*/
@Override
public ApacheValidatorConfiguration addMapping(InputStream stream) {
- if (stream == null) {
- return this;
+ if (stream != null) {
+ mappingStreams.add(IOs.convertToMarkableInputStream(stream));
}
- mappingStreams.add(IOs.convertToMarkableInputStream(stream));
return this;
}
@@ -297,7 +297,6 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
if (beforeCdi) {
return defaultMessageInterpolator;
}
-
if (messageInterpolator == defaultMessageInterpolator && messageInterpolatorClass != null) {
synchronized (this) {
if (messageInterpolator == defaultMessageInterpolator && messageInterpolatorClass != null) {
@@ -336,7 +335,6 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
if (prepared) {
return this;
}
-
createBootstrapConfiguration();
parser.applyConfigWithInstantiation(this); // instantiate the config if needed
@@ -367,7 +365,6 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
if (beforeCdi) {
return constraintValidatorFactory;
}
-
if (constraintValidatorFactory == defaultConstraintValidatorFactory
&& constraintValidatorFactoryClass != null) {
synchronized (this) {
@@ -388,7 +385,6 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
if (beforeCdi) {
return defaultTraversableResolver;
}
-
if (traversableResolver == defaultTraversableResolver && traversableResolverClass != null) {
synchronized (this) {
if (traversableResolver == defaultTraversableResolver && traversableResolverClass != null) {
@@ -404,7 +400,6 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
if (beforeCdi) {
return defaultParameterNameProvider;
}
-
if (parameterNameProvider == defaultParameterNameProvider && parameterNameProviderClass != null) {
synchronized (this) {
if (parameterNameProvider == defaultParameterNameProvider && parameterNameProviderClass != null) {
@@ -452,14 +447,11 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
}
public Closeable getClosable() {
- return new Closeable() {
- @Override
- public void close() throws IOException {
- for (final BValExtension.Releasable<?> releasable : releasables) {
- releasable.release();
- }
- releasables.clear();
+ return () -> {
+ for (final BValExtension.Releasable<?> releasable : releasables) {
+ releasable.release();
}
+ releasables.clear();
};
}
@@ -469,8 +461,7 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
final BValExtension.Releasable<T> releasable = BValExtension.inject(cls);
releasables.add(releasable);
return releasable.getInstance();
- } catch (final Exception e) {
- } catch (final NoClassDefFoundError error) {
+ } catch (Exception | NoClassDefFoundError e) {
}
try {
return cls.newInstance();
@@ -494,4 +485,45 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
public void parameterNameProviderClass(final Class<? extends ParameterNameProvider> clazz) {
parameterNameProviderClass = clazz;
}
+
+ @Override
+ public ApacheValidatorConfiguration clockProvider(ClockProvider clockProvider) {
+ this.clockProvider = clockProvider;
+ return this;
+ }
+
+ @Override
+ public ApacheValidatorConfiguration addValueExtractor(ValueExtractor<?> extractor) {
+ valueExtractors.add(extractor);
+ return this;
+ }
+
+ @Override
+ public ClockProvider getDefaultClockProvider() {
+ return defaultClockProvider;
+ }
+
+ @Override
+ public Set<ValueExtractor<?>> getValueExtractors() {
+ return Collections.unmodifiableSet(valueExtractors);
+ }
+
+ @Override
+ public ClockProvider getClockProvider() {
+ if (beforeCdi) {
+ return defaultClockProvider;
+ }
+ if (clockProvider == defaultClockProvider && clockProviderClass != null) {
+ synchronized (this) {
+ if (clockProvider == defaultClockProvider && clockProviderClass != null) {
+ clockProvider = newInstance(clockProviderClass);
+ }
+ }
+ }
+ return clockProvider;
+ }
+
+ protected void initializePropertyDefaults() {
+ properties.put(Properties.CONSTRAINTS_CACHE_SIZE, Integer.toString(50));
+ }
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintAnnotationAttributes.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintAnnotationAttributes.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintAnnotationAttributes.java
index 24b38ea..df99bf9 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintAnnotationAttributes.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintAnnotationAttributes.java
@@ -16,6 +16,7 @@
*/
package org.apache.bval.jsr;
+import org.apache.bval.util.Exceptions;
import org.apache.bval.util.reflection.Reflection;
import org.apache.bval.util.reflection.TypeUtils;
import org.apache.commons.weaver.privilizer.Privilizing;
@@ -125,29 +126,24 @@ public enum ConstraintAnnotationAttributes {
public <V> V get(Map<? super String, ? super V> map) {
@SuppressWarnings("unchecked")
final V result = (V) map.get(getAttributeName());
- if (TypeUtils.isInstance(result, getType())) {
- return result;
- }
- throw new IllegalStateException(String.format("Invalid '%s' value: %s", getAttributeName(), result));
+ Exceptions.raiseUnless(TypeUtils.isInstance(result, getType()), IllegalStateException::new,
+ "Invalid '%s' value: %s", getAttributeName(), result);
+ return result;
}
public <C extends Annotation> Worker<C> analyze(final Class<C> clazz) {
if (clazz.getName().startsWith("javax.validation.constraint.")) { // cache only APIs classes to avoid memory leaks
@SuppressWarnings("unchecked")
- Worker<C> w = Worker.class.cast(WORKER_CACHE.get(clazz));
- if (w == null) {
- w = new Worker<C>(clazz);
- WORKER_CACHE.putIfAbsent(clazz, w);
- return w;
- }
+ final Worker<C> w = (Worker<C>) WORKER_CACHE.computeIfAbsent(clazz, Worker::new);
+ return w;
}
return new Worker<C>(clazz);
}
// this is static but related to Worker
- private static final ConcurrentMap<Class<?>, Worker<?>> WORKER_CACHE = new ConcurrentHashMap<Class<?>, Worker<?>>();
+ private static final ConcurrentMap<Class<?>, Worker<?>> WORKER_CACHE = new ConcurrentHashMap<>();
private static final ConcurrentMap<Class<?>, ConcurrentMap<String, Method>> METHOD_BY_NAME_AND_CLASS =
- new ConcurrentHashMap<Class<?>, ConcurrentMap<String, Method>>();
+ new ConcurrentHashMap<>();
private static final Method NULL_METHOD;
static {
try {
@@ -171,14 +167,8 @@ public enum ConstraintAnnotationAttributes {
}
private Method findMethod(final Class<C> constraintType, final String attributeName) {
- ConcurrentMap<String, Method> cache = METHOD_BY_NAME_AND_CLASS.get(constraintType);
- if (cache == null) {
- cache = new ConcurrentHashMap<String, Method>();
- final ConcurrentMap<String, Method> old = METHOD_BY_NAME_AND_CLASS.putIfAbsent(constraintType, cache);
- if (old != null) {
- cache = old;
- }
- }
+ ConcurrentMap<String, Method> cache =
+ METHOD_BY_NAME_AND_CLASS.computeIfAbsent(constraintType, t -> new ConcurrentHashMap<>());
final Method found = cache.get(attributeName);
if (found != null) {
@@ -189,15 +179,19 @@ public enum ConstraintAnnotationAttributes {
cache.putIfAbsent(attributeName, NULL_METHOD);
return null;
}
- final Method oldMtd = cache.putIfAbsent(attributeName, m);
- if (oldMtd != null) {
- return oldMtd;
- }
- return m;
+ return cache.computeIfAbsent(attributeName, s -> m);
}
public boolean isValid() {
- return method != null && method != NULL_METHOD;
+ return method != null && method != NULL_METHOD && TypeUtils.isAssignable(method.getReturnType(), type);
+ }
+
+ /**
+ * @since 2.0
+ * @return {@link Type}
+ */
+ public Type getSpecificType() {
+ return isValid() ? method.getGenericReturnType() : type;
}
public <T> T read(final Annotation constraint) {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintCached.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintCached.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintCached.java
index 1bb012f..a1f3924 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintCached.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintCached.java
@@ -18,18 +18,92 @@
*/
package org.apache.bval.jsr;
-import javax.validation.ConstraintValidator;
import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
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.Collectors;
+import java.util.stream.Stream;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.constraintvalidation.SupportedValidationTarget;
+import javax.validation.constraintvalidation.ValidationTarget;
+
+import org.apache.bval.jsr.metadata.AnnotationDeclaredValidatorMappingProvider;
+import org.apache.bval.jsr.metadata.CompositeValidatorMappingProvider;
+import org.apache.bval.jsr.metadata.DualValidationMappingProvider;
+import org.apache.bval.jsr.metadata.ValidatorMappingProvider;
+import org.apache.bval.jsr.util.ToUnmodifiable;
+import org.apache.bval.util.Lazy;
+import org.apache.bval.util.ObjectUtils;
+import org.apache.bval.util.Validate;
/**
- * Description: hold the relationship annotation->validatedBy[] ConstraintValidator classes that are already parsed in a
- * cache.<br/>
+ * Description: hold the relationship annotation->validatedBy[]
+ * ConstraintValidator classes that are already parsed in a cache.<br/>
*/
public class ConstraintCached {
- private final Map<Class<? extends Annotation>, Class<? extends ConstraintValidator<?, ?>>[]> classes =
- new HashMap<Class<? extends Annotation>, Class<? extends ConstraintValidator<?, ?>>[]>();
+
+ /**
+ * Describes a {@link ConstraintValidator} implementation type.
+ *
+ * @since 2.0
+ */
+ public static final class ConstraintValidatorInfo<T extends Annotation> {
+ private static final Set<ValidationTarget> DEFAULT_VALIDATION_TARGETS =
+ Collections.singleton(ValidationTarget.ANNOTATED_ELEMENT);
+
+ private final Class<? extends ConstraintValidator<T, ?>> type;
+ private Set<ValidationTarget> supportedTargets;
+
+ ConstraintValidatorInfo(Class<? extends ConstraintValidator<T, ?>> type) {
+ super();
+ this.type = Validate.notNull(type);
+ final SupportedValidationTarget svt = type.getAnnotation(SupportedValidationTarget.class);
+
+ supportedTargets = svt == null ? DEFAULT_VALIDATION_TARGETS
+ : Collections.unmodifiableSet(EnumSet.copyOf(Arrays.asList(svt.value())));
+ }
+
+ public Class<? extends ConstraintValidator<T, ?>> getType() {
+ return type;
+ }
+
+ public Set<ValidationTarget> getSupportedTargets() {
+ return supportedTargets;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj == this
+ || obj instanceof ConstraintValidatorInfo<?> && ((ConstraintValidatorInfo<?>) obj).type.equals(type);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(type);
+ }
+ }
+
+ private final Map<Class<? extends Annotation>, Set<ConstraintValidatorInfo<?>>> constraintValidatorInfo =
+ new HashMap<>();
+
+ private final List<ValidatorMappingProvider> customValidatorMappingProviders = new ArrayList<>();
+ private final Lazy<ValidatorMappingProvider> validatorMappingProvider =
+ new Lazy<>(this::createValidatorMappingProvider);
+
+ public void add(ValidatorMappingProvider validatorMappingProvider) {
+ if (customValidatorMappingProviders.add(validatorMappingProvider)) {
+ this.validatorMappingProvider.reset(this::createValidatorMappingProvider);
+ }
+ }
/**
* Record the set of validator classes for a given constraint annotation.
@@ -37,33 +111,80 @@ public class ConstraintCached {
* @param annotationClass
* @param definitionClasses
*/
+ @Deprecated
public <A extends Annotation> void putConstraintValidator(Class<A> annotationClass,
Class<? extends ConstraintValidator<A, ?>>[] definitionClasses) {
- classes.put(annotationClass, definitionClasses);
+ if (ObjectUtils.isEmpty(definitionClasses)) {
+ return;
+ }
+ Validate.notNull(annotationClass, "annotationClass");
+ Stream.of(definitionClasses).map(t -> new ConstraintValidatorInfo<>(t))
+ .forEach(constraintValidatorInfo.computeIfAbsent(annotationClass, k -> new HashSet<>())::add);
}
/**
- * Learn whether we have cached the validator classes for the requested constraint annotation.
+ * Learn whether we have cached the validator classes for the requested
+ * constraint annotation.
*
* @param annotationClass
* to look up
* @return boolean
*/
+ @Deprecated
public boolean containsConstraintValidator(Class<? extends Annotation> annotationClass) {
- return classes.containsKey(annotationClass);
+ return constraintValidatorInfo.containsKey(annotationClass);
}
/**
* Get the cached validator classes for the requested constraint annotation.
*
- * @param annotationClass
+ * @param constraintType
* to look up
* @return array of {@link ConstraintValidator} implementation types
*/
@SuppressWarnings("unchecked")
+ @Deprecated
public <A extends Annotation> Class<? extends ConstraintValidator<A, ?>>[] getConstraintValidators(
- Class<A> annotationClass) {
- return (Class<? extends ConstraintValidator<A, ?>>[]) classes.get(annotationClass);
+ Class<A> constraintType) {
+ final Set<ConstraintValidatorInfo<A>> infos = infos(constraintType);
+ return infos == null ? new Class[0]
+ : infos.stream().map(ConstraintValidatorInfo::getType).toArray(Class[]::new);
}
+ public <A extends Annotation> List<Class<? extends ConstraintValidator<A, ?>>> getConstraintValidatorClasses(
+ Class<A> constraintType) {
+ final Set<ConstraintValidatorInfo<A>> infos = infos(constraintType);
+ return infos == null ? Collections.emptyList()
+ : infos.stream().map(ConstraintValidatorInfo::getType).collect(ToUnmodifiable.list());
+ }
+
+ public <A extends Annotation> Set<ConstraintValidatorInfo<A>> getConstraintValidatorInfo(Class<A> constraintType) {
+ return Collections.unmodifiableSet(infos(constraintType));
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private <A extends Annotation> Set<ConstraintValidatorInfo<A>> infos(Class<A> constraintType) {
+ return (Set) constraintValidatorInfo.computeIfAbsent(constraintType,
+ c -> validatorMappingProvider.get().getValidatorMapping(c).getValidatorTypes().stream()
+ .map(ConstraintValidatorInfo::new).collect(Collectors.toSet()));
+ }
+
+ private ValidatorMappingProvider createValidatorMappingProvider() {
+ final ValidatorMappingProvider configured;
+ if (customValidatorMappingProviders.isEmpty()) {
+ configured = AnnotationDeclaredValidatorMappingProvider.INSTANCE;
+ } else {
+ final ValidatorMappingProvider custom;
+ if (customValidatorMappingProviders.size() == 1) {
+ custom = customValidatorMappingProviders.get(0);
+ } else {
+ custom = new CompositeValidatorMappingProvider(customValidatorMappingProviders);
+ }
+ configured = new DualValidationMappingProvider(AnnotationDeclaredValidatorMappingProvider.INSTANCE, custom);
+ }
+ // interpret spec as saying that default constraint validators are
+ // always present even when annotation-based validators
+ // have been excluded by custom (i.e. XML) config:
+ return new DualValidationMappingProvider(configured, ConstraintDefaults.INSTANCE);
+ }
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintDefaults.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintDefaults.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintDefaults.java
index 3e3771e..9ea93e7 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintDefaults.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintDefaults.java
@@ -21,101 +21,70 @@ package org.apache.bval.jsr;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
import javax.validation.ConstraintValidator;
+import org.apache.bval.jsr.metadata.ClassLoadingValidatorMappingProvider;
+import org.apache.bval.jsr.metadata.ValidatorMapping;
import org.apache.bval.util.StringUtils;
import org.apache.bval.util.reflection.Reflection;
import org.apache.commons.weaver.privilizer.Privilizing;
import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
/**
- * Description: Provides access to the default constraints/validator implementation classes built into the framework.
- * These are configured in DefaultConstraints.properties.<br/>
+ * Description: Provides access to the default constraints/validator
+ * implementation classes built into the framework. These are configured in
+ * DefaultConstraints.properties.<br/>
*/
@Privilizing(@CallTo(Reflection.class))
-public class ConstraintDefaults {
+public class ConstraintDefaults extends ClassLoadingValidatorMappingProvider {
+ public static final ConstraintDefaults INSTANCE = new ConstraintDefaults();
+
private static final Logger log = Logger.getLogger(ConstraintDefaults.class.getName());
private static final String DEFAULT_CONSTRAINTS = "org/apache/bval/jsr/DefaultConstraints.properties";
- /**
- * The default constraint data stored herein.
- */
- private Map<String, Class<? extends ConstraintValidator<?, ?>>[]> defaultConstraints;
+ private final Properties properties;
/**
* Create a new ConstraintDefaults instance.
*/
- public ConstraintDefaults() {
- defaultConstraints = loadDefaultConstraints(DEFAULT_CONSTRAINTS);
- }
-
- /**
- * Get the default constraint data.
- * @return String-keyed map
- */
- public Map<String, Class<? extends ConstraintValidator<?, ?>>[]> getDefaultConstraints() {
- return defaultConstraints;
- }
-
- /**
- * Get the default validator implementation types for the specified constraint annotation type.
- * @param annotationType the annotation type
- * @return array of {@link ConstraintValidator} implementation classes
- */
- @SuppressWarnings("unchecked")
- public <A extends Annotation> Class<? extends ConstraintValidator<A, ?>>[] getValidatorClasses(
- Class<A> annotationType) {
- return (Class<? extends ConstraintValidator<A, ?>>[]) getDefaultConstraints().get(annotationType.getName());
+ private ConstraintDefaults() {
+ this.properties = loadProperties(DEFAULT_CONSTRAINTS);
}
- @SuppressWarnings("unchecked")
- private Map<String, Class<? extends ConstraintValidator<?, ?>>[]> loadDefaultConstraints(String resource) {
- final Properties constraintProperties = new Properties();
+ private Properties loadProperties(String resource) {
+ final Properties result = new Properties();
final ClassLoader classloader = getClassLoader();
- final InputStream stream = classloader.getResourceAsStream(resource);
- if (stream == null) {
- log.log(Level.WARNING, String.format("Cannot find %s", resource));
- } else {
- try {
- constraintProperties.load(stream);
- } catch (IOException e) {
- log.log(Level.SEVERE, String.format("Cannot load %s", resource), e);
- } finally {
- try {
- stream.close();
- } catch (final IOException e) {
- // no-op
- }
+ try (final InputStream stream = classloader.getResourceAsStream(resource)) {
+ if (stream == null) {
+ log.log(Level.WARNING, String.format("Cannot find %s", resource));
+ } else {
+ result.load(stream);
}
+ } catch (IOException e) {
+ log.log(Level.SEVERE, String.format("Cannot load %s", resource), e);
}
+ return result;
+ }
- final Map<String, Class<? extends ConstraintValidator<?, ?>>[]> loadedConstraints =
- new HashMap<String, Class<? extends ConstraintValidator<?, ?>>[]>();
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Override
+ public <A extends Annotation> ValidatorMapping<A> doGetValidatorMapping(Class<A> constraintType) {
- for (final Map.Entry<Object, Object> entry : constraintProperties.entrySet()) {
- final List<Class<?>> classes = new LinkedList<Class<?>>();
- for (String className : StringUtils.split((String) entry.getValue(), ',')) {
- try {
- classes.add(Reflection.toClass(className.trim(), classloader));
- } catch (Exception e) {
- log.log(Level.SEVERE, String.format("Cannot find class %s", className), e);
- }
- }
- loadedConstraints.put((String) entry.getKey(), classes.toArray(new Class[classes.size()]));
- }
- return loadedConstraints;
- }
+ final String validators = properties.getProperty(constraintType.getName());
- private ClassLoader getClassLoader() {
- final ClassLoader classloader = Thread.currentThread().getContextClassLoader();
- return classloader == null ? getClass().getClassLoader() : classloader;
+ if (StringUtils.isBlank(validators)) {
+ return null;
+ }
+ return new ValidatorMapping<>("built-in",
+ load(Stream.of(StringUtils.split(validators, ',')).map(String::trim),
+ (Class<ConstraintValidator<A, ?>>) (Class) ConstraintValidator.class,
+ e -> log.log(Level.SEVERE, "exception loading default constraint validators", e))
+ .collect(Collectors.toList()));
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintDescriptorImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintDescriptorImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintDescriptorImpl.java
index a56e1e1..c4c9d99 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintDescriptorImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintDescriptorImpl.java
@@ -21,6 +21,7 @@ package org.apache.bval.jsr;
import javax.validation.ConstraintTarget;
import javax.validation.Payload;
import javax.validation.metadata.ConstraintDescriptor;
+import javax.validation.metadata.ValidateUnwrappedValue;
import java.io.Serializable;
import java.lang.annotation.Annotation;
@@ -220,4 +221,16 @@ public class ConstraintDescriptorImpl<T extends Annotation> implements Constrain
result = 31 * result + (template != null ? template.hashCode() : 0);
return result;
}
+
+ @Override
+ public ValidateUnwrappedValue getValueUnwrapping() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public <U> U unwrap(Class<U> arg0) {
+ // 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/ConstraintValidation.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidation.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidation.java
index 5b51141..5ba14ca 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidation.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidation.java
@@ -39,6 +39,8 @@ import javax.validation.ValidationException;
import javax.validation.constraintvalidation.SupportedValidationTarget;
import javax.validation.constraintvalidation.ValidationTarget;
import javax.validation.metadata.ConstraintDescriptor;
+import javax.validation.metadata.ValidateUnwrappedValue;
+
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
@@ -54,6 +56,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.stream.Collectors;
/**
* Description: Adapter between Constraint (JSR303) and Validation (Core)<br/>
@@ -328,10 +331,12 @@ public class ConstraintValidation<T extends Annotation> implements Validation, C
throw new UnexpectedTypeException(message);
}
if (types.size() > 1) {
- throw new UnexpectedTypeException(
- String.format("Ambiguous validators for type %s. See: @%s at %s. Validators are: %s",
- stringForType(targetType), anno.annotationType().getSimpleName(), stringForLocation(owner, access),
- StringUtils.join(types, ", ")));
+ throw new UnexpectedTypeException(String.format(
+ "Ambiguous validators for type %s. See: @%s at %s. Validators are: %s",
+ stringForType(targetType),
+ anno.annotationType().getSimpleName(),
+ stringForLocation(owner, access), types.stream()
+ .map(Object::toString).collect(Collectors.joining(", "))));
}
}
@@ -524,9 +529,13 @@ public class ConstraintValidation<T extends Annotation> implements Validation, C
* {@inheritDoc}
*/
@Override
- @SuppressWarnings("unchecked")
+ @SuppressWarnings({ "unchecked", "rawtypes" })
public Set<ConstraintDescriptor<?>> getComposingConstraints() {
- return composedConstraints == null ? Collections.EMPTY_SET : composedConstraints;
+ if (composedConstraints == null) {
+ return Collections.emptySet();
+ }
+ final Set result = composedConstraints;
+ return result;
}
/**
@@ -581,4 +590,16 @@ public class ConstraintValidation<T extends Annotation> implements Validation, C
public void setValidated(final boolean validated) {
this.validated = validated;
}
+
+ @Override
+ public ValidateUnwrappedValue getValueUnwrapping() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public <U> U unwrap(Class<U> arg0) {
+ // 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/ConstraintValidatorContextImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidatorContextImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidatorContextImpl.java
index 3599603..930170d 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidatorContextImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidatorContextImpl.java
@@ -25,6 +25,7 @@ import org.apache.bval.jsr.util.NodeImpl;
import org.apache.bval.jsr.util.PathImpl;
import org.apache.bval.model.ValidationListener;
+import javax.validation.ClockProvider;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Path;
@@ -38,7 +39,10 @@ import java.util.List;
* Description: Short-lived {@link ConstraintValidatorContext} implementation passed by
* a {@link ConstraintValidation} to its adapted {@link ConstraintValidator}. <br/>
*/
-public class ConstraintValidatorContextImpl implements ConstraintValidatorContext {
+@Deprecated
+public class ConstraintValidatorContextImpl
+ extends org.apache.bval.jsr.job.ConstraintValidatorContextImpl<Object>
+ implements ConstraintValidatorContext {
private final List<ValidationListener.Error> errorMessages = new LinkedList<ValidationListener.Error>();
private final ConstraintValidation<?> constraintDescriptor;
@@ -53,6 +57,7 @@ public class ConstraintValidatorContextImpl implements ConstraintValidatorContex
*/
public ConstraintValidatorContextImpl(GroupValidationContext<?> validationContext,
ConstraintValidation<?> aConstraintValidation) {
+ super();
this.validationContext = validationContext;
this.constraintDescriptor = aConstraintValidation;
}
@@ -154,6 +159,13 @@ public class ConstraintValidatorContextImpl implements ConstraintValidatorContex
parent.addError(messageTemplate, propertyPath);
return parent;
}
+
+ @Override
+ public ContainerElementNodeBuilderCustomizableContext addContainerElementNode(
+ String arg0, Class<?> arg1, Integer arg2) {
+ // TODO Auto-generated method stub
+ return null;
+ }
}
/**
@@ -190,4 +202,10 @@ public class ConstraintValidatorContextImpl implements ConstraintValidatorContex
public void addError(String messageTemplate, Path propertyPath) {
errorMessages.add(new ValidationListener.Error(messageTemplate, propertyPath, null));
}
+
+ @Override
+ public ClockProvider getClockProvider() {
+ // 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/ConstraintValidatorIdentity.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidatorIdentity.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidatorIdentity.java
index 1092323..572c39a 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidatorIdentity.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidatorIdentity.java
@@ -19,6 +19,8 @@
package org.apache.bval.jsr;
+import java.util.Objects;
+
import javax.validation.ConstraintValidator;
import javax.validation.Path;
@@ -120,12 +122,7 @@ final class ConstraintValidatorIdentity {
*/
@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.path == null) ? 0 : this.path.hashCode());
- result = prime * result + ((this.constraintValidator == null) ? 0 : this.constraintValidator.hashCode());
- return result;
+ return Objects.hash(bean, path, constraintValidator);
}
}
[03/11] bval git commit: implement BV 2.0 against existing BVal unit
tests
Posted by mb...@apache.org.
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeContextBuilderImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeContextBuilderImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeContextBuilderImpl.java
index 80e5b8f..f32db9f 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeContextBuilderImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeContextBuilderImpl.java
@@ -18,18 +18,19 @@
*/
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.ContainerElementNodeBuilderCustomizableContext;
import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.NodeContextBuilder;
/**
* Description: Implementation of {@link NodeContextBuilder}.<br/>
*/
-final class NodeContextBuilderImpl implements ConstraintValidatorContext.ConstraintViolationBuilder.NodeContextBuilder {
- private final ConstraintValidatorContextImpl parent;
- private final String messageTemplate;
- private final PathImpl propertyPath;
+public final class NodeContextBuilderImpl implements ConstraintValidatorContext.ConstraintViolationBuilder.NodeContextBuilder {
+ private final ConstraintValidatorContextImpl<?> context;
+ private final String template;
+ private final PathImpl path;
// The name of the last "added" node, it will only be added if it has a non-null name
// The actual incorporation in the path will take place when the definition of the current leaf node is complete
private final NodeImpl node;
@@ -40,10 +41,10 @@ final class NodeContextBuilderImpl implements ConstraintValidatorContext.Constra
* @param template
* @param path
*/
- NodeContextBuilderImpl(ConstraintValidatorContextImpl contextImpl, String template, PathImpl path, NodeImpl node) {
- parent = contextImpl;
- messageTemplate = template;
- propertyPath = path;
+ NodeContextBuilderImpl(ConstraintValidatorContextImpl<?> contextImpl, String template, PathImpl path, NodeImpl node) {
+ this.context = contextImpl;
+ this.template = template;
+ this.path = path;
this.node = node;
}
@@ -53,8 +54,8 @@ final class NodeContextBuilderImpl implements ConstraintValidatorContext.Constra
@Override
public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderDefinedContext atKey(Object key) {
node.setKey(key);
- propertyPath.addNode(node);
- return new NodeBuilderDefinedContextImpl(parent, messageTemplate, propertyPath);
+ path.addNode(node);
+ return new NodeBuilderDefinedContextImpl(context, template, path);
}
/**
@@ -63,8 +64,8 @@ final class NodeContextBuilderImpl implements ConstraintValidatorContext.Constra
@Override
public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderDefinedContext atIndex(Integer index) {
node.setIndex(index);
- propertyPath.addNode(node);
- return new NodeBuilderDefinedContextImpl(parent, messageTemplate, propertyPath);
+ path.addNode(node);
+ return new NodeBuilderDefinedContextImpl(context, template, path);
}
/**
@@ -78,14 +79,14 @@ final class NodeContextBuilderImpl implements ConstraintValidatorContext.Constra
@Override
public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext addPropertyNode(
String name) {
- propertyPath.addNode(node);
- return new NodeBuilderCustomizableContextImpl(parent, messageTemplate, propertyPath, name);
+ path.addNode(node);
+ return new NodeBuilderCustomizableContextImpl(context, template, path, name);
}
@Override
public ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeBuilderCustomizableContext addBeanNode() {
- propertyPath.addNode(node);
- return new LeafNodeBuilderCustomizableContextImpl(parent, messageTemplate, propertyPath);
+ path.addNode(node);
+ return new LeafNodeBuilderCustomizableContextImpl(context, template, path);
}
/**
@@ -93,9 +94,18 @@ final class NodeContextBuilderImpl implements ConstraintValidatorContext.Constra
*/
@Override
public ConstraintValidatorContext addConstraintViolation() {
- propertyPath.addNode(node);
- parent.addError(messageTemplate, propertyPath);
- return parent;
+ path.addNode(node);
+ context.addError(template, path);
+ return context;
}
-}
\ No newline at end of file
+ @Override
+ public ContainerElementNodeBuilderCustomizableContext addContainerElementNode(String name, Class<?> containerType,
+ Integer typeArgumentIndex) {
+ final NodeImpl node = new NodeImpl.ContainerElementNodeImpl(name, containerType, typeArgumentIndex);
+ path.addNode(node);
+ return new ContainerElementNodeBuilderCustomizableContextImpl(context, template, path, name, containerType,
+ typeArgumentIndex);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeImpl.java
index 5a08f0e..96f9421 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeImpl.java
@@ -21,16 +21,25 @@ package org.apache.bval.jsr.util;
import javax.validation.ElementKind;
import javax.validation.Path;
import javax.validation.Path.Node;
+
+import org.apache.bval.util.Exceptions;
+
import java.io.Serializable;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Consumer;
public class NodeImpl implements Path.Node, Serializable {
private static final long serialVersionUID = 1L;
private static final String INDEX_OPEN = "[";
private static final String INDEX_CLOSE = "]";
- private List<Class<?>> parameterTypes;
+
+ private static <T extends Path.Node> Optional<T> optional(Class<T> type, Object o) {
+ return Optional.ofNullable(o).filter(type::isInstance).map(type::cast);
+ }
/**
* Append a Node to the specified StringBuilder.
@@ -63,7 +72,7 @@ public class NodeImpl implements Path.Node, Serializable {
* @return NodeImpl
*/
public static NodeImpl atIndex(Integer index) {
- NodeImpl result = new NodeImpl();
+ final NodeImpl result = new NodeImpl();
result.setIndex(index);
return result;
}
@@ -74,7 +83,7 @@ public class NodeImpl implements Path.Node, Serializable {
* @return NodeImpl
*/
public static NodeImpl atKey(Object key) {
- NodeImpl result = new NodeImpl();
+ final NodeImpl result = new NodeImpl();
result.setKey(key);
return result;
}
@@ -85,6 +94,9 @@ public class NodeImpl implements Path.Node, Serializable {
private int parameterIndex;
private Object key;
private ElementKind kind;
+ private List<Class<?>> parameterTypes;
+ private Class<?> containerType;
+ private Integer typeArgumentIndex;
/**
* Create a new NodeImpl instance.
@@ -99,13 +111,18 @@ public class NodeImpl implements Path.Node, Serializable {
* @param node
*/
NodeImpl(Path.Node node) {
- this.name = node.getName();
+ this(node.getName());
this.inIterable = node.isInIterable();
this.index = node.getIndex();
this.key = node.getKey();
this.kind = node.getKind();
}
+ <T extends Path.Node> NodeImpl(Path.Node node, Class<T> nodeType, Consumer<T> handler) {
+ this(node);
+ Optional.of(node).filter(nodeType::isInstance).map(nodeType::cast).ifPresent(handler);
+ }
+
private NodeImpl() {
}
@@ -191,10 +208,8 @@ public class NodeImpl implements Path.Node, Serializable {
@Override
public <T extends Node> T as(final Class<T> nodeType) {
- if (nodeType.isInstance(this)) {
- return nodeType.cast(this);
- }
- throw new ClassCastException("Type " + nodeType + " not supported");
+ Exceptions.raiseUnless(nodeType.isInstance(this), ClassCastException::new, "Type %s not supported", nodeType);
+ return nodeType.cast(this);
}
/**
@@ -213,29 +228,13 @@ public class NodeImpl implements Path.Node, Serializable {
if (this == o) {
return true;
}
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- NodeImpl node = (NodeImpl) o;
-
- if (inIterable != node.inIterable) {
- return false;
- }
- if (index != null ? !index.equals(node.index) : node.index != null) {
- return false;
- }
- if (key != null ? !key.equals(node.key) : node.key != null) {
- return false;
- }
- if (name != null ? !name.equals(node.name) : node.name != null) {
- return false;
- }
- if (kind != null ? !kind.equals(node.kind) : node.kind != null) {
+ if (o == null || !getClass().equals(o.getClass())) {
return false;
}
+ final NodeImpl node = (NodeImpl) o;
- return true;
+ return inIterable == node.inIterable && Objects.equals(index, node.index) && Objects.equals(key, node.key)
+ && Objects.equals(name, node.name) && kind == node.kind;
}
/**
@@ -243,12 +242,7 @@ public class NodeImpl implements Path.Node, Serializable {
*/
@Override
public int hashCode() {
- int result = name != null ? name.hashCode() : 0;
- result = 31 * result + (inIterable ? 1 : 0);
- result = 31 * result + (index != null ? index.hashCode() : 0);
- result = 31 * result + (key != null ? key.hashCode() : 0);
- result = 31 * result + (kind != null ? kind.hashCode() : 0);
- return result;
+ return Objects.hash(name, Boolean.valueOf(inIterable), index, key, kind);
}
public int getParameterIndex() {
@@ -263,12 +257,24 @@ public class NodeImpl implements Path.Node, Serializable {
this.parameterTypes = parameterTypes;
}
+ public Class<?> getContainerClass() {
+ return containerType;
+ }
+
+ public Integer getTypeArgumentIndex() {
+ return typeArgumentIndex;
+ }
+
+ public void inContainer(Class<?> containerType, Integer typeArgumentIndex) {
+ this.containerType = containerType;
+ this.typeArgumentIndex = typeArgumentIndex;
+ }
+
+ @SuppressWarnings("serial")
public static class ParameterNodeImpl extends NodeImpl implements Path.ParameterNode {
public ParameterNodeImpl(final Node cast) {
super(cast);
- if (ParameterNodeImpl.class.isInstance(cast)) {
- setParameterIndex(ParameterNodeImpl.class.cast(cast).getParameterIndex());
- }
+ optional(Path.ParameterNode.class, cast).ifPresent(n -> setParameterIndex(n.getParameterIndex()));
}
public ParameterNodeImpl(final String name, final int idx) {
@@ -282,12 +288,11 @@ public class NodeImpl implements Path.Node, Serializable {
}
}
+ @SuppressWarnings("serial")
public static class ConstructorNodeImpl extends NodeImpl implements Path.ConstructorNode {
public ConstructorNodeImpl(final Node cast) {
super(cast);
- if (NodeImpl.class.isInstance(cast)) {
- setParameterTypes(NodeImpl.class.cast(cast).parameterTypes);
- }
+ optional(Path.ConstructorNode.class, cast).ifPresent(n -> setParameterTypes(n.getParameterTypes()));
}
public ConstructorNodeImpl(final String simpleName, List<Class<?>> paramTypes) {
@@ -301,6 +306,7 @@ public class NodeImpl implements Path.Node, Serializable {
}
}
+ @SuppressWarnings("serial")
public static class CrossParameterNodeImpl extends NodeImpl implements Path.CrossParameterNode {
public CrossParameterNodeImpl() {
super("<cross-parameter>");
@@ -316,12 +322,11 @@ public class NodeImpl implements Path.Node, Serializable {
}
}
+ @SuppressWarnings("serial")
public static class MethodNodeImpl extends NodeImpl implements Path.MethodNode {
public MethodNodeImpl(final Node cast) {
super(cast);
- if (MethodNodeImpl.class.isInstance(cast)) {
- setParameterTypes(MethodNodeImpl.class.cast(cast).getParameterTypes());
- }
+ optional(Path.MethodNode.class, cast).ifPresent(n -> setParameterTypes(n.getParameterTypes()));
}
public MethodNodeImpl(final String name, final List<Class<?>> classes) {
@@ -335,6 +340,7 @@ public class NodeImpl implements Path.Node, Serializable {
}
}
+ @SuppressWarnings("serial")
public static class ReturnValueNodeImpl extends NodeImpl implements Path.ReturnValueNode {
public ReturnValueNodeImpl(final Node cast) {
super(cast);
@@ -350,6 +356,7 @@ public class NodeImpl implements Path.Node, Serializable {
}
}
+ @SuppressWarnings("serial")
public static class PropertyNodeImpl extends NodeImpl implements Path.PropertyNode {
public PropertyNodeImpl(final String name) {
super(name);
@@ -357,6 +364,8 @@ public class NodeImpl implements Path.Node, Serializable {
public PropertyNodeImpl(final Node cast) {
super(cast);
+ optional(Path.PropertyNode.class, cast)
+ .ifPresent(n -> inContainer(n.getContainerClass(), n.getTypeArgumentIndex()));
}
@Override
@@ -365,6 +374,7 @@ public class NodeImpl implements Path.Node, Serializable {
}
}
+ @SuppressWarnings("serial")
public static class BeanNodeImpl extends NodeImpl implements Path.BeanNode {
public BeanNodeImpl() {
// no-op
@@ -372,6 +382,8 @@ public class NodeImpl implements Path.Node, Serializable {
public BeanNodeImpl(final Node cast) {
super(cast);
+ optional(Path.BeanNode.class, cast)
+ .ifPresent(n -> inContainer(n.getContainerClass(), n.getTypeArgumentIndex()));
}
@Override
@@ -379,4 +391,24 @@ public class NodeImpl implements Path.Node, Serializable {
return ElementKind.BEAN;
}
}
+
+ @SuppressWarnings("serial")
+ public static class ContainerElementNodeImpl extends NodeImpl implements Path.ContainerElementNode {
+
+ public ContainerElementNodeImpl(String name, Class<?> containerType, Integer typeArgumentIndex) {
+ super(name);
+ inContainer(containerType, typeArgumentIndex);
+ }
+
+ public ContainerElementNodeImpl(final Node cast) {
+ super(cast);
+ optional(Path.ContainerElementNode.class, cast)
+ .ifPresent(n -> inContainer(n.getContainerClass(), n.getTypeArgumentIndex()));
+ }
+
+ @Override
+ public ElementKind getKind() {
+ return ElementKind.CONTAINER_ELEMENT;
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathImpl.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathImpl.java
index 59fba83..430d257 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathImpl.java
@@ -18,16 +18,19 @@
*/
package org.apache.bval.jsr.util;
-import javax.validation.Path;
import java.io.Serializable;
-import java.util.ArrayList;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
+import java.util.Objects;
+
+import javax.validation.Path;
+
+import org.apache.bval.util.Exceptions;
/**
- * Description: object holding the property path as a list of nodes.
- * (Implementation partially based on reference implementation)
- * <br/>
+ * Description: object holding the property path as a list of nodes. (Implementation partially based on reference
+ * implementation) <br/>
* This class is not synchronized.
*
* @version $Rev: 1498347 $ $Date: 2013-07-01 12:06:18 +0200 (lun., 01 juil. 2013) $
@@ -41,8 +44,8 @@ public class PathImpl implements Path, Serializable {
/**
* Builds non-root paths from expressions.
*/
- private static class PathImplBuilder implements PathNavigation.Callback<PathImpl> {
- PathImpl result = new PathImpl();
+ public static class Builder implements PathNavigation.Callback<PathImpl> {
+ private final PathImpl result = PathImpl.create();
/**
* {@inheritDoc}
@@ -72,9 +75,6 @@ public class PathImpl implements Path, Serializable {
*/
@Override
public PathImpl result() {
- if (result.nodeList.isEmpty()) {
- throw new IllegalStateException();
- }
return result;
}
@@ -85,11 +85,8 @@ public class PathImpl implements Path, Serializable {
public void handleGenericInIterable() {
result.addNode(NodeImpl.atIndex(null));
}
-
}
- private final List<NodeImpl> nodeList;
-
/**
* Returns a {@code Path} instance representing the path described by the given string. To create a root node the
* empty string should be passed. Note: This signature is to maintain pluggability with the RI impl.
@@ -102,7 +99,7 @@ public class PathImpl implements Path, Serializable {
if (propertyPath == null || propertyPath.isEmpty()) {
return create();
}
- return PathNavigation.navigateAndReturn(propertyPath, new PathImplBuilder());
+ return PathNavigation.navigateAndReturn(propertyPath, new Builder());
}
/**
@@ -127,6 +124,10 @@ public class PathImpl implements Path, Serializable {
return path == null ? null : new PathImpl(path);
}
+ public static PathImpl of(Path path) {
+ return path instanceof PathImpl ? (PathImpl) path : copy(path);
+ }
+
private static NodeImpl newNode(final Node cast) {
if (PropertyNode.class.isInstance(cast)) {
return new NodeImpl.PropertyNodeImpl(cast);
@@ -140,9 +141,6 @@ public class PathImpl implements Path, Serializable {
if (ConstructorNode.class.isInstance(cast)) {
return new NodeImpl.ConstructorNodeImpl(cast);
}
- if (ConstructorNode.class.isInstance(cast)) {
- return new NodeImpl.ConstructorNodeImpl(cast);
- }
if (ReturnValueNode.class.isInstance(cast)) {
return new NodeImpl.ReturnValueNodeImpl(cast);
}
@@ -152,18 +150,19 @@ public class PathImpl implements Path, Serializable {
if (CrossParameterNode.class.isInstance(cast)) {
return new NodeImpl.CrossParameterNodeImpl(cast);
}
+ if (ContainerElementNode.class.isInstance(cast)) {
+ return new NodeImpl.ContainerElementNodeImpl(cast);
+ }
return new NodeImpl(cast);
}
+ private final LinkedList<NodeImpl> nodeList = new LinkedList<>();
+
private PathImpl() {
- nodeList = new ArrayList<NodeImpl>();
}
- private PathImpl(Iterable<Node> path) {
- this();
- for (final Node node : path) {
- nodeList.add(newNode(node));
- }
+ private PathImpl(Iterable<? extends Node> nodes) {
+ nodes.forEach(n -> nodeList.add(newNode(n)));
}
/**
@@ -176,7 +175,7 @@ public class PathImpl implements Path, Serializable {
if (nodeList.size() != 1) {
return false;
}
- Path.Node first = nodeList.get(0);
+ final Path.Node first = nodeList.peekFirst();
return !first.isInIterable() && first.getName() == null;
}
@@ -186,13 +185,10 @@ public class PathImpl implements Path, Serializable {
* @return PathImpl
*/
public PathImpl getPathWithoutLeafNode() {
- List<Node> nodes = new ArrayList<Node>(nodeList);
- PathImpl path = null;
- if (nodes.size() > 1) {
- nodes.remove(nodes.size() - 1);
- path = new PathImpl(nodes);
+ if (nodeList.size() < 2) {
+ return null;
}
- return path;
+ return new PathImpl(nodeList.subList(0, nodeList.size() - 1));
}
/**
@@ -202,12 +198,11 @@ public class PathImpl implements Path, Serializable {
* to add
*/
public void addNode(Node node) {
- NodeImpl impl = node instanceof NodeImpl ? (NodeImpl) node : newNode(node);
+ final NodeImpl impl = node instanceof NodeImpl ? (NodeImpl) node : newNode(node);
if (isRootPath()) {
- nodeList.set(0, impl);
- } else {
- nodeList.add(impl);
+ nodeList.pop();
}
+ nodeList.add(impl);
}
/**
@@ -229,7 +224,6 @@ public class PathImpl implements Path, Serializable {
return;
}
}
-
final NodeImpl node;
if ("<cross-parameter>".equals(name)) {
node = new NodeImpl.CrossParameterNodeImpl();
@@ -237,7 +231,6 @@ public class PathImpl implements Path, Serializable {
node = new NodeImpl.PropertyNodeImpl(name);
}
addNode(node);
-
}
/**
@@ -248,11 +241,10 @@ public class PathImpl implements Path, Serializable {
* if no nodes are found
*/
public NodeImpl removeLeafNode() {
- if (isRootPath() || nodeList.isEmpty()) {
- throw new IllegalStateException("No nodes in path!");
- }
+ Exceptions.raiseIf(isRootPath() || nodeList.isEmpty(), IllegalStateException::new, "No nodes in path!");
+
try {
- return nodeList.remove(nodeList.size() - 1);
+ return nodeList.removeLast();
} finally {
if (nodeList.isEmpty()) {
nodeList.add(new NodeImpl((String) null));
@@ -269,7 +261,7 @@ public class PathImpl implements Path, Serializable {
if (nodeList.isEmpty()) {
return null;
}
- return (NodeImpl) nodeList.get(nodeList.size() - 1);
+ return nodeList.peekLast();
}
/**
@@ -292,14 +284,14 @@ public class PathImpl implements Path, Serializable {
if (path instanceof PathImpl && ((PathImpl) path).isRootPath()) {
return true;
}
- Iterator<Node> pathIter = path.iterator();
- Iterator<Node> thisIter = iterator();
+ final Iterator<Node> pathIter = path.iterator();
+ final Iterator<Node> thisIter = iterator();
while (pathIter.hasNext()) {
- Node pathNode = pathIter.next();
+ final Node pathNode = pathIter.next();
if (!thisIter.hasNext()) {
return false;
}
- Node thisNode = thisIter.next();
+ final Node thisNode = thisIter.next();
if (pathNode.isInIterable()) {
if (!thisNode.isInIterable()) {
return false;
@@ -328,7 +320,7 @@ public class PathImpl implements Path, Serializable {
*/
@Override
public String toString() {
- StringBuilder builder = new StringBuilder();
+ final StringBuilder builder = new StringBuilder();
for (Path.Node node : this) {
NodeImpl.appendNode(node, builder);
}
@@ -346,9 +338,7 @@ public class PathImpl implements Path, Serializable {
if (o == null || !getClass().equals(o.getClass())) {
return false;
}
-
- PathImpl path = (PathImpl) o;
- return nodeList == path.nodeList || nodeList != null && nodeList.equals(path.nodeList);
+ return Objects.equals(nodeList, ((PathImpl) o).nodeList);
}
/**
@@ -356,7 +346,6 @@ public class PathImpl implements Path, Serializable {
*/
@Override
public int hashCode() {
- return nodeList == null ? 0 : nodeList.hashCode();
+ return Objects.hashCode(nodeList);
}
-
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathNavigation.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathNavigation.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathNavigation.java
index 36fb919..7ba6bc3 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathNavigation.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathNavigation.java
@@ -18,12 +18,17 @@ package org.apache.bval.jsr.util;
import javax.validation.ValidationException;
+import org.apache.bval.util.Exceptions;
import org.apache.commons.lang3.StringEscapeUtils;
+import org.apache.commons.lang3.Validate;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.text.ParsePosition;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import java.util.logging.Logger;
/**
@@ -67,13 +72,13 @@ public class PathNavigation {
/**
* Callback "procedure" that always returns null.
*/
- public static abstract class CallbackProcedure implements Callback<Object> {
+ public static abstract class CallbackProcedure implements Callback<Void> {
/**
* {@inheritDoc}
*/
@Override
- public final Object result() {
+ public final Void result() {
complete();
return null;
}
@@ -85,6 +90,34 @@ public class PathNavigation {
}
}
+ public static class CompositeCallbackProcedure extends CallbackProcedure {
+ private final List<Callback<?>> delegates;
+
+ public CompositeCallbackProcedure(Callback<?>... delegates) {
+ this(new ArrayList<>(Arrays.asList(delegates)));
+ }
+
+ public CompositeCallbackProcedure(List<Callback<?>> delegates) {
+ super();
+ this.delegates = Validate.notNull(delegates);
+ }
+
+ @Override
+ public void handleProperty(String name) {
+ delegates.forEach(d -> d.handleProperty(name));
+ }
+
+ @Override
+ public void handleIndexOrKey(String value) {
+ delegates.forEach(d -> d.handleIndexOrKey(value));
+ }
+
+ @Override
+ public void handleGenericInIterable() {
+ delegates.forEach(Callback::handleGenericInIterable);
+ }
+ }
+
private static class QuotedStringParser {
String parseQuotedString(CharSequence path, PathPosition pos) throws Exception {
final int len = path.length();
@@ -118,8 +151,7 @@ public class PathNavigation {
@Override
protected void handleNextChar(CharSequence path, PathPosition pos, Writer target) throws IOException {
- final int
- codePoints = StringEscapeUtils.UNESCAPE_JAVA.translate(path, pos.getIndex(), target);
+ final int codePoints = StringEscapeUtils.UNESCAPE_JAVA.translate(path, pos.getIndex(), target);
if (codePoints == 0) {
super.handleNextChar(path, pos, target);
} else {
@@ -128,13 +160,12 @@ public class PathNavigation {
}
}
}
-
}
private static final Logger LOG = Logger.getLogger(PathNavigation.class.getName());
private static final QuotedStringParser QUOTED_STRING_PARSER;
-
+
static {
QuotedStringParser quotedStringParser;
try {
@@ -164,10 +195,10 @@ public class PathNavigation {
public static <T> T navigateAndReturn(CharSequence propertyPath, Callback<? extends T> callback) {
try {
parse(propertyPath == null ? "" : propertyPath, new PathPosition(callback));
- } catch (ValidationException ex) {
+ } catch (ValidationException | IllegalArgumentException ex) {
throw ex;
- } catch (Exception ex) {
- throw new ValidationException(String.format("invalid property: %s", propertyPath), ex);
+ } catch (Exception e) {
+ Exceptions.raise(ValidationException::new, e, "invalid property: %s", propertyPath);
}
return callback.result();
}
@@ -190,23 +221,21 @@ public class PathNavigation {
char c = path.charAt(here);
switch (c) {
case ']':
- throw new IllegalStateException(String.format("Position %s: unexpected '%s'", here, c));
+ Exceptions.raise(IllegalStateException::new, "Position %s: unexpected '%s'", here, c);
case '[':
handleIndex(path, pos.next());
break;
case '.':
- if (sep) {
- throw new IllegalStateException(
- String.format("Position %s: expected property, index/key, or end of expression", here));
- }
+ Exceptions.raiseIf(sep, IllegalStateException::new,
+ "Position %s: expected property, index/key, or end of expression", here);
+
sep = true;
pos.next();
// fall through:
default:
- if (!sep) {
- throw new IllegalStateException(String.format(
- "Position %s: expected property path separator, index/key, or end of expression", here));
- }
+ Exceptions.raiseUnless(sep, IllegalStateException::new,
+ "Position %s: expected property path separator, index/key, or end of expression", here);
+
pos.handleProperty(parseProperty(path, pos));
}
sep = false;
@@ -214,8 +243,8 @@ public class PathNavigation {
}
private static String parseProperty(CharSequence path, PathPosition pos) throws Exception {
- int len = path.length();
- int start = pos.getIndex();
+ final int len = path.length();
+ final int start = pos.getIndex();
loop: while (pos.getIndex() < len) {
switch (path.charAt(pos.getIndex())) {
case '[':
@@ -225,27 +254,28 @@ public class PathNavigation {
}
pos.next();
}
- if (pos.getIndex() > start) {
- return path.subSequence(start, pos.getIndex()).toString();
- }
- throw new IllegalStateException(String.format("Position %s: expected property", start));
+ Exceptions.raiseIf(pos.getIndex() == start, IllegalStateException::new, "Position %s: expected property",
+ start);
+
+ return path.subSequence(start, pos.getIndex()).toString();
}
/**
* Handles an index/key. If the text contained between [] is surrounded by a pair of " or ', it will be treated as a
- * string which may contain Java escape sequences. This function is only available if commons-lang3 is available on the classpath!
+ * string which may contain Java escape sequences. This function is only available if commons-lang3 is available on
+ * the classpath!
*
* @param path
* @param pos
* @throws Exception
*/
private static void handleIndex(CharSequence path, PathPosition pos) throws Exception {
- int len = path.length();
- int start = pos.getIndex();
+ final int len = path.length();
+ final int start = pos.getIndex();
if (start < len) {
- char first = path.charAt(pos.getIndex());
+ final char first = path.charAt(pos.getIndex());
if (first == '"' || first == '\'') {
- String s = QUOTED_STRING_PARSER.parseQuotedString(path, pos);
+ final String s = QUOTED_STRING_PARSER.parseQuotedString(path, pos);
if (s != null && path.charAt(pos.getIndex()) == ']') {
pos.handleIndexOrKey(s);
pos.next();
@@ -254,7 +284,7 @@ public class PathNavigation {
}
// no quoted string; match ] greedily
while (pos.getIndex() < len) {
- int here = pos.getIndex();
+ final int here = pos.getIndex();
try {
if (path.charAt(here) == ']') {
if (here == start) {
@@ -269,13 +299,13 @@ public class PathNavigation {
}
}
}
- throw new IllegalStateException(String.format("Position %s: unparsable index", start));
+ Exceptions.raise(IllegalStateException::new, "Position %s: unparsable index", start);
}
/**
* ParsePosition/Callback
*/
- private static class PathPosition extends ParsePosition implements Callback<Object> {
+ private static class PathPosition extends ParsePosition implements Callback<Void> {
final Callback<?> delegate;
/**
@@ -336,7 +366,7 @@ public class PathNavigation {
* {@inheritDoc}
*/
@Override
- public Object result() {
+ public Void result() {
return null;
}
@@ -344,9 +374,8 @@ public class PathNavigation {
* {@inheritDoc}
*/
/*
- * Override equals to make findbugs happy;
- * would simply ignore but doesn't seem to be possible at the inner class level
- * without attaching the filter to the containing class.
+ * Override equals to make findbugs happy; would simply ignore but doesn't seem to be possible at the inner
+ * class level without attaching the filter to the containing class.
*/
@Override
public boolean equals(Object obj) {
@@ -364,5 +393,4 @@ public class PathNavigation {
return super.hashCode();
}
}
-
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/util/Proxies.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/Proxies.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/Proxies.java
index 1fa033c..1d0c1ee 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/util/Proxies.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/Proxies.java
@@ -26,7 +26,7 @@ public final class Proxies {
private static final Set<String> KNOWN_PROXY_CLASSNAMES;
static {
- final Set<String> s = new HashSet<String>();
+ final Set<String> s = new HashSet<>();
s.add("org.jboss.weld.bean.proxy.ProxyObject");
KNOWN_PROXY_CLASSNAMES = Collections.unmodifiableSet(s);
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/util/ToUnmodifiable.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/util/ToUnmodifiable.java b/bval-jsr/src/main/java/org/apache/bval/jsr/util/ToUnmodifiable.java
new file mode 100644
index 0000000..a470e0d
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/util/ToUnmodifiable.java
@@ -0,0 +1,34 @@
+package org.apache.bval.jsr.util;
+
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
+
+/**
+ * Utility {@link Collector} definitions.
+ */
+public class ToUnmodifiable {
+
+ public static <T> Collector<T, ?, Set<T>> set(Supplier<Set<T>> set) {
+ return Collectors.collectingAndThen(Collectors.toCollection(set), Collections::unmodifiableSet);
+ }
+
+ public static <T> Collector<T, ?, Set<T>> set() {
+ return Collectors.collectingAndThen(Collectors.toCollection(LinkedHashSet::new), Collections::unmodifiableSet);
+ }
+
+ public static <T> Collector<T, ?, List<T>> list() {
+ return Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList);
+ }
+
+ public static <T, K, U> Collector<T, ?, Map<K, U>> map(Function<? super T, ? extends K> keyMapper,
+ Function<? super T, ? extends U> valueMapper) {
+ return Collectors.collectingAndThen(Collectors.toMap(keyMapper, valueMapper), Collections::unmodifiableMap);
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/FxExtractor.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/FxExtractor.java b/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/FxExtractor.java
new file mode 100644
index 0000000..15601b2
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/FxExtractor.java
@@ -0,0 +1,96 @@
+/*
+ * 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.valueextraction;
+
+import java.util.Optional;
+import java.util.function.BooleanSupplier;
+
+import javax.validation.valueextraction.ExtractedValue;
+import javax.validation.valueextraction.UnwrapByDefault;
+import javax.validation.valueextraction.ValueExtractor;
+
+import org.apache.bval.util.reflection.Reflection;
+
+import javafx.beans.property.ReadOnlyListProperty;
+import javafx.beans.property.ReadOnlyMapProperty;
+import javafx.beans.property.ReadOnlySetProperty;
+import javafx.beans.value.ObservableValue;
+
+@SuppressWarnings("restriction")
+public abstract class FxExtractor {
+ public static class Activation implements BooleanSupplier {
+
+ @Override
+ public boolean getAsBoolean() {
+ try {
+ return Reflection.toClass("javafx.beans.Observable") != null;
+ } catch (ClassNotFoundException e) {
+ return false;
+ }
+ }
+ }
+
+ @UnwrapByDefault
+ public static class ForObservableValue implements ValueExtractor<ObservableValue<@ExtractedValue ?>> {
+
+ @Override
+ public void extractValues(ObservableValue<?> originalValue, ValueExtractor.ValueReceiver receiver) {
+ receiver.value(null, originalValue.getValue());
+ }
+ }
+
+ public static class ForListProperty implements ValueExtractor<ReadOnlyListProperty<@ExtractedValue ?>> {
+
+ @Override
+ public void extractValues(ReadOnlyListProperty<?> originalValue, ValueExtractor.ValueReceiver receiver) {
+ Optional.ofNullable(originalValue.getValue()).ifPresent(l -> {
+ for (int i = 0, sz = l.size(); i < sz; i++) {
+ receiver.indexedValue("<list element>", i, l.get(i));
+ }
+ });
+ }
+ }
+
+ public static class ForSetProperty implements ValueExtractor<ReadOnlySetProperty<@ExtractedValue ?>> {
+
+ @Override
+ public void extractValues(ReadOnlySetProperty<?> originalValue, ValueExtractor.ValueReceiver receiver) {
+ Optional.ofNullable(originalValue.getValue())
+ .ifPresent(s -> s.forEach(e -> receiver.iterableValue("<iterable element>", e)));
+ }
+ }
+
+ public static class ForMapPropertyKey implements ValueExtractor<ReadOnlyMapProperty<@ExtractedValue ?, ?>> {
+
+ @Override
+ public void extractValues(ReadOnlyMapProperty<?, ?> originalValue, ValueExtractor.ValueReceiver receiver) {
+ Optional.ofNullable(originalValue.getValue())
+ .ifPresent(m -> m.keySet().forEach(k -> receiver.keyedValue("<map key>", k, k)));
+ }
+ }
+
+ public static class ForMapPropertyValue implements ValueExtractor<ReadOnlyMapProperty<?, @ExtractedValue ?>> {
+
+ @Override
+ public void extractValues(ReadOnlyMapProperty<?, ?> originalValue, ValueExtractor.ValueReceiver receiver) {
+ Optional.ofNullable(originalValue.getValue()).ifPresent(
+ m -> m.entrySet().forEach(e -> receiver.keyedValue("<map value>", e.getKey(), e.getValue())));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/IterableElementExtractor.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/IterableElementExtractor.java b/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/IterableElementExtractor.java
new file mode 100644
index 0000000..8fd2fc0
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/IterableElementExtractor.java
@@ -0,0 +1,30 @@
+/*
+ * 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.valueextraction;
+
+import javax.validation.valueextraction.ExtractedValue;
+import javax.validation.valueextraction.ValueExtractor;
+
+public class IterableElementExtractor implements ValueExtractor<Iterable<@ExtractedValue ?>> {
+
+ @Override
+ public void extractValues(Iterable<?> originalValue, ValueExtractor.ValueReceiver receiver) {
+ originalValue.forEach(v -> receiver.iterableValue("<iterable element>", v));
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/ListElementExtractor.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/ListElementExtractor.java b/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/ListElementExtractor.java
new file mode 100644
index 0000000..bd84726
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/ListElementExtractor.java
@@ -0,0 +1,34 @@
+/*
+ * 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.valueextraction;
+
+import java.util.List;
+
+import javax.validation.valueextraction.ExtractedValue;
+import javax.validation.valueextraction.ValueExtractor;
+
+public class ListElementExtractor implements ValueExtractor<List<@ExtractedValue ?>> {
+
+ @Override
+ public void extractValues(List<?> originalValue, ValueExtractor.ValueReceiver receiver) {
+ for (int i = 0, sz = originalValue.size(); i < sz; i++) {
+ receiver.indexedValue("<list element>", i, originalValue.get(i));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/MapExtractor.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/MapExtractor.java b/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/MapExtractor.java
new file mode 100644
index 0000000..a6848b8
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/MapExtractor.java
@@ -0,0 +1,42 @@
+/*
+ * 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.valueextraction;
+
+import java.util.Map;
+
+import javax.validation.valueextraction.ExtractedValue;
+import javax.validation.valueextraction.ValueExtractor;
+
+public abstract class MapExtractor {
+ public static class ForKey implements ValueExtractor<Map<@ExtractedValue ?, ?>> {
+
+ @Override
+ public void extractValues(Map<?, ?> originalValue, ValueExtractor.ValueReceiver receiver) {
+ originalValue.keySet().forEach(k -> receiver.keyedValue("<map key>", k, k));
+ }
+ }
+
+ public static class ForValue implements ValueExtractor<Map<?, @ExtractedValue ?>> {
+
+ @Override
+ public void extractValues(Map<?, ?> originalValue, ValueExtractor.ValueReceiver receiver) {
+ originalValue.entrySet().forEach(e -> receiver.keyedValue("<map value>", e.getKey(), e.getValue()));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/OptionalExtractor.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/OptionalExtractor.java b/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/OptionalExtractor.java
new file mode 100644
index 0000000..5f073cc
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/OptionalExtractor.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.valueextraction;
+
+import java.util.Optional;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
+
+import javax.validation.valueextraction.ExtractedValue;
+import javax.validation.valueextraction.UnwrapByDefault;
+import javax.validation.valueextraction.ValueExtractor;
+
+public abstract class OptionalExtractor {
+ public static class ForObject implements ValueExtractor<Optional<@ExtractedValue ?>> {
+
+ @Override
+ public void extractValues(Optional<?> originalValue, ValueExtractor.ValueReceiver receiver) {
+ receiver.value(null, originalValue.orElse(null));
+ }
+ }
+
+ @UnwrapByDefault
+ public static class ForInt implements ValueExtractor<@ExtractedValue(type = Integer.class) OptionalInt> {
+
+ @Override
+ public void extractValues(OptionalInt originalValue, ValueExtractor.ValueReceiver receiver) {
+ receiver.value(null, originalValue.isPresent() ? Integer.valueOf(originalValue.getAsInt()) : null);
+ }
+ }
+
+ @UnwrapByDefault
+ public static class ForLong implements ValueExtractor<@ExtractedValue(type = Long.class) OptionalLong> {
+
+ @Override
+ public void extractValues(OptionalLong originalValue, ValueExtractor.ValueReceiver receiver) {
+ receiver.value(null, originalValue.isPresent() ? Long.valueOf(originalValue.getAsLong()) : null);
+ }
+ }
+
+ @UnwrapByDefault
+ public static class ForDouble implements ValueExtractor<@ExtractedValue(type = Double.class) OptionalDouble> {
+
+ @Override
+ public void extractValues(OptionalDouble originalValue, ValueExtractor.ValueReceiver receiver) {
+ receiver.value(null, originalValue.isPresent() ? Double.valueOf(originalValue.getAsDouble()) : null);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/ValueExtractors.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/ValueExtractors.java b/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/ValueExtractors.java
new file mode 100644
index 0000000..50feb6c
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/ValueExtractors.java
@@ -0,0 +1,181 @@
+/*
+ * 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.valueextraction;
+
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Properties;
+import java.util.Set;
+import java.util.function.BooleanSupplier;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import javax.validation.valueextraction.ValueExtractor;
+import javax.validation.valueextraction.ValueExtractorDeclarationException;
+import javax.validation.valueextraction.ValueExtractorDefinitionException;
+
+import org.apache.bval.jsr.metadata.ContainerElementKey;
+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.bval.util.reflection.TypeUtils;
+
+public class ValueExtractors {
+ public static final ValueExtractors DEFAULT;
+
+ static {
+ DEFAULT = new ValueExtractors(null) {
+ {
+ final Properties defaultExtractors = new Properties();
+ try {
+ defaultExtractors.load(ValueExtractors.class.getResourceAsStream("DefaultExtractors.properties"));
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ split(defaultExtractors.getProperty(ValueExtractor.class.getName())).map(cn -> {
+ try {
+ @SuppressWarnings("unchecked")
+ final Class<? extends ValueExtractor<?>> result =
+ (Class<? extends ValueExtractor<?>>) Reflection.toClass(cn)
+ .asSubclass(ValueExtractor.class);
+ return result;
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }).map(ValueExtractors::newInstance).forEach(super::add);
+
+ split(defaultExtractors.getProperty(ValueExtractor.class.getName() + ".container"))
+ .flatMap(ValueExtractors::loadValueExtractors).forEach(super::add);
+ }
+
+ @Override
+ public void add(ValueExtractor<?> extractor) {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ public static Class<?> getExtractedType(ValueExtractor<?> extractor, Type target) {
+ final ContainerElementKey key = ContainerElementKey.forValueExtractor(extractor);
+ Type result = key.getAnnotatedType().getType();
+ if (result instanceof TypeVariable<?>) {
+ result = TypeUtils.getTypeArguments(target, key.getContainerClass()).get(result);
+ }
+ Exceptions.raiseUnless(result instanceof Class<?>, ValueExtractorDefinitionException::new,
+ "%s did not resolve to a %s relative to %s", key, Class.class.getName(), target);
+ return (Class<?>) result;
+ }
+
+ private static Stream<String> split(String s) {
+ return Stream.of(StringUtils.split(s, ','));
+ }
+
+ private static <T> T newInstance(Class<T> t) {
+ try {
+ return t.newInstance();
+ } catch (InstantiationException | IllegalAccessException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private static Stream<ValueExtractor<?>> loadValueExtractors(String containerClassName) {
+ try {
+ final Class<? extends BooleanSupplier> activation =
+ Reflection.toClass(containerClassName + "$Activation").asSubclass(BooleanSupplier.class);
+ if (!newInstance(activation).getAsBoolean()) {
+ return Stream.empty();
+ }
+ } catch (ClassNotFoundException e) {
+ // always active
+ }
+ final Class<?> containerClass;
+ try {
+ containerClass = Reflection.toClass(containerClassName);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException(e);
+ }
+ return Stream.of(containerClass.getClasses()).filter(ValueExtractor.class::isAssignableFrom).map(c -> {
+ @SuppressWarnings("unchecked")
+ final Class<? extends ValueExtractor<?>> result =
+ (Class<? extends ValueExtractor<?>>) c.asSubclass(ValueExtractor.class);
+ return result;
+ }).map(ValueExtractors::newInstance);
+ }
+
+ private final Lazy<Map<ContainerElementKey, ValueExtractor<?>>> valueExtractors = new Lazy<>(HashMap::new);
+ private final ValueExtractors parent;
+
+ public ValueExtractors() {
+ this(DEFAULT);
+ }
+
+ private ValueExtractors(ValueExtractors parent) {
+ this.parent = parent;
+ }
+
+ public ValueExtractors createChild() {
+ return new ValueExtractors(this);
+ }
+
+ public void add(ValueExtractor<?> extractor) {
+ Validate.notNull(extractor);
+ valueExtractors.get().compute(ContainerElementKey.forValueExtractor(extractor), (k, v) -> {
+ Exceptions.raiseIf(v != null, ValueExtractorDeclarationException::new,
+ "Multiple context-level %ss specified for %s", ValueExtractor.class.getSimpleName(), k);
+ return extractor;
+ });
+ }
+
+ public Map<ContainerElementKey, ValueExtractor<?>> getValueExtractors() {
+ final Lazy<Map<ContainerElementKey, ValueExtractor<?>>> result = new Lazy<>(HashMap::new);
+ populate(result);
+ return result.optional().orElseGet(Collections::emptyMap);
+ }
+
+ public ValueExtractor<?> find(ContainerElementKey key) {
+ final Map<ContainerElementKey, ValueExtractor<?>> allValueExtractors = getValueExtractors();
+ if (allValueExtractors.containsKey(key)) {
+ return allValueExtractors.get(key);
+ }
+ // search for assignable ContainerElementKey:
+ Set<ContainerElementKey> assignableKeys = key.getAssignableKeys();
+ while (!assignableKeys.isEmpty()) {
+ final Optional<ValueExtractor<?>> found = assignableKeys.stream().filter(allValueExtractors::containsKey)
+ .<ValueExtractor<?>> map(allValueExtractors::get).findFirst();
+ if (found.isPresent()) {
+ return found.get();
+ }
+ assignableKeys = assignableKeys.stream().map(ContainerElementKey::getAssignableKeys)
+ .flatMap(Collection::stream).collect(Collectors.toSet());
+ }
+ return null;
+ }
+
+ protected void populate(Supplier<Map<ContainerElementKey, ValueExtractor<?>>> target) {
+ Optional.ofNullable(parent).ifPresent(p -> p.populate(target));
+ valueExtractors.optional().ifPresent(m -> target.get().putAll(m));
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxy.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxy.java b/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxy.java
index 77aed70..96a2b46 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxy.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxy.java
@@ -16,20 +16,21 @@
*/
package org.apache.bval.jsr.xml;
-import javax.validation.Valid;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.SortedSet;
-import java.util.TreeSet;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
+import javax.validation.Valid;
+
+import org.apache.bval.util.Exceptions;
/**
* Description: <br/>
- * InvocationHandler implementation of <code>Annotation</code> that pretends it
- * is a "real" source code annotation.
+ * InvocationHandler implementation of <code>Annotation</code> that pretends it is a "real" source code annotation.
* <p/>
*/
class AnnotationProxy implements Annotation, InvocationHandler, Serializable {
@@ -38,7 +39,7 @@ class AnnotationProxy implements Annotation, InvocationHandler, Serializable {
private static final long serialVersionUID = 1L;
private final Class<? extends Annotation> annotationType;
- private final Map<String, Object> values;
+ private final SortedMap<String, Object> values;
/**
* Create a new AnnotationProxy instance.
@@ -46,28 +47,23 @@ class AnnotationProxy implements Annotation, InvocationHandler, Serializable {
* @param <A>
* @param descriptor
*/
- public <A extends Annotation> AnnotationProxy(AnnotationProxyBuilder<A> descriptor) {
+ <A extends Annotation> AnnotationProxy(AnnotationProxyBuilder<A> descriptor) {
this.annotationType = descriptor.getType();
- values = getAnnotationValues(descriptor);
- }
-
- private <A extends Annotation> Map<String, Object> getAnnotationValues(AnnotationProxyBuilder<A> descriptor) {
- final Map<String, Object> result = new HashMap<String, Object>();
+ values = new TreeMap<>();
int processedValuesFromDescriptor = 0;
for (final Method m : descriptor.getMethods()) {
if (descriptor.contains(m.getName())) {
- result.put(m.getName(), descriptor.getValue(m.getName()));
+ values.put(m.getName(), descriptor.getValue(m.getName()));
processedValuesFromDescriptor++;
- } else if (m.getDefaultValue() != null) {
- result.put(m.getName(), m.getDefaultValue());
} else {
- throw new IllegalArgumentException("No value provided for " + m.getName());
+ Exceptions.raiseIf(m.getDefaultValue() == null, IllegalArgumentException::new,
+ "No value provided for %s", m.getName());
+ values.put(m.getName(), m.getDefaultValue());
}
}
- if (processedValuesFromDescriptor != descriptor.size() && !Valid.class.equals(annotationType)) {
- throw new RuntimeException("Trying to instanciate " + annotationType + " with unknown paramters.");
- }
- return result;
+ Exceptions.raiseUnless(processedValuesFromDescriptor == descriptor.size() || Valid.class.equals(annotationType),
+ IllegalArgumentException::new, "Trying to instantiate %s with unknown parameters.",
+ annotationType.getName());
}
/**
@@ -94,22 +90,7 @@ class AnnotationProxy implements Annotation, InvocationHandler, Serializable {
*/
@Override
public String toString() {
- StringBuilder result = new StringBuilder();
- result.append('@').append(annotationType().getName()).append('(');
- boolean comma = false;
- for (String m : getMethodsSorted()) {
- if (comma)
- result.append(", ");
- result.append(m).append('=').append(values.get(m));
- comma = true;
- }
- result.append(")");
- return result.toString();
- }
-
- private SortedSet<String> getMethodsSorted() {
- SortedSet<String> result = new TreeSet<String>();
- result.addAll(values.keySet());
- return result;
+ return values.entrySet().stream().map(e -> String.format("%s=%s", e.getKey(), e.getValue()))
+ .collect(Collectors.joining(", ", String.format("@%s(", annotationType().getName()), ")"));
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxyBuilder.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxyBuilder.java b/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxyBuilder.java
index dedfabc..02383cb 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxyBuilder.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxyBuilder.java
@@ -30,10 +30,12 @@ import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.enterprise.util.AnnotationLiteral;
+import javax.validation.ConstraintTarget;
import javax.validation.Payload;
import javax.validation.Valid;
import javax.validation.ValidationException;
@@ -45,11 +47,21 @@ import javax.validation.groups.ConvertGroup;
*/
@Privilizing(@CallTo(Reflection.class))
public final class AnnotationProxyBuilder<A extends Annotation> {
- private static final ConcurrentMap<Class<?>, Method[]> METHODS_CACHE = new ConcurrentHashMap<Class<?>, Method[]>();
+ private static final ConcurrentMap<Class<?>, Method[]> METHODS_CACHE = new ConcurrentHashMap<>();
+
+ public static <A> Method[] findMethods(final Class<A> annotationType) {
+ // cache only built-in constraints to avoid memory leaks:
+ // TODO use configurable cache size property?
+ if (annotationType.getName().startsWith("javax.validation.constraints.")) {
+ return METHODS_CACHE.computeIfAbsent(annotationType, Reflection::getDeclaredMethods);
+ }
+ return Reflection.getDeclaredMethods(annotationType);
+ }
private final Class<A> type;
- private final Map<String, Object> elements = new HashMap<String, Object>();
+ private final Map<String, Object> elements = new HashMap<>();
private final Method[] methods;
+ private boolean changed;
/**
* Create a new AnnotationProxyBuilder instance.
@@ -61,21 +73,6 @@ public final class AnnotationProxyBuilder<A extends Annotation> {
this.methods = findMethods(annotationType);
}
- public static <A> Method[] findMethods(final Class<A> annotationType) {
- if (annotationType.getName().startsWith("javax.validation.constraints.")) { // cache built-in constraints only to avoid mem leaks
- Method[] mtd = METHODS_CACHE.get(annotationType);
- if (mtd == null) {
- final Method[] value = Reflection.getDeclaredMethods(annotationType);
- mtd = METHODS_CACHE.putIfAbsent(annotationType, value);
- if (mtd == null) {
- mtd = value;
- }
- }
- return mtd;
- }
- return Reflection.getDeclaredMethods(annotationType);
- }
-
/**
* Create a new AnnotationProxyBuilder instance.
*
@@ -84,16 +81,15 @@ public final class AnnotationProxyBuilder<A extends Annotation> {
*/
public AnnotationProxyBuilder(Class<A> annotationType, Map<String, Object> elements) {
this(annotationType);
- for (Map.Entry<String, Object> entry : elements.entrySet()) {
- this.elements.put(entry.getKey(), entry.getValue());
- }
+ elements.forEach(this.elements::put);
}
/**
* Create a builder initially configured to create an annotation equivalent
- * to <code>annot</code>.
+ * to {@code annot}.
*
- * @param annot Annotation to be replicated.
+ * @param annot
+ * Annotation to be replicated.
*/
@SuppressWarnings("unchecked")
public AnnotationProxyBuilder(A annot) {
@@ -102,8 +98,7 @@ public final class AnnotationProxyBuilder<A extends Annotation> {
for (Method m : methods) {
final boolean mustUnset = Reflection.setAccessible(m, true);
try {
- Object value = m.invoke(annot);
- this.elements.put(m.getName(), value);
+ this.elements.put(m.getName(), m.invoke(annot));
} catch (Exception e) {
throw new ValidationException("Cannot access annotation " + annot + " element: " + m.getName(), e);
} finally {
@@ -124,8 +119,22 @@ public final class AnnotationProxyBuilder<A extends Annotation> {
* @param elementName
* @param value
*/
- public void putValue(String elementName, Object value) {
- elements.put(elementName, value);
+ @Deprecated
+ public Object putValue(String elementName, Object value) {
+ return elements.put(elementName, value);
+ }
+
+ /**
+ * Add an element to the configuration.
+ *
+ * @param elementName
+ * @param value
+ * @return whether any change occurred
+ */
+ public boolean setValue(String elementName, Object value) {
+ final boolean result = !Objects.equals(elements.put(elementName, value), value);
+ changed |= result;
+ return result;
}
/**
@@ -171,27 +180,42 @@ public final class AnnotationProxyBuilder<A extends Annotation> {
* Configure the well-known JSR303 "message" element.
*
* @param message
+ * @return
*/
- public void setMessage(String message) {
- ConstraintAnnotationAttributes.MESSAGE.put(elements, message);
+ public boolean setMessage(String message) {
+ return setValue(ConstraintAnnotationAttributes.MESSAGE.getAttributeName(), message);
}
/**
* Configure the well-known JSR303 "groups" element.
*
* @param groups
+ * @return
*/
- public void setGroups(Class<?>[] groups) {
- ConstraintAnnotationAttributes.GROUPS.put(elements, groups);
+ public boolean setGroups(Class<?>[] groups) {
+ return setValue(ConstraintAnnotationAttributes.GROUPS.getAttributeName(), groups);
}
/**
* Configure the well-known JSR303 "payload" element.
*
* @param payload
+ * @return
+ */
+ public boolean setPayload(Class<? extends Payload>[] payload) {
+ return setValue(ConstraintAnnotationAttributes.PAYLOAD.getAttributeName(), payload);
+ }
+
+ /**
+ * Configure the well-known "validationAppliesTo" element.
+ *
+ * @param constraintTarget
*/
- public void setPayload(Class<? extends Payload>[] payload) {
- ConstraintAnnotationAttributes.PAYLOAD.put(elements, payload);
+ public boolean setValidationAppliesTo(ConstraintTarget constraintTarget) {
+ return setValue(ConstraintAnnotationAttributes.VALIDATION_APPLIES_TO.getAttributeName(), constraintTarget);
+ }
+ public boolean isChanged() {
+ return changed;
}
/**
@@ -203,16 +227,22 @@ public final class AnnotationProxyBuilder<A extends Annotation> {
final ClassLoader classLoader = Reflection.getClassLoader(getType());
@SuppressWarnings("unchecked")
final Class<A> proxyClass = (Class<A>) Proxy.getProxyClass(classLoader, getType());
- final InvocationHandler handler = new AnnotationProxy(this);
- return doCreateAnnotation(proxyClass, handler);
+ return doCreateAnnotation(proxyClass, new AnnotationProxy(this));
}
@Privileged
private A doCreateAnnotation(final Class<A> proxyClass, final InvocationHandler handler) {
try {
- Constructor<A> constructor = proxyClass.getConstructor(InvocationHandler.class);
- Reflection.setAccessible(constructor, true); // java 8
- return constructor.newInstance(handler);
+ final Constructor<A> constructor = proxyClass.getConstructor(InvocationHandler.class);
+ final boolean mustUnset = Reflection.setAccessible(constructor, true); // java
+ // 8
+ try {
+ return constructor.newInstance(handler);
+ } finally {
+ if (mustUnset) {
+ Reflection.setAccessible(constructor, false);
+ }
+ }
} catch (Exception e) {
throw new ValidationException("Unable to create annotation for configured constraint", e);
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-jsr/src/main/java/org/apache/bval/jsr/xml/SchemaManager.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/xml/SchemaManager.java b/bval-jsr/src/main/java/org/apache/bval/jsr/xml/SchemaManager.java
new file mode 100644
index 0000000..a502b7e
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/xml/SchemaManager.java
@@ -0,0 +1,286 @@
+/*
+ * 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.xml;
+
+import java.net.URL;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.function.Function;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.xml.XMLConstants;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.UnmarshallerHandler;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import javax.xml.validation.ValidatorHandler;
+
+import org.apache.bval.util.Lazy;
+import org.apache.bval.util.reflection.Reflection;
+import org.w3c.dom.Document;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.AttributesImpl;
+import org.xml.sax.helpers.XMLFilterImpl;
+
+/**
+ * Unmarshals XML converging on latest schema version. Presumes backward compatiblity between schemae.
+ */
+public class SchemaManager {
+ public static class Builder {
+ private final SortedMap<Key, Lazy<Schema>> data = new TreeMap<>();
+
+ public Builder add(String version, String ns, String resource) {
+ data.put(new Key(version, ns), new Lazy<>(() -> SchemaManager.loadSchema(resource)));
+ return this;
+ }
+
+ public SchemaManager build() {
+ return new SchemaManager(new TreeMap<>(data));
+ }
+ }
+
+ private static class Key implements Comparable<Key> {
+ private static final Comparator<Key> CMP = Comparator.comparing(Key::getVersion).thenComparing(Key::getNs);
+
+ final String version;
+ final String ns;
+
+ Key(String version, String ns) {
+ super();
+ this.version = Objects.toString(version, "");
+ this.ns = Objects.toString(ns, "");
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public String getNs() {
+ return ns;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ return Optional.ofNullable(obj).filter(SchemaManager.Key.class::isInstance)
+ .map(SchemaManager.Key.class::cast)
+ .filter(k -> Objects.equals(this.version, k.version) && Objects.equals(this.ns, k.ns)).isPresent();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(version, ns);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s:%s", version, ns);
+ }
+
+ @Override
+ public int compareTo(Key o) {
+ return CMP.compare(this, o);
+ }
+ }
+
+ private class DynamicValidatorHandler extends XMLFilterImpl {
+ ContentHandler ch;
+ SAXParseException e;
+
+ @Override
+ public void setContentHandler(ContentHandler handler) {
+ super.setContentHandler(handler);
+ this.ch = handler;
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
+ if (getContentHandler() == ch) {
+ final Key schemaKey = new Key(Objects.toString(atts.getValue("version"), ""), uri);
+ if (data.containsKey(schemaKey)) {
+ final Schema schema = data.get(schemaKey).get();
+ final ValidatorHandler vh = schema.newValidatorHandler();
+ vh.startDocument();
+ vh.setContentHandler(ch);
+ super.setContentHandler(vh);
+ }
+ }
+ try {
+ super.startElement(uri, localName, qName, atts);
+ } catch (SAXParseException e) {
+ this.e = e;
+ }
+ }
+
+ @Override
+ public void error(SAXParseException e) throws SAXException {
+ this.e = e;
+ super.error(e);
+ }
+
+ @Override
+ public void fatalError(SAXParseException e) throws SAXException {
+ this.e = e;
+ super.fatalError(e);
+ }
+
+ void validate() throws SAXParseException {
+ if (e != null) {
+ throw e;
+ }
+ }
+ }
+
+ //@formatter:off
+ private enum XmlAttributeType {
+ CDATA, ID, IDREF, IDREFS, NMTOKEN, NMTOKENS, ENTITY, ENTITIES, NOTATION;
+ //@formatter:on
+ }
+
+ private class SchemaRewriter extends XMLFilterImpl {
+ private boolean root = true;
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
+ final Key schemaKey = new Key(Objects.toString(atts.getValue("version"), ""), uri);
+
+ if (!target.equals(schemaKey) && data.containsKey(schemaKey)) {
+ uri = target.ns;
+ if (root) {
+ atts = rewrite(atts);
+ root = false;
+ }
+ }
+ super.startElement(uri, localName, qName, atts);
+ }
+
+ private Attributes rewrite(Attributes atts) {
+ final AttributesImpl result;
+ if (atts instanceof AttributesImpl) {
+ result = (AttributesImpl) atts;
+ } else {
+ result = new AttributesImpl(atts);
+ }
+ set(result, "", VERSION_ATTRIBUTE, "", XmlAttributeType.CDATA, target.version);
+ return result;
+ }
+
+ private void set(AttributesImpl attrs, String uri, String localName, String qName, XmlAttributeType type,
+ String value) {
+ for (int i = 0, sz = attrs.getLength(); i < sz; i++) {
+ if (Objects.equals(qName, attrs.getQName(i))
+ || Objects.equals(uri, attrs.getURI(i)) && Objects.equals(localName, attrs.getLocalName(i))) {
+ attrs.setAttribute(i, uri, localName, qName, type.name(), value);
+ return;
+ }
+ }
+ attrs.addAttribute(uri, localName, qName, type.name(), value);
+ }
+ }
+
+ public static final String VERSION_ATTRIBUTE = "version";
+
+ private static final Logger log = Logger.getLogger(SchemaManager.class.getName());
+ private static final SchemaFactory SCHEMA_FACTORY = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+ private static final SAXParserFactory SAX_PARSER_FACTORY;
+
+ static {
+ SAX_PARSER_FACTORY = SAXParserFactory.newInstance();
+ SAX_PARSER_FACTORY.setNamespaceAware(true);
+ }
+
+ static Schema loadSchema(String resource) {
+ final URL schemaUrl = Reflection.getClassLoader(XmlUtils.class).getResource(resource);
+ try {
+ return SCHEMA_FACTORY.newSchema(schemaUrl);
+ } catch (SAXException e) {
+ log.log(Level.WARNING, String.format("Unable to parse schema: %s", resource), e);
+ return null;
+ }
+ }
+
+ private static Class<?> getObjectFactory(Class<?> type) throws ClassNotFoundException {
+ final String className = String.format("%s.%s", type.getPackage().getName(), "ObjectFactory");
+ return Reflection.toClass(className, type.getClassLoader());
+ }
+
+ private final Key target;
+ private final SortedMap<Key, Lazy<Schema>> data;
+ private final String description;
+
+ private SchemaManager(SortedMap<Key, Lazy<Schema>> data) {
+ super();
+ this.data = Collections.unmodifiableSortedMap(data);
+ this.target = data.lastKey();
+ this.description = target.ns.substring(target.ns.lastIndexOf('/') + 1);
+ }
+
+ public Optional<Schema> getSchema(String ns, String version) {
+ return Optional.of(new Key(version, ns)).map(data::get).map(Lazy::get);
+ }
+
+ public Optional<Schema> getSchema(Document document) {
+ return Optional.ofNullable(document).map(Document::getDocumentElement)
+ .map(e -> getSchema(e.getAttribute(XMLConstants.XMLNS_ATTRIBUTE), e.getAttribute(VERSION_ATTRIBUTE))).get();
+ }
+
+ public <E extends Exception> Schema requireSchema(Document document, Function<String, E> exc) throws E {
+ return getSchema(document).orElseThrow(() -> Objects.requireNonNull(exc, "exc")
+ .apply(String.format("Unknown %s schema", Objects.toString(description, ""))));
+ }
+
+ public <T> T unmarshal(InputSource input, Class<T> type) throws Exception {
+ final XMLReader xmlReader = SAX_PARSER_FACTORY.newSAXParser().getXMLReader();
+
+ // validate specified schema:
+ final DynamicValidatorHandler schemaValidator = new DynamicValidatorHandler();
+ xmlReader.setContentHandler(schemaValidator);
+
+ // rewrite to latest schema, if required:
+ final SchemaRewriter schemaRewriter = new SchemaRewriter();
+ schemaValidator.setContentHandler(schemaRewriter);
+
+ JAXBContext jc = JAXBContext.newInstance(getObjectFactory(type));
+ // unmarshal:
+ final UnmarshallerHandler unmarshallerHandler = jc.createUnmarshaller().getUnmarshallerHandler();
+ schemaRewriter.setContentHandler(unmarshallerHandler);
+
+ xmlReader.parse(input);
+
+ schemaValidator.validate();
+
+ @SuppressWarnings("unchecked")
+ final JAXBElement<T> result = (JAXBElement<T>) unmarshallerHandler.getResult();
+ return result.getValue();
+ }
+}
[11/11] bval git commit: implement BV 2.0 against existing BVal unit
tests
Posted by mb...@apache.org.
implement BV 2.0 against existing BVal unit tests
Project: http://git-wip-us.apache.org/repos/asf/bval/repo
Commit: http://git-wip-us.apache.org/repos/asf/bval/commit/3f287a7a
Tree: http://git-wip-us.apache.org/repos/asf/bval/tree/3f287a7a
Diff: http://git-wip-us.apache.org/repos/asf/bval/diff/3f287a7a
Branch: refs/heads/bv2
Commit: 3f287a7aff06ac0eaa10711d55afa5d79b8d9dbd
Parents: cd050cf
Author: Matt Benson <mb...@apache.org>
Authored: Wed Nov 15 14:47:45 2017 -0600
Committer: Matt Benson <mb...@apache.org>
Committed: Wed Feb 21 14:23:23 2018 -0600
----------------------------------------------------------------------
bundle/pom.xml | 2 +-
bval-core/pom.xml | 2 +-
.../bval/routines/EMailValidationUtils.java | 7 +-
.../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-extras/pom.xml | 4 +-
.../constraints/checkdigit/ABANumber.java | 4 +-
.../extras/constraints/checkdigit/CUSIP.java | 4 +-
.../extras/constraints/checkdigit/EAN13.java | 4 +-
.../extras/constraints/checkdigit/IBAN.java | 4 +-
.../constraints/checkdigit/IBANValidator.java | 8 +-
.../extras/constraints/checkdigit/ISBN10.java | 4 +-
.../extras/constraints/checkdigit/Luhn.java | 4 +-
.../checkdigit/ModulusValidator.java | 4 +-
.../extras/constraints/checkdigit/Sedol.java | 4 +-
.../extras/constraints/checkdigit/Verhoeff.java | 4 +-
.../checkdigit/VerhoeffValidator.java | 4 +-
.../constraints/creditcard/AmericanExpress.java | 4 +-
.../extras/constraints/creditcard/Diners.java | 4 +-
.../extras/constraints/creditcard/Discover.java | 4 +-
.../constraints/creditcard/Mastercard.java | 4 +-
.../constraints/file/DirectoryValidator.java | 2 +-
.../constraints/file/SymlinkValidator.java | 2 +-
.../extras/constraints/net/DomainValidator.java | 33 +-
.../constraints/net/InetAddressValidator.java | 4 +-
.../checkdigit/ABANumberValidatorTest.java | 2 +-
.../checkdigit/AbstractCheckDigitTest.java | 4 +-
.../checkdigit/CUSIPValidatorTest.java | 2 +-
.../checkdigit/EAN13CheckDigitTest.java | 2 +-
.../checkdigit/IBANCheckDigitTest.java | 2 +-
.../checkdigit/ISBN10CheckDigitTest.java | 2 +-
.../checkdigit/LuhnCheckDigitTest.java | 2 +-
.../checkdigit/SedolCheckDigitTest.java | 2 +-
.../checkdigit/VerhoeffCheckDigitTest.java | 2 +-
.../net/InetAddressValidatorTest.java | 2 +-
bval-json/pom.xml | 2 +-
bval-jsr/pom.xml | 19 +-
.../java/org/apache/bval/cdi/AnyLiteral.java | 3 +-
.../org/apache/bval/cdi/BValAnnotatedType.java | 33 +-
.../java/org/apache/bval/cdi/BValExtension.java | 18 +-
.../org/apache/bval/cdi/BValInterceptor.java | 28 +-
.../apache/bval/cdi/BValInterceptorBean.java | 6 +-
.../org/apache/bval/cdi/DefaultLiteral.java | 3 +-
.../apache/bval/cdi/EmptyAnnotationLiteral.java | 24 +-
.../java/org/apache/bval/cdi/ValidatorBean.java | 6 +-
.../apache/bval/cdi/ValidatorFactoryBean.java | 6 +-
.../bval/constraints/AssertFalseValidator.java | 6 +-
.../bval/constraints/AssertTrueValidator.java | 6 +-
.../DecimalMaxValidatorForNumber.java | 12 +-
.../DecimalMaxValidatorForString.java | 2 +-
.../DecimalMinValidatorForNumber.java | 12 +-
.../DecimalMinValidatorForString.java | 2 +-
.../java/org/apache/bval/constraints/Email.java | 15 +-
.../apache/bval/constraints/EmailValidator.java | 7 +-
.../constraints/FutureOrPresentValidator.java | 138 ++++
.../bval/constraints/FutureValidator.java | 138 ++++
.../bval/constraints/MaxValidatorForNumber.java | 4 +-
.../bval/constraints/MaxValidatorForString.java | 2 +-
.../bval/constraints/MinValidatorForNumber.java | 4 +-
.../bval/constraints/MinValidatorForString.java | 2 +-
.../bval/constraints/NotBlankValidator.java | 34 +
.../org/apache/bval/constraints/NotEmpty.java | 28 +-
.../bval/constraints/NotEmptyValidator.java | 19 +-
.../NotEmptyValidatorForCharSequence.java | 34 +
.../NotEmptyValidatorForCollection.java | 7 +-
.../constraints/NotEmptyValidatorForMap.java | 6 +-
.../constraints/NotEmptyValidatorForString.java | 37 -
.../bval/constraints/NotNullValidator.java | 4 -
.../apache/bval/constraints/NullValidator.java | 5 -
.../bval/constraints/NumberSignValidator.java | 68 ++
.../constraints/PastOrPresentValidator.java | 138 ++++
.../apache/bval/constraints/PastValidator.java | 138 ++++
.../bval/constraints/PatternValidator.java | 4 +-
.../apache/bval/constraints/TimeValidator.java | 44 ++
.../apache/bval/context/ValidationContext.java | 125 ++++
.../main/java/org/apache/bval/el/ELFacade.java | 16 +-
.../bval/jsr/AbstractConstraintDescriptor.java | 32 +
.../bval/jsr/AnnotationConstraintBuilder.java | 38 +-
.../apache/bval/jsr/AnnotationProcessor.java | 24 +-
.../apache/bval/jsr/ApacheFactoryContext.java | 83 +-
.../bval/jsr/ApacheValidatorConfiguration.java | 7 +-
.../apache/bval/jsr/ApacheValidatorFactory.java | 171 +++--
.../bval/jsr/BootstrapConfigurationImpl.java | 29 +-
.../bval/jsr/CascadingPropertyValidator.java | 96 ++-
.../org/apache/bval/jsr/ConfigurationImpl.java | 128 ++--
.../jsr/ConstraintAnnotationAttributes.java | 46 +-
.../org/apache/bval/jsr/ConstraintCached.java | 143 +++-
.../org/apache/bval/jsr/ConstraintDefaults.java | 103 +--
.../bval/jsr/ConstraintDescriptorImpl.java | 13 +
.../apache/bval/jsr/ConstraintValidation.java | 33 +-
.../jsr/ConstraintValidatorContextImpl.java | 20 +-
.../bval/jsr/ConstraintValidatorIdentity.java | 9 +-
.../bval/jsr/ConstraintViolationImpl.java | 94 +--
.../jsr/DefaultConstraintValidatorFactory.java | 12 +-
.../bval/jsr/DefaultMessageInterpolator.java | 35 +-
.../jsr/DefaultValidationProviderResolver.java | 50 +-
.../org/apache/bval/jsr/GraphBeanIdentity.java | 28 +-
.../java/org/apache/bval/jsr/GraphContext.java | 95 +++
.../jsr/NodeBuilderCustomizableContextImpl.java | 89 +++
.../apache/bval/jsr/NodeContextBuilderImpl.java | 88 +++
.../bval/jsr/ParameterDescriptorImpl.java | 7 +
.../apache/bval/jsr/PropertyDescriptorImpl.java | 9 +
.../bval/jsr/ReturnValueDescriptorImpl.java | 8 +
.../java/org/apache/bval/jsr/ValidatorImpl.java | 141 ++++
.../org/apache/bval/jsr/descriptor/BeanD.java | 128 ++++
.../jsr/descriptor/CascadableContainerD.java | 88 +++
.../apache/bval/jsr/descriptor/ComposedD.java | 123 +++
.../ComputeConstraintValidatorClass.java | 183 +++++
.../apache/bval/jsr/descriptor/ConstraintD.java | 276 +++++++
.../bval/jsr/descriptor/ConstructorD.java | 41 +
.../jsr/descriptor/ContainerElementTypeD.java | 119 +++
.../bval/jsr/descriptor/CrossParameterD.java | 18 +
.../bval/jsr/descriptor/DescriptorManager.java | 74 ++
.../apache/bval/jsr/descriptor/ElementD.java | 122 +++
.../apache/bval/jsr/descriptor/ExecutableD.java | 84 +++
.../org/apache/bval/jsr/descriptor/Finder.java | 103 +++
.../bval/jsr/descriptor/GroupConversion.java | 85 +++
.../bval/jsr/descriptor/MetadataReader.java | 291 +++++++
.../org/apache/bval/jsr/descriptor/MethodD.java | 49 ++
.../apache/bval/jsr/descriptor/ParameterD.java | 62 ++
.../apache/bval/jsr/descriptor/PropertyD.java | 106 +++
.../bval/jsr/descriptor/ReturnValueD.java | 36 +
.../java/org/apache/bval/jsr/groups/Group.java | 13 +-
.../groups/GroupConversionDescriptorImpl.java | 3 +-
.../java/org/apache/bval/jsr/groups/Groups.java | 67 +-
.../apache/bval/jsr/groups/GroupsComputer.java | 111 ++-
.../jsr/job/ConstraintValidatorContextImpl.java | 195 +++++
.../org/apache/bval/jsr/job/ValidateBean.java | 60 ++
.../apache/bval/jsr/job/ValidateParameters.java | 188 +++++
.../apache/bval/jsr/job/ValidateProperty.java | 522 +++++++++++++
.../bval/jsr/job/ValidateReturnValue.java | 126 ++++
.../org/apache/bval/jsr/job/ValidationJob.java | 380 ++++++++++
.../bval/jsr/job/ValidationJobFactory.java | 112 +++
.../bval/jsr/metadata/AnnotationBehavior.java | 35 +
.../AnnotationBehaviorMergeStrategy.java | 54 ++
...otationDeclaredValidatorMappingProvider.java | 42 ++
.../ClassLoadingValidatorMappingProvider.java | 48 ++
.../bval/jsr/metadata/CompositeBuilder.java | 227 ++++++
.../CompositeValidatorMappingProvider.java | 42 ++
.../bval/jsr/metadata/ContainerElementKey.java | 175 +++++
.../apache/bval/jsr/metadata/DualBuilder.java | 243 ++++++
.../metadata/DualValidationMappingProvider.java | 50 ++
.../apache/bval/jsr/metadata/EmptyBuilder.java | 183 +++++
.../jsr/metadata/HasAnnotationBehavior.java | 24 +
.../bval/jsr/metadata/HierarchyBuilder.java | 235 ++++++
.../bval/jsr/metadata/MetadataBuilder.java | 98 +++
.../bval/jsr/metadata/MetadataBuilders.java | 41 +
.../org/apache/bval/jsr/metadata/Metas.java | 324 ++++++++
.../bval/jsr/metadata/ReflectionBuilder.java | 272 +++++++
.../org/apache/bval/jsr/metadata/Signature.java | 75 ++
.../bval/jsr/metadata/ValidatorMapping.java | 121 +++
.../jsr/metadata/ValidatorMappingProvider.java | 51 ++
.../apache/bval/jsr/metadata/XmlBuilder.java | 694 +++++++++++++++++
.../metadata/XmlValidationMappingProvider.java | 64 ++
.../parameter/DefaultParameterNameProvider.java | 25 +-
.../resolver/CachingTraversableResolver.java | 26 +-
.../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 +
.../bval/jsr/valueextraction/FxExtractor.java | 96 +++
.../IterableElementExtractor.java | 30 +
.../valueextraction/ListElementExtractor.java | 34 +
.../bval/jsr/valueextraction/MapExtractor.java | 42 ++
.../jsr/valueextraction/OptionalExtractor.java | 65 ++
.../jsr/valueextraction/ValueExtractors.java | 181 +++++
.../apache/bval/jsr/xml/AnnotationProxy.java | 59 +-
.../bval/jsr/xml/AnnotationProxyBuilder.java | 104 ++-
.../org/apache/bval/jsr/xml/SchemaManager.java | 286 +++++++
.../bval/jsr/xml/ValidationMappingParser.java | 749 ++-----------------
.../apache/bval/jsr/xml/ValidationParser.java | 330 ++++----
.../java/org/apache/bval/jsr/xml/XmlUtils.java | 67 ++
.../bval/jsr/DefaultConstraints.properties | 81 +-
.../DefaultExtractors.properties | 25 +
bval-jsr/src/main/xjb/binding-customization.xjb | 4 +-
.../main/xsd/validation-configuration-2.0.xsd | 75 ++
.../src/main/xsd/validation-mapping-2.0.xsd | 297 ++++++++
.../org/apache/bval/jsr/BeanDescriptorTest.java | 3 +
.../bval/jsr/CustomValidatorFactoryTest.java | 6 +
.../java/org/apache/bval/jsr/Jsr303Test.java | 24 +-
.../org/apache/bval/jsr/ValidationTest.java | 2 +
.../org/apache/bval/jsr/example/Engine.java | 8 +-
.../jsr/extensions/MethodValidatorImplTest.java | 4 +-
.../jsr/groups/GroupSequenceIsolationTest.java | 10 +-
.../bval/jsr/groups/GroupsComputerTest.java | 88 +--
.../test/java/org/apache/bval/jsr/xml/Demo.java | 40 +
.../bval/jsr/xml/ValidationParserTest.java | 18 +-
.../src/test/resources/sample-validation11.xml | 30 +
.../src/test/resources/sample-validation2.xml | 30 +
bval-tck11/pom.xml | 8 +-
bval-xstream/pom.xml | 2 +-
pom.xml | 39 +-
213 files changed, 12302 insertions(+), 2281 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bundle/pom.xml
----------------------------------------------------------------------
diff --git a/bundle/pom.xml b/bundle/pom.xml
index 80cd95d..2f57116 100644
--- a/bundle/pom.xml
+++ b/bundle/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.apache.bval</groupId>
<artifactId>bval-parent</artifactId>
- <version>1.1.3-SNAPSHOT</version>
+ <version>2.0.0-SNAPSHOT</version>
</parent>
<!-- use fully qualified naming for OSGi bundles -->
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-core/pom.xml
----------------------------------------------------------------------
diff --git a/bval-core/pom.xml b/bval-core/pom.xml
index 48026d4..b7a7f8b 100644
--- a/bval-core/pom.xml
+++ b/bval-core/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.apache.bval</groupId>
<artifactId>bval-parent</artifactId>
- <version>1.1.3-SNAPSHOT</version>
+ <version>2.0.0-SNAPSHOT</version>
</parent>
<artifactId>bval-core</artifactId>
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-core/src/main/java/org/apache/bval/routines/EMailValidationUtils.java
----------------------------------------------------------------------
diff --git a/bval-core/src/main/java/org/apache/bval/routines/EMailValidationUtils.java b/bval-core/src/main/java/org/apache/bval/routines/EMailValidationUtils.java
index 1158c7f..0835bae 100644
--- a/bval-core/src/main/java/org/apache/bval/routines/EMailValidationUtils.java
+++ b/bval-core/src/main/java/org/apache/bval/routines/EMailValidationUtils.java
@@ -29,12 +29,11 @@ public class EMailValidationUtils {
private static String ATOM = "[^\\x00-\\x1F\\(\\)\\<\\>\\@\\,\\;\\:\\\\\\\"\\.\\[\\]\\s]";
private static String DOMAIN = "(" + ATOM + "+(\\." + ATOM + "+)*";
private static String IP_DOMAIN = "\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\]";
- public static final java.util.regex.Pattern DEFAULT_EMAIL_PATTERN;
+ public static final Pattern DEFAULT_EMAIL_PATTERN;
static {
- DEFAULT_EMAIL_PATTERN =
- java.util.regex.Pattern.compile("^" + ATOM + "+(\\." + ATOM + "+)*@" + DOMAIN + "|" + IP_DOMAIN + ")$",
- java.util.regex.Pattern.CASE_INSENSITIVE);
+ DEFAULT_EMAIL_PATTERN = Pattern.compile("^" + ATOM + "+(\\." + ATOM + "+)*@" + DOMAIN + "|" + IP_DOMAIN + ")$",
+ Pattern.CASE_INSENSITIVE);
}
/**
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/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/3f287a7a/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/3f287a7a/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/3f287a7a/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/3f287a7a/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/3f287a7a/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/3f287a7a/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/3f287a7a/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/3f287a7a/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/3f287a7a/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/3f287a7a/bval-extras/pom.xml
----------------------------------------------------------------------
diff --git a/bval-extras/pom.xml b/bval-extras/pom.xml
index 7a3edff..3dc7982 100644
--- a/bval-extras/pom.xml
+++ b/bval-extras/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.apache.bval</groupId>
<artifactId>bval-parent</artifactId>
- <version>1.1.3-SNAPSHOT</version>
+ <version>2.0.0-SNAPSHOT</version>
</parent>
<artifactId>bval-extras</artifactId>
@@ -69,7 +69,7 @@
<dependencies>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
- <artifactId>geronimo-validation_1.1_spec</artifactId>
+ <artifactId>geronimo-validation_2.0_spec</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/ABANumber.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/ABANumber.java b/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/ABANumber.java
index 921ffbc..821b6aa 100644
--- a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/ABANumber.java
+++ b/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/ABANumber.java
@@ -25,7 +25,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -40,7 +42,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
*/
@Documented
@Constraint(validatedBy = ABANumberValidator.class)
-@Target({ FIELD, ANNOTATION_TYPE, PARAMETER })
+@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface ABANumber {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/CUSIP.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/CUSIP.java b/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/CUSIP.java
index 85e84fd..139ab50 100644
--- a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/CUSIP.java
+++ b/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/CUSIP.java
@@ -25,7 +25,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -40,7 +42,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
*/
@Documented
@Constraint(validatedBy = CUSIPValidator.class)
-@Target({ FIELD, ANNOTATION_TYPE, PARAMETER })
+@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface CUSIP {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/EAN13.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/EAN13.java b/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/EAN13.java
index 4f835f6..667c786 100644
--- a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/EAN13.java
+++ b/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/EAN13.java
@@ -25,7 +25,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -40,7 +42,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
*/
@Documented
@Constraint(validatedBy = EAN13Validator.class)
-@Target({ FIELD, ANNOTATION_TYPE, PARAMETER })
+@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface EAN13 {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/IBAN.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/IBAN.java b/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/IBAN.java
index f0685c0..c48173f 100644
--- a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/IBAN.java
+++ b/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/IBAN.java
@@ -25,7 +25,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -40,7 +42,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
*/
@Documented
@Constraint(validatedBy = IBANValidator.class)
-@Target({ FIELD, ANNOTATION_TYPE, PARAMETER })
+@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface IBAN {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/IBANValidator.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/IBANValidator.java b/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/IBANValidator.java
index 38eace6..1f392c7 100644
--- a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/IBANValidator.java
+++ b/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/IBANValidator.java
@@ -26,7 +26,7 @@ import static java.lang.Character.getNumericValue;
/**
* <b>IBAN</b> (International Bank Account Number) Check Digit calculation/validation.
* <p>
- * This rountine is based on the ISO 7064 Mod 97,10 check digit caluclation routine.
+ * This routine is based on the ISO 7064 Mod 97,10 check digit caluclation routine.
* <p>
* The two check digit characters in a IBAN number are the third and fourth characters
* in the code. For <i>check digit</i> calculation/validation the first four characters are moved
@@ -40,7 +40,7 @@ import static java.lang.Character.getNumericValue;
* <a href="http://en.wikipedia.org/wiki/International_Bank_Account_Number">Wikipedia -
* IBAN number</a>.
*/
-public final class IBANValidator implements ConstraintValidator<IBAN, String> {
+public final class IBANValidator implements ConstraintValidator<IBAN, CharSequence> {
private static final long MAX = 999999999;
@@ -50,12 +50,12 @@ public final class IBANValidator implements ConstraintValidator<IBAN, String> {
* {@inheritDoc}
*/
@Override
- public boolean isValid(String code, ConstraintValidatorContext context) {
+ public boolean isValid(CharSequence code, ConstraintValidatorContext context) {
if (code.length() < 5) {
return false;
}
- String reformattedCode = code.substring(4) + code.substring(0, 4);
+ String reformattedCode = code.subSequence(4, code.length()).toString() + code.subSequence(0, 4).toString();
long total = 0;
for (int i = 0; i < reformattedCode.length(); i++) {
int charValue = getNumericValue(reformattedCode.charAt(i));
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/ISBN10.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/ISBN10.java b/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/ISBN10.java
index a3a1bc3..9ce9b19 100644
--- a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/ISBN10.java
+++ b/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/ISBN10.java
@@ -25,7 +25,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -40,7 +42,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
*/
@Documented
@Constraint(validatedBy = ISBN10Validator.class)
-@Target({ FIELD, ANNOTATION_TYPE, PARAMETER })
+@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface ISBN10 {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/Luhn.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/Luhn.java b/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/Luhn.java
index 3bc186e..4e7ede5 100644
--- a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/Luhn.java
+++ b/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/Luhn.java
@@ -25,7 +25,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -40,7 +42,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
*/
@Documented
@Constraint(validatedBy = LuhnValidator.class)
-@Target({ FIELD, ANNOTATION_TYPE, PARAMETER })
+@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface Luhn {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/ModulusValidator.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/ModulusValidator.java b/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/ModulusValidator.java
index f25bea4..57d463d 100644
--- a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/ModulusValidator.java
+++ b/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/ModulusValidator.java
@@ -38,7 +38,7 @@ import static java.lang.Character.isDigit;
*
* @param <A>
*/
-abstract class ModulusValidator<A extends Annotation> implements ConstraintValidator<A, String> {
+abstract class ModulusValidator<A extends Annotation> implements ConstraintValidator<A, CharSequence> {
private final int modulus;
@@ -58,7 +58,7 @@ abstract class ModulusValidator<A extends Annotation> implements ConstraintValid
* {@inheritDoc}
*/
@Override
- public boolean isValid(String code, ConstraintValidatorContext context) {
+ public boolean isValid(CharSequence code, ConstraintValidatorContext context) {
if (code.length() == 0) {
return false;
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/Sedol.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/Sedol.java b/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/Sedol.java
index e69947c..67a2c01 100644
--- a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/Sedol.java
+++ b/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/Sedol.java
@@ -25,7 +25,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -40,7 +42,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
*/
@Documented
@Constraint(validatedBy = SedolValidator.class)
-@Target({ FIELD, ANNOTATION_TYPE, PARAMETER })
+@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface Sedol {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/Verhoeff.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/Verhoeff.java b/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/Verhoeff.java
index e051a39..d3afc67 100644
--- a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/Verhoeff.java
+++ b/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/Verhoeff.java
@@ -25,7 +25,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -40,7 +42,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
*/
@Documented
@Constraint(validatedBy = VerhoeffValidator.class)
-@Target({ FIELD, ANNOTATION_TYPE, PARAMETER })
+@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface Verhoeff {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/VerhoeffValidator.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/VerhoeffValidator.java b/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/VerhoeffValidator.java
index 5a7d76b..b6c6249 100644
--- a/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/VerhoeffValidator.java
+++ b/bval-extras/src/main/java/org/apache/bval/extras/constraints/checkdigit/VerhoeffValidator.java
@@ -33,7 +33,7 @@ import static java.lang.Character.getNumericValue;
* See <a href="http://en.wikipedia.org/wiki/Verhoeff_algorithm">Wikipedia
* - Verhoeff algorithm</a> for more details.
*/
-public final class VerhoeffValidator implements ConstraintValidator<Verhoeff, String> {
+public final class VerhoeffValidator implements ConstraintValidator<Verhoeff, CharSequence> {
//@formatter:off
/** D - multiplication table */
@@ -65,7 +65,7 @@ public final class VerhoeffValidator implements ConstraintValidator<Verhoeff, St
* {@inheritDoc}
*/
@Override
- public boolean isValid(String code, ConstraintValidatorContext context) {
+ public boolean isValid(CharSequence code, ConstraintValidatorContext context) {
if (code.length() == 0) {
return false;
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/main/java/org/apache/bval/extras/constraints/creditcard/AmericanExpress.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/main/java/org/apache/bval/extras/constraints/creditcard/AmericanExpress.java b/bval-extras/src/main/java/org/apache/bval/extras/constraints/creditcard/AmericanExpress.java
index 3d08d19..051d210 100644
--- a/bval-extras/src/main/java/org/apache/bval/extras/constraints/creditcard/AmericanExpress.java
+++ b/bval-extras/src/main/java/org/apache/bval/extras/constraints/creditcard/AmericanExpress.java
@@ -28,7 +28,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -45,7 +47,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Luhn
@Pattern(regexp = "^(3[47]\\d{13})$")
@Constraint(validatedBy = {})
-@Target({ FIELD, ANNOTATION_TYPE, PARAMETER })
+@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface AmericanExpress {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/main/java/org/apache/bval/extras/constraints/creditcard/Diners.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/main/java/org/apache/bval/extras/constraints/creditcard/Diners.java b/bval-extras/src/main/java/org/apache/bval/extras/constraints/creditcard/Diners.java
index de6fd35..efb0772 100644
--- a/bval-extras/src/main/java/org/apache/bval/extras/constraints/creditcard/Diners.java
+++ b/bval-extras/src/main/java/org/apache/bval/extras/constraints/creditcard/Diners.java
@@ -28,7 +28,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -45,7 +47,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Luhn
@Pattern(regexp = "^(30[0-5]\\d{11}|3095\\d{10}|36\\d{12}|3[8-9]\\d{12})$")
@Constraint(validatedBy = {})
-@Target({ FIELD, ANNOTATION_TYPE, PARAMETER })
+@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface Diners {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/main/java/org/apache/bval/extras/constraints/creditcard/Discover.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/main/java/org/apache/bval/extras/constraints/creditcard/Discover.java b/bval-extras/src/main/java/org/apache/bval/extras/constraints/creditcard/Discover.java
index c445837..4e5ddd5 100644
--- a/bval-extras/src/main/java/org/apache/bval/extras/constraints/creditcard/Discover.java
+++ b/bval-extras/src/main/java/org/apache/bval/extras/constraints/creditcard/Discover.java
@@ -28,7 +28,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -45,7 +47,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Luhn
@Pattern(regexp = "^((6011\\d{12})|(64[4-9]\\d{13})|(65\\d{14}))$")
@Constraint(validatedBy = {})
-@Target({ FIELD, ANNOTATION_TYPE, PARAMETER })
+@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface Discover {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/main/java/org/apache/bval/extras/constraints/creditcard/Mastercard.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/main/java/org/apache/bval/extras/constraints/creditcard/Mastercard.java b/bval-extras/src/main/java/org/apache/bval/extras/constraints/creditcard/Mastercard.java
index f30482e..1a9b6a5 100644
--- a/bval-extras/src/main/java/org/apache/bval/extras/constraints/creditcard/Mastercard.java
+++ b/bval-extras/src/main/java/org/apache/bval/extras/constraints/creditcard/Mastercard.java
@@ -28,7 +28,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -45,7 +47,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Luhn
@Pattern(regexp = "^(5[1-5]\\d{14})$")
@Constraint(validatedBy = {})
-@Target({ FIELD, ANNOTATION_TYPE, PARAMETER })
+@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface Mastercard {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/main/java/org/apache/bval/extras/constraints/file/DirectoryValidator.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/main/java/org/apache/bval/extras/constraints/file/DirectoryValidator.java b/bval-extras/src/main/java/org/apache/bval/extras/constraints/file/DirectoryValidator.java
index a95ebde..6bca3b7 100644
--- a/bval-extras/src/main/java/org/apache/bval/extras/constraints/file/DirectoryValidator.java
+++ b/bval-extras/src/main/java/org/apache/bval/extras/constraints/file/DirectoryValidator.java
@@ -32,7 +32,7 @@ public class DirectoryValidator implements ConstraintValidator<Directory, File>
*/
@Override
public boolean isValid(File value, ConstraintValidatorContext context) {
- return value.exists() && value.isDirectory();
+ return value.isDirectory();
}
/**
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/main/java/org/apache/bval/extras/constraints/file/SymlinkValidator.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/main/java/org/apache/bval/extras/constraints/file/SymlinkValidator.java b/bval-extras/src/main/java/org/apache/bval/extras/constraints/file/SymlinkValidator.java
index 6ed85fd..ef85896 100644
--- a/bval-extras/src/main/java/org/apache/bval/extras/constraints/file/SymlinkValidator.java
+++ b/bval-extras/src/main/java/org/apache/bval/extras/constraints/file/SymlinkValidator.java
@@ -49,7 +49,7 @@ public class SymlinkValidator implements ConstraintValidator<Symlink, File> {
}
try {
- File fileInCanonicalDir = null;
+ File fileInCanonicalDir;
if (value.getParent() == null) {
fileInCanonicalDir = value;
} else {
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/main/java/org/apache/bval/extras/constraints/net/DomainValidator.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/main/java/org/apache/bval/extras/constraints/net/DomainValidator.java b/bval-extras/src/main/java/org/apache/bval/extras/constraints/net/DomainValidator.java
index b989531..c7668d5 100644
--- a/bval-extras/src/main/java/org/apache/bval/extras/constraints/net/DomainValidator.java
+++ b/bval-extras/src/main/java/org/apache/bval/extras/constraints/net/DomainValidator.java
@@ -20,11 +20,12 @@ package org.apache.bval.extras.constraints.net;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
-import java.util.List;
+import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import static java.util.Arrays.asList;
+import java.util.Arrays;
+import java.util.HashSet;
/**
* <p><b>Domain name</b> validation routines.</p>
@@ -63,7 +64,7 @@ import static java.util.Arrays.asList;
* {@link java.net.InetAddress} for that functionality.)
* </p>
*/
-public class DomainValidator implements ConstraintValidator<Domain, String> {
+public class DomainValidator implements ConstraintValidator<Domain, CharSequence> {
private boolean allowLocal;
@@ -77,15 +78,13 @@ public class DomainValidator implements ConstraintValidator<Domain, String> {
* {@inheritDoc}
*/
@Override
- public boolean isValid(String domain, ConstraintValidatorContext context) {
+ public boolean isValid(CharSequence domain, ConstraintValidatorContext context) {
Matcher matcher = DOMAIN_NAME_REGEX.matcher(domain);
if (matcher.matches()) {
domain = matcher.group(1);
- return isValidTld(domain);
- } else if (allowLocal && DOMAIN_LABEL.matcher(domain).matches()) {
- return true;
+ return isValidTld(domain.toString());
}
- return false;
+ return allowLocal && DOMAIN_LABEL.matcher(domain).matches();
}
/**
@@ -154,7 +153,7 @@ public class DomainValidator implements ConstraintValidator<Domain, String> {
}
private static String chompLeadingDot(String str) {
- if (str.startsWith(".")) {
+ if (str.charAt(0) == '.') {
return str.substring(1);
}
return str;
@@ -165,11 +164,11 @@ public class DomainValidator implements ConstraintValidator<Domain, String> {
// ----- Authoritative and comprehensive list at:
// ----- http://data.iana.org/TLD/tlds-alpha-by-domain.txt
- private static final List<String> INFRASTRUCTURE_TLDS = asList("arpa", // internet infrastructure
+ private static final Set<String> INFRASTRUCTURE_TLDS = new HashSet<>(Arrays.asList("arpa", // internet infrastructure
"root" // diagnostic marker for non-truncated root zone
- );
+ ));
- private static final List<String> GENERIC_TLDS = asList("aero", // air transport industry
+ private static final Set<String> GENERIC_TLDS = new HashSet<>(Arrays.asList("aero", // air transport industry
"asia", // Pan-Asia/Asia Pacific
"biz", // businesses
"cat", // Catalan linguistic/cultural community
@@ -189,9 +188,9 @@ public class DomainValidator implements ConstraintValidator<Domain, String> {
"edu", // accredited postsecondary US education entities
"mil", // United States Military
"int" // organizations established by international treaty
- );
+ ));
- private static final List<String> COUNTRY_CODE_TLDS = asList("ac", // Ascension Island
+ private static final Set<String> COUNTRY_CODE_TLDS = new HashSet<>(Arrays.asList("ac", // Ascension Island
"ad", // Andorra
"ae", // United Arab Emirates
"af", // Afghanistan
@@ -440,11 +439,11 @@ public class DomainValidator implements ConstraintValidator<Domain, String> {
"za", // South Africa
"zm", // Zambia
"zw" // Zimbabwe
- );
+ ));
- private static final List<String> LOCAL_TLDS = asList("localhost", // RFC2606 defined
+ private static final Set<String> LOCAL_TLDS = new HashSet<>(Arrays.asList("localhost", // RFC2606 defined
"localdomain" // Also widely used as localhost.localdomain
- );
+ ));
/**
* {@inheritDoc}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/main/java/org/apache/bval/extras/constraints/net/InetAddressValidator.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/main/java/org/apache/bval/extras/constraints/net/InetAddressValidator.java b/bval-extras/src/main/java/org/apache/bval/extras/constraints/net/InetAddressValidator.java
index 461562c..d482e01 100644
--- a/bval-extras/src/main/java/org/apache/bval/extras/constraints/net/InetAddressValidator.java
+++ b/bval-extras/src/main/java/org/apache/bval/extras/constraints/net/InetAddressValidator.java
@@ -27,7 +27,7 @@ import java.util.regex.Pattern;
*
* <p>This class provides methods to validate a candidate IP address.
*/
-public class InetAddressValidator implements ConstraintValidator<InetAddress, String> {
+public class InetAddressValidator implements ConstraintValidator<InetAddress, CharSequence> {
private static final Pattern IPV4_PATTERN =
Pattern.compile("^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
@@ -37,7 +37,7 @@ public class InetAddressValidator implements ConstraintValidator<InetAddress, St
* {@inheritDoc}
*/
@Override
- public boolean isValid(String value, ConstraintValidatorContext context) {
+ public boolean isValid(CharSequence value, ConstraintValidatorContext context) {
if (!IPV4_PATTERN.matcher(value).matches()) {
return false;
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/ABANumberValidatorTest.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/ABANumberValidatorTest.java b/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/ABANumberValidatorTest.java
index d186dcb..8cd2399 100644
--- a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/ABANumberValidatorTest.java
+++ b/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/ABANumberValidatorTest.java
@@ -25,7 +25,7 @@ import java.lang.annotation.Annotation;
public class ABANumberValidatorTest extends AbstractCheckDigitTest {
@Override
- protected ConstraintValidator<? extends Annotation, String> getConstraint() {
+ protected ConstraintValidator<? extends Annotation, ? super String> getConstraint() {
return new ABANumberValidator();
}
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/AbstractCheckDigitTest.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/AbstractCheckDigitTest.java b/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/AbstractCheckDigitTest.java
index c25278f..190bd5b 100644
--- a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/AbstractCheckDigitTest.java
+++ b/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/AbstractCheckDigitTest.java
@@ -37,7 +37,7 @@ public abstract class AbstractCheckDigitTest {
private int checkDigitLth;
/** Check digit routine being tested */
- private ConstraintValidator<? extends Annotation, String> routine;
+ private ConstraintValidator<? extends Annotation, ? super String> routine;
/** Array of valid code values */
private String[] valid;
@@ -55,7 +55,7 @@ public abstract class AbstractCheckDigitTest {
return 1;
}
- protected abstract ConstraintValidator<? extends Annotation, String> getConstraint();
+ protected abstract ConstraintValidator<? extends Annotation, ? super String> getConstraint();
protected abstract String[] getValid();
http://git-wip-us.apache.org/repos/asf/bval/blob/3f287a7a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/CUSIPValidatorTest.java
----------------------------------------------------------------------
diff --git a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/CUSIPValidatorTest.java b/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/CUSIPValidatorTest.java
index 5bc57c3..fe13c4b 100644
--- a/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/CUSIPValidatorTest.java
+++ b/bval-extras/src/test/java/org/apache/bval/extras/constraints/checkdigit/CUSIPValidatorTest.java
@@ -25,7 +25,7 @@ import java.lang.annotation.Annotation;
public class CUSIPValidatorTest extends AbstractCheckDigitTest {
@Override
- protected ConstraintValidator<? extends Annotation, String> getConstraint() {
+ protected ConstraintValidator<? extends Annotation, ? super String> getConstraint() {
return new CUSIPValidator();
}