Skip to content

Commit 4186c93

Browse files
mkurzgsmet
authored andcommitted
HV-1589 Tests for the caching behaviour of HibernateConstraintValidator
1 parent 3b26aff commit 4186c93

File tree

6 files changed

+341
-25
lines changed

6 files changed

+341
-25
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*
2+
* Hibernate Validator, declare and validate application constraints
3+
*
4+
* License: Apache License, Version 2.0
5+
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
6+
*/
7+
package org.hibernate.validator.test.internal.engine.constraintvalidation;
8+
9+
/**
10+
* @author Matthias Kurz
11+
*/
12+
public class Company {
13+
14+
@SimpleHibernateConstraintValidatorConstraint
15+
private String name;
16+
}

engine/src/test/java/org/hibernate/validator/test/internal/engine/constraintvalidation/ConstraintValidatorManagerTest.java

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
package org.hibernate.validator.test.internal.engine.constraintvalidation;
88

99
import static org.assertj.core.api.Assertions.assertThat;
10+
import static org.hibernate.validator.testutils.ConstraintValidatorInitializationHelper.getConstraintValidatorInitializationContext;
1011
import static org.hibernate.validator.testutils.ConstraintValidatorInitializationHelper.getDummyConstraintValidatorInitializationContext;
1112
import static org.hibernate.validator.testutils.ValidatorUtil.getConfiguration;
1213
import static org.hibernate.validator.testutils.ValidatorUtil.getValidator;
@@ -15,21 +16,30 @@
1516
import static org.testng.Assert.assertNull;
1617
import static org.testng.Assert.assertTrue;
1718

19+
import java.time.Clock;
20+
import java.time.Duration;
1821
import java.util.Set;
1922

23+
import javax.validation.ClockProvider;
2024
import javax.validation.ConstraintValidator;
2125
import javax.validation.ConstraintValidatorFactory;
2226
import javax.validation.Validator;
27+
import javax.validation.ValidatorFactory;
2328
import javax.validation.constraints.NotNull;
2429
import javax.validation.constraints.Size;
2530
import javax.validation.metadata.BeanDescriptor;
2631
import javax.validation.metadata.ConstraintDescriptor;
2732
import javax.validation.metadata.PropertyDescriptor;
2833

34+
import org.hibernate.validator.HibernateValidatorFactory;
35+
import org.hibernate.validator.constraintvalidation.HibernateConstraintValidatorInitializationContext;
2936
import org.hibernate.validator.internal.constraintvalidators.bv.NotNullValidator;
37+
import org.hibernate.validator.internal.engine.DefaultClockProvider;
3038
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorFactoryImpl;
3139
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager;
40+
import org.hibernate.validator.internal.engine.scripting.DefaultScriptEvaluatorFactory;
3241
import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl;
42+
import org.hibernate.validator.spi.scripting.ScriptEvaluatorFactory;
3343
import org.hibernate.validator.testutil.TestForIssue;
3444
import org.testng.annotations.BeforeMethod;
3545
import org.testng.annotations.Test;
@@ -258,6 +268,196 @@ String.class, sizeOnAddress2Descriptor, constraintValidatorFactory, getDummyCons
258268
assertThat( sizeValidatorForAddress1 ).isSameAs( sizeValidatorForAddress2 );
259269
}
260270

271+
@Test
272+
@TestForIssue(jiraKey = "HV-1589")
273+
public void testValidatorsAreCachedPerConstraintAndAnnotationMembersAndScriptEvaluatorFactory() {
274+
Validator validator = getConfiguration()
275+
.addMapping(
276+
ConstraintValidatorManagerTest.class.getResourceAsStream(
277+
"hv-1589-mapping.xml"
278+
)
279+
)
280+
.buildValidatorFactory()
281+
.getValidator();
282+
283+
ConstraintDescriptorImpl<?> sizeOnMiddleNameDescriptor = getSingleConstraintDescriptorForProperty(
284+
validator, User.class, "middleName"
285+
);
286+
ConstraintDescriptorImpl<?> sizeOnAddress1Descriptor = getSingleConstraintDescriptorForProperty(
287+
validator, User.class, "address1"
288+
);
289+
ConstraintDescriptorImpl<?> sizeOnAddress2Descriptor = getSingleConstraintDescriptorForProperty(
290+
validator, User.class, "address2"
291+
);
292+
293+
ScriptEvaluatorFactory scriptEvaluatorFactory1 = new DefaultScriptEvaluatorFactory( null );
294+
ScriptEvaluatorFactory scriptEvaluatorFactory2 = new DefaultScriptEvaluatorFactory( null );
295+
296+
HibernateConstraintValidatorInitializationContext initializationContext1 = getConstraintValidatorInitializationContext(
297+
scriptEvaluatorFactory1, DefaultClockProvider.INSTANCE, Duration.ZERO, null );
298+
HibernateConstraintValidatorInitializationContext initializationContext2 = getConstraintValidatorInitializationContext(
299+
scriptEvaluatorFactory2, DefaultClockProvider.INSTANCE, Duration.ZERO, null );
300+
301+
ConstraintValidator<?, ?> sizeValidatorForMiddleNameCtx1 = constraintValidatorManager.getInitializedValidator(
302+
String.class, sizeOnMiddleNameDescriptor, constraintValidatorFactory, initializationContext1
303+
);
304+
ConstraintValidator<?, ?> sizeValidatorForAddress1Ctx1 = constraintValidatorManager.getInitializedValidator(
305+
String.class, sizeOnAddress1Descriptor, constraintValidatorFactory, initializationContext1
306+
);
307+
ConstraintValidator<?, ?> sizeValidatorForAddress2Ctx1 = constraintValidatorManager.getInitializedValidator(
308+
String.class, sizeOnAddress2Descriptor, constraintValidatorFactory, initializationContext1
309+
);
310+
ConstraintValidator<?, ?> sizeValidatorForAddress2Ctx2 = constraintValidatorManager.getInitializedValidator(
311+
String.class, sizeOnAddress2Descriptor, constraintValidatorFactory, initializationContext2
312+
);
313+
ConstraintValidator<?, ?> sizeValidatorForAddress1Ctx2 = constraintValidatorManager.getInitializedValidator(
314+
String.class, sizeOnAddress1Descriptor, constraintValidatorFactory, initializationContext2
315+
);
316+
317+
assertThat( sizeValidatorForMiddleNameCtx1 ).isNotSameAs( sizeValidatorForAddress1Ctx1 );
318+
assertThat( sizeValidatorForAddress1Ctx1 ).isSameAs( sizeValidatorForAddress2Ctx1 );
319+
assertThat( sizeValidatorForAddress1Ctx1 ).isNotSameAs( sizeValidatorForAddress2Ctx2 );
320+
assertThat( sizeValidatorForAddress2Ctx2 ).isSameAs( sizeValidatorForAddress1Ctx2 );
321+
}
322+
323+
@Test
324+
@TestForIssue(jiraKey = "HV-1589")
325+
public void testValidatorsAreCachedPerConstraintAndAnnotationMembersAndClockProvider() {
326+
Validator validator = getConfiguration()
327+
.addMapping(
328+
ConstraintValidatorManagerTest.class.getResourceAsStream(
329+
"hv-1589-mapping.xml"
330+
)
331+
)
332+
.buildValidatorFactory()
333+
.getValidator();
334+
335+
ConstraintDescriptorImpl<?> sizeOnMiddleNameDescriptor = getSingleConstraintDescriptorForProperty(
336+
validator, User.class, "middleName"
337+
);
338+
ConstraintDescriptorImpl<?> sizeOnAddress1Descriptor = getSingleConstraintDescriptorForProperty(
339+
validator, User.class, "address1"
340+
);
341+
ConstraintDescriptorImpl<?> sizeOnAddress2Descriptor = getSingleConstraintDescriptorForProperty(
342+
validator, User.class, "address2"
343+
);
344+
345+
ScriptEvaluatorFactory scriptEvaluatorFactory = new DefaultScriptEvaluatorFactory( null );
346+
347+
ClockProvider clockProvider1 = new ClockProvider() {
348+
@Override
349+
public Clock getClock() {
350+
return null;
351+
}
352+
};
353+
ClockProvider clockProvider2 = new ClockProvider() {
354+
@Override
355+
public Clock getClock() {
356+
return null;
357+
}
358+
};
359+
360+
HibernateConstraintValidatorInitializationContext initializationContext1 = getConstraintValidatorInitializationContext(
361+
scriptEvaluatorFactory, clockProvider1, Duration.ZERO, null );
362+
HibernateConstraintValidatorInitializationContext initializationContext2 = getConstraintValidatorInitializationContext(
363+
scriptEvaluatorFactory, clockProvider2, Duration.ZERO, null );
364+
365+
ConstraintValidator<?, ?> sizeValidatorForMiddleNameCtx1 = constraintValidatorManager.getInitializedValidator(
366+
String.class, sizeOnMiddleNameDescriptor, constraintValidatorFactory, initializationContext1
367+
);
368+
ConstraintValidator<?, ?> sizeValidatorForAddress1Ctx1 = constraintValidatorManager.getInitializedValidator(
369+
String.class, sizeOnAddress1Descriptor, constraintValidatorFactory, initializationContext1
370+
);
371+
ConstraintValidator<?, ?> sizeValidatorForAddress2Ctx1 = constraintValidatorManager.getInitializedValidator(
372+
String.class, sizeOnAddress2Descriptor, constraintValidatorFactory, initializationContext1
373+
);
374+
ConstraintValidator<?, ?> sizeValidatorForAddress2Ctx2 = constraintValidatorManager.getInitializedValidator(
375+
String.class, sizeOnAddress2Descriptor, constraintValidatorFactory, initializationContext2
376+
);
377+
ConstraintValidator<?, ?> sizeValidatorForAddress1Ctx2 = constraintValidatorManager.getInitializedValidator(
378+
String.class, sizeOnAddress1Descriptor, constraintValidatorFactory, initializationContext2
379+
);
380+
381+
assertThat( sizeValidatorForMiddleNameCtx1 ).isNotSameAs( sizeValidatorForAddress1Ctx1 );
382+
assertThat( sizeValidatorForAddress1Ctx1 ).isSameAs( sizeValidatorForAddress2Ctx1 );
383+
assertThat( sizeValidatorForAddress1Ctx1 ).isNotSameAs( sizeValidatorForAddress2Ctx2 );
384+
assertThat( sizeValidatorForAddress2Ctx2 ).isSameAs( sizeValidatorForAddress1Ctx2 );
385+
}
386+
387+
@Test
388+
@TestForIssue(jiraKey = "HV-1589")
389+
public void testValidatorsAreCachedPerConstraintAndAnnotationMembersAndTemporalValidationTolerance() {
390+
Validator validator = getConfiguration()
391+
.addMapping(
392+
ConstraintValidatorManagerTest.class.getResourceAsStream(
393+
"hv-1589-mapping.xml"
394+
)
395+
)
396+
.buildValidatorFactory()
397+
.getValidator();
398+
399+
ConstraintDescriptorImpl<?> sizeOnMiddleNameDescriptor = getSingleConstraintDescriptorForProperty(
400+
validator, User.class, "middleName"
401+
);
402+
ConstraintDescriptorImpl<?> sizeOnAddress1Descriptor = getSingleConstraintDescriptorForProperty(
403+
validator, User.class, "address1"
404+
);
405+
ConstraintDescriptorImpl<?> sizeOnAddress2Descriptor = getSingleConstraintDescriptorForProperty(
406+
validator, User.class, "address2"
407+
);
408+
409+
ScriptEvaluatorFactory scriptEvaluatorFactory = new DefaultScriptEvaluatorFactory( null );
410+
411+
HibernateConstraintValidatorInitializationContext initializationContext1 = getConstraintValidatorInitializationContext(
412+
scriptEvaluatorFactory, DefaultClockProvider.INSTANCE, Duration.ofDays( 1 ), null );
413+
HibernateConstraintValidatorInitializationContext initializationContext2 = getConstraintValidatorInitializationContext(
414+
scriptEvaluatorFactory, DefaultClockProvider.INSTANCE, Duration.ofDays( 999 ), null );
415+
416+
ConstraintValidator<?, ?> sizeValidatorForMiddleNameCtx1 = constraintValidatorManager.getInitializedValidator(
417+
String.class, sizeOnMiddleNameDescriptor, constraintValidatorFactory, initializationContext1
418+
);
419+
ConstraintValidator<?, ?> sizeValidatorForAddress1Ctx1 = constraintValidatorManager.getInitializedValidator(
420+
String.class, sizeOnAddress1Descriptor, constraintValidatorFactory, initializationContext1
421+
);
422+
ConstraintValidator<?, ?> sizeValidatorForAddress2Ctx1 = constraintValidatorManager.getInitializedValidator(
423+
String.class, sizeOnAddress2Descriptor, constraintValidatorFactory, initializationContext1
424+
);
425+
ConstraintValidator<?, ?> sizeValidatorForAddress2Ctx2 = constraintValidatorManager.getInitializedValidator(
426+
String.class, sizeOnAddress2Descriptor, constraintValidatorFactory, initializationContext2
427+
);
428+
ConstraintValidator<?, ?> sizeValidatorForAddress1Ctx2 = constraintValidatorManager.getInitializedValidator(
429+
String.class, sizeOnAddress1Descriptor, constraintValidatorFactory, initializationContext2
430+
);
431+
432+
assertThat( sizeValidatorForMiddleNameCtx1 ).isNotSameAs( sizeValidatorForAddress1Ctx1 );
433+
assertThat( sizeValidatorForAddress1Ctx1 ).isSameAs( sizeValidatorForAddress2Ctx1 );
434+
assertThat( sizeValidatorForAddress1Ctx1 ).isNotSameAs( sizeValidatorForAddress2Ctx2 );
435+
assertThat( sizeValidatorForAddress2Ctx2 ).isSameAs( sizeValidatorForAddress1Ctx2 );
436+
}
437+
438+
@Test
439+
@TestForIssue(jiraKey = "HV-1589")
440+
public void testHibernateConstraintValidatorsAreNotCachedByConstraintTree() {
441+
try ( ValidatorFactory factory = getConfiguration().buildValidatorFactory() ) {
442+
443+
// Let's validate with different initialization contexts to make sure the ConstraintTree instance
444+
// doesn't cache a HibernateConstraintValidator instance
445+
446+
assertThat( factory
447+
.getValidator().validate( new Company() ).iterator().next().getMessage() ).isEqualTo( "PT0S" );
448+
449+
assertThat( factory
450+
.unwrap( HibernateValidatorFactory.class ).usingContext()
451+
.temporalValidationTolerance( Duration.ofHours( 7 ) )
452+
.getValidator().validate( new Company() ).iterator().next().getMessage() ).isEqualTo( "PT7H" );
453+
454+
assertThat( factory
455+
.unwrap( HibernateValidatorFactory.class ).usingContext()
456+
.temporalValidationTolerance( Duration.ofDays( 5 ) )
457+
.getValidator().validate( new Company() ).iterator().next().getMessage() ).isEqualTo( "PT120H" );
458+
}
459+
}
460+
261461
private ConstraintDescriptorImpl<?> getConstraintDescriptorForProperty(String propertyName) {
262462
return getSingleConstraintDescriptorForProperty( validator, Foo.class, propertyName );
263463
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Hibernate Validator, declare and validate application constraints
3+
*
4+
* License: Apache License, Version 2.0
5+
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
6+
*/
7+
package org.hibernate.validator.test.internal.engine.constraintvalidation;
8+
9+
import java.time.Duration;
10+
11+
import javax.validation.ConstraintValidatorContext;
12+
import javax.validation.metadata.ConstraintDescriptor;
13+
14+
import org.hibernate.validator.constraintvalidation.HibernateConstraintValidator;
15+
import org.hibernate.validator.constraintvalidation.HibernateConstraintValidatorInitializationContext;
16+
17+
public class SimpleHibernateConstraintValidator implements HibernateConstraintValidator<SimpleHibernateConstraintValidatorConstraint, String> {
18+
19+
Duration duration;
20+
21+
@Override
22+
public void initialize(ConstraintDescriptor<SimpleHibernateConstraintValidatorConstraint> constraintDescriptor,
23+
HibernateConstraintValidatorInitializationContext initializationContext) {
24+
duration = initializationContext.getTemporalValidationTolerance();
25+
}
26+
27+
@Override
28+
public boolean isValid(String value, ConstraintValidatorContext context) {
29+
context.buildConstraintViolationWithTemplate( duration.toString() ).addConstraintViolation().disableDefaultConstraintViolation();
30+
return false;
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Hibernate Validator, declare and validate application constraints
3+
*
4+
* License: Apache License, Version 2.0
5+
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
6+
*/
7+
package org.hibernate.validator.test.internal.engine.constraintvalidation;
8+
9+
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
10+
import static java.lang.annotation.ElementType.FIELD;
11+
import static java.lang.annotation.ElementType.METHOD;
12+
import static java.lang.annotation.ElementType.PARAMETER;
13+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
14+
15+
import java.lang.annotation.Documented;
16+
import java.lang.annotation.Retention;
17+
import java.lang.annotation.Target;
18+
19+
import javax.validation.Constraint;
20+
import javax.validation.Payload;
21+
22+
@Target({ FIELD, METHOD, PARAMETER, ANNOTATION_TYPE })
23+
@Retention(RUNTIME)
24+
@Documented
25+
@Constraint(validatedBy = { SimpleHibernateConstraintValidator.class } )
26+
public @interface SimpleHibernateConstraintValidatorConstraint {
27+
String message() default "Invalid";
28+
29+
Class<?>[] groups() default { };
30+
31+
Class<? extends Payload>[] payload() default { };
32+
}

engine/src/test/java/org/hibernate/validator/testutils/ConstraintValidatorInitializationHelper.java

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -29,31 +29,8 @@ public class ConstraintValidatorInitializationHelper {
2929

3030
private static final ConstraintHelper CONSTRAINT_HELPER = new ConstraintHelper();
3131

32-
private static final HibernateConstraintValidatorInitializationContext DUMMY_CONSTRAINT_VALIDATOR_INITIALIZATION_CONTEXT
33-
= new HibernateConstraintValidatorInitializationContext() {
34-
35-
private ScriptEvaluatorFactory scriptEvaluatorFactory = new DefaultScriptEvaluatorFactory( null );
36-
37-
@Override
38-
public ScriptEvaluator getScriptEvaluatorForLanguage(String languageName) {
39-
return scriptEvaluatorFactory.getScriptEvaluatorByLanguageName( languageName );
40-
}
41-
42-
@Override
43-
public ClockProvider getClockProvider() {
44-
return DefaultClockProvider.INSTANCE;
45-
}
46-
47-
@Override
48-
public Duration getTemporalValidationTolerance() {
49-
return Duration.ZERO;
50-
}
51-
52-
@Override
53-
public <C> C getConstraintValidatorPayload(Class<C> type) {
54-
return null;
55-
}
56-
};
32+
private static final HibernateConstraintValidatorInitializationContext DUMMY_CONSTRAINT_VALIDATOR_INITIALIZATION_CONTEXT =
33+
getConstraintValidatorInitializationContext( new DefaultScriptEvaluatorFactory( null ), DefaultClockProvider.INSTANCE, Duration.ZERO, null );
5734

5835
private ConstraintValidatorInitializationHelper() {
5936
}
@@ -87,4 +64,32 @@ public static <A extends Annotation, T> void initialize(
8764
public static HibernateConstraintValidatorInitializationContext getDummyConstraintValidatorInitializationContext() {
8865
return DUMMY_CONSTRAINT_VALIDATOR_INITIALIZATION_CONTEXT;
8966
}
67+
68+
public static HibernateConstraintValidatorInitializationContext getConstraintValidatorInitializationContext(
69+
ScriptEvaluatorFactory scriptEvaluatorFactory, ClockProvider clockProvider, Duration duration, Class<?> payload
70+
) {
71+
return new HibernateConstraintValidatorInitializationContext() {
72+
73+
@Override
74+
public ScriptEvaluator getScriptEvaluatorForLanguage(String languageName) {
75+
return scriptEvaluatorFactory.getScriptEvaluatorByLanguageName( languageName );
76+
}
77+
78+
@Override
79+
public ClockProvider getClockProvider() {
80+
return clockProvider;
81+
}
82+
83+
@Override
84+
public Duration getTemporalValidationTolerance() {
85+
return duration;
86+
}
87+
88+
@Override
89+
@SuppressWarnings("unchecked")
90+
public <C> C getConstraintValidatorPayload(Class<C> type) {
91+
return (C) payload;
92+
}
93+
};
94+
}
9095
}

0 commit comments

Comments
 (0)