.
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package cz.jirutka.validator.collection.internal;
25 |
26 | import org.hibernate.validator.internal.metadata.core.ConstraintHelper;
27 | import org.hibernate.validator.internal.metadata.core.ConstraintOrigin;
28 | import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl;
29 |
30 | import javax.validation.metadata.ConstraintDescriptor;
31 | import java.lang.annotation.Annotation;
32 | import java.lang.annotation.ElementType;
33 | import java.lang.reflect.Constructor;
34 | import java.lang.reflect.Member;
35 |
36 | /**
37 | * Factory that builds instances of {@link ConstraintDescriptorImpl}.
38 | *
39 | * This is a workaround to support multiple versions of Hibernate Validator;
40 | * 4.3.0 and greater. The problem is that {@code ConstraintDescriptorImpl} is
41 | * internal class of the Hibernate Validator and its constructor's signature
42 | * has been several times changed between major versions. The class implements
43 | * public interface {@link ConstraintDescriptor}, but its implementation is
44 | * pretty complex (547 LOC), it seems that it can't be reimplemented simpler
45 | * and I hate code copy&pasting...
46 | */
47 | public abstract class ConstraintDescriptorFactory {
48 |
49 | private static final ConstraintHelper CONSTRAINT_HELPER = new ConstraintHelper();
50 |
51 | protected final Constructor constructor;
52 |
53 |
54 | private ConstraintDescriptorFactory() {
55 | try {
56 | this.constructor = ConstraintDescriptorImpl.class.getConstructor(getConstructorArguments());
57 | } catch (NoSuchMethodException ex) {
58 | throw new IllegalStateException(ex);
59 | }
60 | }
61 |
62 | /**
63 | * Creates a new instance of factory for the version of Hibernate Validator
64 | * detected on classpath.
65 | */
66 | public static ConstraintDescriptorFactory newInstance() {
67 |
68 | int version = HibernateValidatorInfo.getVersion();
69 |
70 | if (version >= 5_1_0) {
71 | return new ConstraintDescriptorFactory() {
72 | Class[] getConstructorArguments() {
73 | return new Class[]{ ConstraintHelper.class, Member.class, Annotation.class, ElementType.class };
74 | }
75 | ConstraintDescriptorImpl newInstance(Annotation annotation) throws ReflectiveOperationException {
76 | return constructor.newInstance(CONSTRAINT_HELPER, null, annotation, ElementType.LOCAL_VARIABLE);
77 | }
78 | };
79 | } else if (version >= 5_0_0) {
80 | return new ConstraintDescriptorFactory() {
81 | Class[] getConstructorArguments() {
82 | return new Class[]{ Annotation.class, ConstraintHelper.class, Class.class,
83 | ElementType.class, ConstraintOrigin.class, Member.class };
84 | }
85 | ConstraintDescriptorImpl newInstance(Annotation annotation) throws ReflectiveOperationException {
86 | return constructor.newInstance(annotation, CONSTRAINT_HELPER, null, ElementType.LOCAL_VARIABLE,
87 | ConstraintOrigin.DEFINED_LOCALLY, null);
88 | }
89 | };
90 | } else if (version >= 4_3_0) {
91 | return new ConstraintDescriptorFactory() {
92 | Class[] getConstructorArguments() {
93 | return new Class[]{ Annotation.class, ConstraintHelper.class, Class.class,
94 | ElementType.class, ConstraintOrigin.class };
95 | }
96 | ConstraintDescriptorImpl newInstance(Annotation annotation) throws ReflectiveOperationException {
97 | return constructor.newInstance(annotation, CONSTRAINT_HELPER, null, ElementType.LOCAL_VARIABLE,
98 | ConstraintOrigin.DEFINED_LOCALLY);
99 | }
100 | };
101 | } else {
102 | throw new UnsupportedVersionException("Hibernate Validator older then 4.3.0 is not supported");
103 | }
104 | }
105 |
106 | /**
107 | * @param annotation The constraint annotation.
108 | * @return An instance of {@link ConstraintDescriptorImpl} for the given
109 | * constraint.
110 | */
111 | @SuppressWarnings("unchecked")
112 | public ConstraintDescriptor buildConstraintDescriptor(T annotation) {
113 | try {
114 | return newInstance(annotation);
115 |
116 | } catch (ReflectiveOperationException ex) {
117 | throw new IllegalStateException(ex);
118 | }
119 | }
120 |
121 | //////// Abstract methods ////////
122 |
123 | abstract ConstraintDescriptorImpl newInstance(Annotation annotation) throws ReflectiveOperationException;
124 |
125 | abstract Class[] getConstructorArguments();
126 |
127 |
128 |
129 | //////// Inner classes ////////
130 |
131 | public static class UnsupportedVersionException extends IllegalStateException {
132 |
133 | public UnsupportedVersionException(String message) {
134 | super(message);
135 | }
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/src/main/java/cz/jirutka/validator/collection/internal/ConstraintValidatorContextUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright 2013-2016 Jakub Jirutka .
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package cz.jirutka.validator.collection.internal;
25 |
26 | import javax.validation.ConstraintValidatorContext;
27 |
28 | public abstract class ConstraintValidatorContextUtils {
29 |
30 | private static final int HV_VERSION = HibernateValidatorInfo.getVersion();
31 |
32 | /**
33 | * Builds and adds a constraint violation inside an iterable value to the
34 | * given {@code ConstraintValidatorContext}. If running with Hibernate
35 | * Validator 5.x, then it also registers index of the violated value.
36 | *
37 | * @param context The Constraint validator context.
38 | * @param message The interpolated error message.
39 | * @param index Index of the invalid value inside a list (ignored on HV 4.x).
40 | */
41 | public static void addConstraintViolationInIterable(ConstraintValidatorContext context, String message, int index) {
42 | if (HV_VERSION >= 5_0_0) {
43 | context.buildConstraintViolationWithTemplate(message)
44 | .addBeanNode()
45 | .inIterable()
46 | .atIndex(index)
47 | .addConstraintViolation();
48 | } else {
49 | context.buildConstraintViolationWithTemplate(message)
50 | .addConstraintViolation();
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/cz/jirutka/validator/collection/internal/HibernateValidatorInfo.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright 2013-2014 Jakub Jirutka .
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package cz.jirutka.validator.collection.internal;
25 |
26 | import org.hibernate.validator.HibernateValidator;
27 | import org.slf4j.Logger;
28 | import org.slf4j.LoggerFactory;
29 |
30 | import static java.lang.Integer.parseInt;
31 | import static org.apache.commons.lang3.StringUtils.isNotEmpty;
32 |
33 | public abstract class HibernateValidatorInfo {
34 |
35 | private static final Logger LOG = LoggerFactory.getLogger(HibernateValidatorInfo.class);
36 |
37 | /**
38 | * Returns version of the Hibernate Validator determined from the package
39 | * info on classpath.
40 | *
41 | * Version number is parsed as: 5.1.1.Final -> 511, 5.2.0-SNAPSHOT -> 520.
42 | *
43 | * @return A parsed version number, or {@link Integer#MAX_VALUE} if could not be determined.
44 | */
45 | public static int getVersion() {
46 |
47 | Package pkg = HibernateValidator.class.getPackage();
48 |
49 | if (pkg != null) {
50 | String version = pkg.getImplementationVersion();
51 | String title = pkg.getImplementationTitle();
52 |
53 | if (isNotEmpty(version) && "hibernate-validator".equals(title)) {
54 | LOG.info("Found Hibernate Validator {}", version);
55 | return parseVersion(version);
56 | }
57 | }
58 | LOG.warn("Could not determine Hibernate Validator version");
59 | return Integer.MAX_VALUE;
60 | }
61 |
62 | static int parseVersion(String version) {
63 | String[] tokens = version.split("[.-]");
64 |
65 | return parseInt(tokens[0]) * 100
66 | + parseInt(tokens[1]) * 10
67 | + parseInt(tokens[2]);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/java/cz/jirutka/validator/collection/internal/MessageInterpolatorContext.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright 2013-2014 Jakub Jirutka .
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package cz.jirutka.validator.collection.internal;
25 |
26 | import org.apache.commons.lang3.builder.EqualsBuilder;
27 | import org.apache.commons.lang3.builder.HashCodeBuilder;
28 |
29 | import javax.validation.MessageInterpolator;
30 | import javax.validation.metadata.ConstraintDescriptor;
31 |
32 | public class MessageInterpolatorContext implements MessageInterpolator.Context {
33 |
34 | private final ConstraintDescriptor> constraintDescriptor;
35 |
36 | private final Object validatedValue;
37 |
38 |
39 | public MessageInterpolatorContext(ConstraintDescriptor> constraintDescriptor, Object validatedValue) {
40 | this.constraintDescriptor = constraintDescriptor;
41 | this.validatedValue = validatedValue;
42 | }
43 |
44 |
45 | public ConstraintDescriptor> getConstraintDescriptor() {
46 | return constraintDescriptor;
47 | }
48 |
49 | public Object getValidatedValue() {
50 | return validatedValue;
51 | }
52 |
53 | public T unwrap(Class type) {
54 | throw new UnsupportedOperationException("Not implemented");
55 | }
56 |
57 | @Override
58 | public boolean equals(Object obj) {
59 | // this is normally not called, so use just brief reflection method
60 | return EqualsBuilder.reflectionEquals(this, obj);
61 | }
62 |
63 | @Override
64 | public int hashCode() {
65 | // this is normally not called, so use just brief reflection method
66 | return HashCodeBuilder.reflectionHashCode(this);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/test/groovy/cz/jirutka/validator/collection/CommonEachValidatorIT.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright 2013-2015 Jakub Jirutka .
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package cz.jirutka.validator.collection
25 |
26 | import cz.jirutka.validator.collection.internal.HibernateValidatorInfo
27 | import spock.lang.Ignore
28 | import spock.lang.Issue
29 | import spock.lang.Specification
30 | import spock.lang.Unroll
31 |
32 | import static cz.jirutka.validator.collection.TestUtils.evalClassWithConstraint
33 | import static cz.jirutka.validator.collection.TestUtils.validate
34 |
35 | @Unroll
36 | class CommonEachValidatorIT extends Specification {
37 |
38 | static HV_VERSION = HibernateValidatorInfo.getVersion()
39 |
40 | def constraint = null
41 |
42 |
43 | def 'validate @EachX for common constraint [ #desc ]'() {
44 | given:
45 | constraint = '@EachSize(min=2, max=6)'
46 | expect:
47 | assertViolations values, isValid, invalidIndex, 'size must be between 2 and 6'
48 | where:
49 | values | desc || isValid | invalidIndex
50 | ['f', 'ab'] | 'first value invalid' || false | 0
51 | ['ab', ''] | 'last value invalid' || false | 1
52 | ['foo'] | 'valid value' || true | null
53 | ['ab', 'cd'] | 'valid values' || true | null
54 | [null, 'ab'] | 'valid values with null' || true | null
55 | [] | 'empty list' || true | null
56 | null | 'null' || true | null
57 | }
58 |
59 | def 'validate composite constraint with two @EachX [ #desc ]'() {
60 | given:
61 | constraint = '@EachComposite'
62 | expect:
63 | assertViolations values, isValid, invalidIndex, message
64 | where:
65 | values | desc || isValid | invalidIndex | message
66 | ['f'] | 'value invalid by first cons.' || false | 0 | 'size must be between 2 and 8'
67 | ['foo', '132'] | 'value invalid by second cons.' || false | 1 | 'must contain a-z only'
68 | ['ab', 'cd'] | 'valid values' || true | null | null
69 | }
70 |
71 | def 'validate @EachX for constraint that validates nulls [ #desc ]'() {
72 | given:
73 | constraint = '@EachNotNull'
74 | expect:
75 | assertViolations values, isValid, 1, 'may not be null'
76 | where:
77 | values | desc || isValid
78 | ['a', null] | 'a null value' || false
79 | ['a', 'b'] | 'not null values' || true
80 | }
81 |
82 | @Ignore('should be fixed!') @Issue('#8')
83 | def 'validate @EachX for pure composite constraint [ #desc ]'() {
84 | given:
85 | constraint = '@EachRange(min=16L, max=64L)'
86 | expect:
87 | assertViolations values, isValid, 0, 'must be between 16 and 64'
88 | where:
89 | values | desc || isValid
90 | [6] | 'invalid value' || false
91 | [42] | 'valid value' || true
92 | }
93 |
94 | @Ignore('should be fixed!') @Issue('#8')
95 | def 'validate @EachX for half-composite constraint [ #desc ]'() {
96 | given:
97 | constraint = '@EachNotBlank'
98 | expect:
99 | assertViolations values, isValid, invalidIndex, 'may not be empty'
100 | where:
101 | values | desc || isValid | invalidIndex
102 | [''] | 'value invalid by top validator' || false | 0
103 | ['foo', null] | 'value invalid by composite cons.' || false | 1
104 | ['allons-y!'] | 'valid value' || true | null
105 | }
106 |
107 | @Ignore('should be fixed!') @Issue('#8')
108 | def 'validate @EachX for constraint that uses @OverridesAttribute [ #desc value ]'() {
109 | given:
110 | constraint = '@EachURL(protocol="https", regexp=".*[^x]$")'
111 | expect:
112 | assertViolations values, isValid, 0, 'must be a valid URL'
113 | where:
114 | values | desc || isValid
115 | ['http://fit.cvut.cz'] | "invalid normal attribute's" || false
116 | ['https://fit.cvut.cx'] | "invalid overrided attribute's" || false
117 | ['https://fit.cvut.cz'] | 'valid' || true
118 | }
119 |
120 | def 'validate @EachX with custom message template'() {
121 | given:
122 | constraint = '@EachURL(protocol="https", message="must be a valid URL with {protocol}")'
123 | expect:
124 | assertViolations(['http://fit.cvut.cz'], false, 0, 'must be a valid URL with https')
125 | }
126 |
127 | def 'validate legacy @EachX constraint [ #desc ]'() {
128 | given:
129 | constraint = '@LegacyEachSize(@Size(min=2, max=6))'
130 | expect:
131 | assertViolations values, isValid, 0, 'size must be between 2 and 6'
132 | where:
133 | values | desc || isValid
134 | ['f', 'ab'] | 'invalid value' || false
135 | ['ab', 'cd'] | 'valid values' || true
136 | }
137 |
138 |
139 | //////// Helpers ////////
140 |
141 | void assertViolations(Object value, boolean shouldBeValid, Integer invalidIndex, String expectedMessage) {
142 | def entity = evalClassWithConstraint(constraint, value)
143 | def propertyPath = HV_VERSION >= 5_0_0 ? "valuesList[${invalidIndex}]" : 'valuesList'
144 | def violations = validate(entity)
145 |
146 | assert violations.isEmpty() == shouldBeValid
147 |
148 | if (!shouldBeValid) {
149 | assert violations.size() == 1
150 | assert violations[0].invalidValue == value
151 | assert violations[0].propertyPath.toString() == propertyPath
152 | assert violations[0].rootBean.is(entity)
153 | assert violations[0].rootBeanClass == entity.class
154 | assert violations[0].message == expectedMessage
155 | }
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/src/test/groovy/cz/jirutka/validator/collection/CommonEachValidatorTest.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright 2013-2014 Jakub Jirutka .
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package cz.jirutka.validator.collection
25 |
26 | import cz.jirutka.validator.collection.fixtures.LegacyEachSize
27 | import spock.lang.Specification
28 |
29 | import javax.validation.MessageInterpolator
30 | import javax.validation.MessageInterpolator.Context
31 | import javax.validation.ValidatorFactory
32 | import javax.validation.constraints.Pattern
33 | import javax.validation.constraints.Size
34 | import javax.validation.metadata.ConstraintDescriptor
35 |
36 | import static cz.jirutka.validator.collection.TestUtils.createAnnotation
37 |
38 | // TODO more tests
39 | class CommonEachValidatorTest extends Specification {
40 |
41 | def interpolator = Mock(MessageInterpolator)
42 | def factory = Stub(ValidatorFactory) {
43 | getMessageInterpolator() >> interpolator
44 | }
45 | def validator = new CommonEachValidator(validatorFactory: factory)
46 |
47 |
48 | def 'createMessage: should extract message template and interpolate it'() {
49 | given:
50 | def msgTemplate = 'must match "{regexp}"'
51 | def descriptor = Stub(ConstraintDescriptor) {
52 | getAnnotation() >> createAnnotation(Pattern, regexp: '[a-z]', message: msgTemplate)
53 | }
54 | def value = new Object()
55 | def expected = 'must match "[a-z]"'
56 | when:
57 | def actual = validator.createInterpolatedMessage(descriptor, value)
58 | then:
59 | 1 * interpolator.interpolate(msgTemplate, { Context cxt ->
60 | cxt.constraintDescriptor == descriptor && cxt.validatedValue == value
61 | }) >> expected
62 | and:
63 | actual == expected
64 | }
65 |
66 | def 'unwrapConstraints'() {
67 | given:
68 | def expected = [ createAnnotation(Size, min: 10), createAnnotation(Size) ] as Size[]
69 | def eachAnno = createAnnotation(LegacyEachSize, value: expected)
70 | expect:
71 | validator.unwrapConstraints(eachAnno) == expected
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/test/groovy/cz/jirutka/validator/collection/TestUtils.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright 2013-2015 Jakub Jirutka .
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package cz.jirutka.validator.collection
25 |
26 | import org.hibernate.validator.internal.util.annotationfactory.AnnotationDescriptor
27 | import org.hibernate.validator.internal.util.annotationfactory.AnnotationFactory
28 |
29 | import javax.validation.Validation
30 |
31 | class TestUtils {
32 |
33 | static evalClassWithConstraint(annotationLine, List values) {
34 | def value = values ? "[ ${values.collect{ toLiteral(it) }.join(',')} ]" : null
35 |
36 | def template = """
37 | import cz.jirutka.validator.collection.constraints.*
38 | import cz.jirutka.validator.collection.fixtures.*
39 | import javax.validation.constraints.*
40 |
41 | class TestMock {
42 | ${annotationLine.replace('"', "'")}
43 | public List valuesList = $value
44 | }
45 | """
46 | new GroovyClassLoader().parseClass(template).newInstance()
47 | }
48 |
49 | static evalClassWithConstraint(Class annotationType, Map attributes, List values) {
50 | evalClassWithConstraint(createAnnotationString(annotationType, attributes), values)
51 | }
52 |
53 | static toLiteral(value) {
54 | switch (value) {
55 | case null : return null
56 | case String : return "'${value.toString()}'"
57 | case Long : return "${value}L"
58 | case List : return '[' + value.collect { toLiteral(it) }.join(', ') + ']'
59 | case Map : return '[' + value.collect { k, v -> "${k}: ${ toLiteral(v) }" }.join(',') + ']'
60 | case Enum : return "${value.declaringClass.name}.${value.name()}"
61 | case Date : return "new Date(${toLiteral(value.time)})"
62 | default : return String.valueOf(value)
63 | }
64 | }
65 |
66 | static createAnnotation(Class annotationType, Map attributes) {
67 | createAnnotation(attributes, annotationType)
68 | }
69 |
70 | static createAnnotation(Map attributes=[:], Class annotationType) {
71 | def desc = AnnotationDescriptor.getInstance(annotationType, attributes)
72 | AnnotationFactory.create(desc)
73 | }
74 |
75 | static createAnnotationString(Class annotationType, Map attributes) {
76 | def attrsLine = attributes.collect { k, v -> "${k}=${toLiteral(v)}" }.join(', ')
77 | "@${annotationType.name}(${attrsLine})"
78 | }
79 |
80 | static validate(entity) {
81 | Validation.buildDefaultValidatorFactory().validator.validate(entity)
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/test/groovy/cz/jirutka/validator/collection/constraints/EachAnnotationIT.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright 2013-2015 Jakub Jirutka .
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package cz.jirutka.validator.collection.constraints
25 |
26 | import cz.jirutka.validator.collection.internal.HibernateValidatorInfo
27 | import org.apache.commons.lang3.ClassUtils
28 | import org.hibernate.validator.constraints.CreditCardNumber
29 | import org.hibernate.validator.constraints.NotEmpty
30 | import org.hibernate.validator.constraints.Range
31 | import spock.lang.Specification
32 | import spock.lang.Unroll
33 |
34 | import static cz.jirutka.validator.collection.TestUtils.evalClassWithConstraint
35 | import static cz.jirutka.validator.collection.TestUtils.validate
36 |
37 | @Unroll
38 | class EachAnnotationIT extends Specification {
39 |
40 | static final HV_VERSION = HibernateValidatorInfo.getVersion()
41 |
42 | // List of @Each* annotations for constraints defined in JSR 303/349.
43 | static final CONSTRAINTS_JSR = [
44 | EachAssertFalse, EachAssertTrue, EachDecimalMax, EachDecimalMin,
45 | EachDigits, EachFuture, EachMax, EachMin, EachNotNull, EachPast,
46 | EachPattern, EachSize
47 | ]
48 |
49 | // List of @Each* annotations for Hibernate constraints in HV 4.3.0.
50 | static final CONSTRAINTS_HV = [
51 | EachEmail, EachLength, EachNotBlank, EachNotEmpty, EachRange,
52 | EachScriptAssert, EachURL
53 | ]
54 |
55 | // List of @Each* annotations for Hibernate constraints in HV 5.1.0 and newer.
56 | static final CONSTRAINTS_5_1_0 = [
57 | EachCreditCardNumber, EachEAN, EachLuhnCheck, EachMod10Check,
58 | EachMod11Check, EachSafeHtml
59 | ]
60 |
61 | // List of @Each* annotations which are only a composition of other @Each* annotations.
62 | static final COMPOSITE_CONSTRAINTS = [
63 | EachCreditCardNumber, EachNotEmpty, EachRange
64 | ]
65 |
66 |
67 | def 'verify that @#name is annotated with @EachConstraint(validateAs = #expValidateAsName)'() {
68 | expect:
69 | constraint.isAnnotationPresent(EachConstraint)
70 | and:
71 | def validateAs = constraint.getAnnotation(EachConstraint).validateAs()
72 | constraint.simpleName == /Each${validateAs.simpleName}/
73 | where:
74 | constraint << (eachConstraints - COMPOSITE_CONSTRAINTS)
75 | name = constraint.simpleName
76 | expValidateAsName = name.replaceFirst('^Each', '') + '.class'
77 | }
78 |
79 | def 'verify that #constraint.simpleName defines same attributes as its validateAs constraint'() {
80 | setup:
81 | def validateAs = constraint.getAnnotation(EachConstraint).validateAs()
82 | expect:
83 | attributesTypesSet(constraint).containsAll attributesTypesSet(validateAs)
84 | where:
85 | constraint << (eachConstraints - COMPOSITE_CONSTRAINTS)
86 | }
87 |
88 | def 'verify that @#constraint.simpleName defines same attributes as #validateAs.simpleName'() {
89 | setup:
90 | // skip test for constraints that doesn't work in the current HV version
91 | if (!eachConstraints.contains(constraint)) return
92 | expect:
93 | attributesTypesSet(constraint).containsAll attributesTypesSet(validateAs)
94 | where:
95 | constraint | validateAs
96 | EachNotEmpty | NotEmpty
97 | EachRange | Range
98 | EachCreditCardNumber | CreditCardNumber
99 | }
100 |
101 | def 'validate @#constraintName on collection of #valuesType'() {
102 | setup:
103 | // skip test for constraints that doesn't work in the current HV version
104 | if (!eachConstraints.contains(constraint)) return
105 | and:
106 | def validEntity = evalClassWithConstraint(constraint, attributes, validValue)
107 | def invalidEntity = evalClassWithConstraint(constraint, attributes, invalidValue)
108 | expect:
109 | validate(validEntity).empty
110 | ! validate(invalidEntity).empty
111 | where:
112 | constraint | attributes | validValue | invalidValue
113 | EachAssertFalse | [:] | [false, false] | [false, true]
114 | EachAssertTrue | [:] | [true, true] | [true, false]
115 | EachCreditCardNumber | [:] | ['79927398713'] | ['79927398714']
116 | EachDecimalMax | [value: '3'] | [1, 2, 3] | [2, 3, 4]
117 | EachDecimalMax | [value: '3'] | ['1', '2', '3'] | ['2', '3', '4']
118 | EachDecimalMin | [value: '3'] | [3, 4, 5] | [2, 3, 4]
119 | EachDecimalMin | [value: '3'] | ['3', '4', '5'] | ['2', '3', '4']
120 | EachDigits | [integer: 2, fraction: 1] | [42.1, 13.2] | [42.1, 3.14]
121 | EachDigits | [integer: 2, fraction: 1] | ['42.1', '13.2'] | ['42.1', '3.14']
122 | EachEAN | [:] | ['1234567890128'] | ['1234567890128', '66']
123 | EachEmail | [:] | ['x@y.z', 'a@b.c'] | ['x@y.z', 'ab.c']
124 | EachFuture | [:] | [futureDate()] | [pastDate()]
125 | EachLength | [min: 1, max: 3] | ['a', 'foo'] | ['a', 'allons-y!']
126 | EachLuhnCheck | [:] | ['79927398713'] | ['79927398714']
127 | EachMax | [value: 3L] | [1, 2, 3] | [2, 3, 4]
128 | EachMax | [value: 3L] | ['1', '2', '3'] | ['2', '3', '4']
129 | EachMin | [value: 3L] | [3, 4, 5] | [1, 2, 3]
130 | EachMin | [value: 3L] | ['3', '4', '5'] | ['1', '2', '3']
131 | EachMod10Check | [:] | ['123'] | ['123', '124']
132 | EachMod11Check | [:] | ['124'] | ['124', '125']
133 | EachNotBlank | [:] | ['foo', 'bar'] | ['foo', '']
134 | EachNotEmpty | [:] | ['x', 'yz'] | ['x', '']
135 | EachNotEmpty | [:] | [[1], [2, 3]] | [[1], []]
136 | EachNotEmpty | [:] | [[a: 1], [b: 2]] | [[a: 1], [:]]
137 | EachNotNull | [:] | ['foo', 'bar'] | ['foo', null]
138 | EachPast | [:] | [pastDate()] | [futureDate()]
139 | EachPattern | [regexp: '[A-Z]+'] | ['FOO', 'BAR'] | ['FOO', '123']
140 | EachRange | [min: 3L, max: 6L] | [3, 4, 5] | [6, 7, 8]
141 | EachRange | [min: 3L, max: 6L] | ['3', '4', '5'] | ['6', '7', '8']
142 | EachSafeHtml | [:] | ['foo'] | ['WAT?']
143 | EachSize | [min: 1, max: 2] | ['a', 'xy'] | ['a', 'foo']
144 | EachSize | [min: 1, max: 2] | [[1], [2, 3]] | [[1], [2, 3, 4]]
145 | EachSize | [min: 1, max: 2] | [[a: 1], [b: 2]] | [[a: 1], [:]]
146 | EachURL | [protocol: 'https'] | ['https://nic.cz'] | ['http://nic.cz']
147 |
148 | constraintName = ClassUtils.getSimpleName(constraint) // using ClassUtils to avoid NoClassDefFoundError
149 | valuesType = validValue[0].getClass().simpleName + 's'
150 | }
151 |
152 |
153 | //////// Helpers ////////
154 |
155 | static getEachConstraints() {
156 | (CONSTRAINTS_JSR + CONSTRAINTS_HV + (HV_VERSION >= 5_1_0 ? CONSTRAINTS_5_1_0 : [])).toSet()
157 | }
158 |
159 | def attributesTypesSet(Class annotation) {
160 | annotation.declaredMethods.collect(new HashSet()) { m ->
161 | [m.name, m.returnType]
162 | }
163 | }
164 |
165 | def futureDate() {
166 | new Date().plus(1)
167 | }
168 |
169 | def pastDate() {
170 | new Date().minus(1)
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/src/test/groovy/cz/jirutka/validator/collection/internal/AnnotationUtilsTest.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright 2013-2014 Jakub Jirutka .
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package cz.jirutka.validator.collection.internal
25 |
26 | import cz.jirutka.validator.collection.TestUtils
27 | import spock.lang.Specification
28 | import spock.lang.Unroll
29 |
30 | import javax.validation.constraints.NotNull
31 | import javax.validation.constraints.Pattern
32 | import javax.validation.constraints.Size
33 |
34 | import static cz.jirutka.validator.collection.internal.AnnotationUtils.*
35 |
36 | class AnnotationUtilsTest extends Specification {
37 |
38 |
39 | //////// readAttribute() ////////
40 |
41 | def "readAttribute: return attribute's value"() {
42 | given:
43 | def attrs = value != null ? [(name): value] : [:]
44 | def annotation = TestUtils.createAnnotation(Size, attrs)
45 | expect:
46 | readAttribute(annotation, name, reqType) == expected
47 | where:
48 | name | reqType | value || expected
49 | 'min' | Integer | 1 || 1
50 | 'message' | String | null || '{javax.validation.constraints.Size.message}'
51 | 'groups' | Class[] | [String] as Class[] || [String]
52 | }
53 |
54 | @Unroll
55 | def "readAttribute: throw IllegalArgumentException when attribute #reason"() {
56 | given:
57 | def annotation = TestUtils.createAnnotation(NotNull)
58 | when:
59 | readAttribute(annotation, attrName, attrType)
60 | then:
61 | thrown IllegalArgumentException
62 | where:
63 | attrName | attrType | reason
64 | 'foo' | String | "doesn't exist"
65 | 'message' | Integer | "isn't instance of required type"
66 | }
67 |
68 |
69 | //////// hasAttribute() ////////
70 |
71 | @Unroll
72 | def 'hasAttribute: return #expected for #desc attribute'() {
73 | expect:
74 | hasAttribute(Size, name) == expected
75 | where:
76 | name | expected
77 | 'min' | true
78 | 'foo' | false
79 |
80 | desc = expected ? 'existing' : 'undefined'
81 | }
82 |
83 |
84 | //////// readAllAttributes() ////////
85 |
86 | def 'readAllAttributes: return attributes as map'() {
87 | given:
88 | def attrs = [message: 'allons-y!', max: 10]
89 | def annotation = TestUtils.createAnnotation(Size, attrs)
90 | def expected = [groups: [], payload: [], min: 0] + attrs
91 | expect:
92 | readAllAttributes(annotation) == expected
93 | }
94 |
95 |
96 | //////// createAnnotation() ////////
97 |
98 | def 'createAnnotation: create annotation when given valid attributes'() {
99 | given:
100 | def attributes = [min: 42, message: 'allons-y!']
101 | when:
102 | def actual = createAnnotation(Size, attributes)
103 | then:
104 | actual instanceof Size
105 | actual.min() == attributes['min']
106 | actual.message() == attributes['message']
107 | }
108 |
109 | @Unroll
110 | def 'createAnnotation: create annotation and ignore #desc'() {
111 | when:
112 | def actual = createAnnotation(Size, attributes)
113 | then:
114 | actual instanceof Size
115 | actual.message() == '{javax.validation.constraints.Size.message}'
116 | where:
117 | attributes | desc
118 | [undefined: 666] | 'undefined attribute'
119 | [message: null] | 'attribute with null'
120 | }
121 |
122 | def 'createAnnotation: throw IllegalArgumentException when wrong attribute type'() {
123 | when:
124 | createAnnotation(Size, [min: 'fail'])
125 | then:
126 | def ex = thrown(IllegalArgumentException)
127 | ex.message == "Attribute 'min' expects int, but given: fail (java.lang.String)"
128 | }
129 |
130 | def 'createAnnotation: throw IllegalArgumentException when omit required attribute'() {
131 | when:
132 | createAnnotation(Pattern, [message: 'fail'])
133 | then:
134 | def ex = thrown(IllegalArgumentException)
135 | ex.message == 'Missing required attribute: regexp'
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/src/test/groovy/cz/jirutka/validator/collection/internal/HibernateValidatorInfoTest.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright 2013-2014 Jakub Jirutka .
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package cz.jirutka.validator.collection.internal
25 |
26 | import spock.lang.Specification
27 | import spock.lang.Unroll
28 |
29 | @Unroll
30 | class HibernateValidatorInfoTest extends Specification {
31 |
32 | def 'parse version: #input'() {
33 | expect:
34 | HibernateValidatorInfo.parseVersion(input) == expected
35 | where:
36 | input | expected
37 | '5.1.1.Final' | 511
38 | '5.2.0-SNAPSHOT' | 520
39 | '4.0.0.GA' | 400
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/test/java/cz/jirutka/validator/collection/fixtures/EachComposite.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright 2013-2014 Jakub Jirutka .
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package cz.jirutka.validator.collection.fixtures;
25 |
26 | import cz.jirutka.validator.collection.constraints.EachPattern;
27 | import cz.jirutka.validator.collection.constraints.EachSize;
28 |
29 | import javax.validation.Constraint;
30 | import javax.validation.Payload;
31 | import java.lang.annotation.Documented;
32 | import java.lang.annotation.Retention;
33 | import java.lang.annotation.Target;
34 |
35 | import static java.lang.annotation.ElementType.FIELD;
36 | import static java.lang.annotation.ElementType.METHOD;
37 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
38 |
39 | @EachSize(min=2, max=8)
40 | @EachPattern(regexp="[a-z]+", message="must contain a-z only")
41 | @Documented
42 | @Retention(RUNTIME)
43 | @Target({ METHOD, FIELD })
44 | @Constraint(validatedBy = {})
45 | public @interface EachComposite {
46 |
47 | String message() default "";
48 | Class>[] groups() default {};
49 | Class extends Payload>[] payload() default {};
50 | }
51 |
--------------------------------------------------------------------------------
/src/test/java/cz/jirutka/validator/collection/fixtures/LegacyEachSize.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright 2013-2014 Jakub Jirutka .
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package cz.jirutka.validator.collection.fixtures;
25 |
26 | import cz.jirutka.validator.collection.CommonEachValidator;
27 |
28 | import javax.validation.Constraint;
29 | import javax.validation.Payload;
30 | import javax.validation.constraints.Size;
31 | import java.lang.annotation.Documented;
32 | import java.lang.annotation.Retention;
33 | import java.lang.annotation.Target;
34 |
35 | import static java.lang.annotation.ElementType.*;
36 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
37 |
38 | @Documented
39 | @Retention(RUNTIME)
40 | @Target({METHOD, FIELD, ANNOTATION_TYPE})
41 | @Constraint(validatedBy = CommonEachValidator.class)
42 | public @interface LegacyEachSize {
43 |
44 | String message() default "";
45 | Class>[] groups() default {};
46 | Class extends Payload>[] payload() default {};
47 |
48 | Size[] value();
49 | }
50 |
--------------------------------------------------------------------------------
/src/test/resources/simplelogger.properties:
--------------------------------------------------------------------------------
1 | org.slf4j.simpleLogger.defaultLogLevel=trace
2 |
--------------------------------------------------------------------------------