Skip to content

Commit 58a9365

Browse files
committed
HV-1978 Propagated EL level to iterable nodes
(cherry picked from commit 574db66)
1 parent 94078ee commit 58a9365

File tree

3 files changed

+190
-16
lines changed

3 files changed

+190
-16
lines changed

engine/src/main/java/org/hibernate/validator/internal/engine/constraintvalidation/ConstraintValidatorContextImpl.java

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -189,11 +189,16 @@ private ConstraintViolationCreationContext getDefaultConstraintViolationCreation
189189
private abstract class NodeBuilderBase {
190190

191191
protected final String messageTemplate;
192-
protected ExpressionLanguageFeatureLevel expressionLanguageFeatureLevel = defaultCustomViolationExpressionLanguageFeatureLevel;
192+
protected ExpressionLanguageFeatureLevel expressionLanguageFeatureLevel;
193193
protected PathImpl propertyPath;
194194

195195
protected NodeBuilderBase(String template, PathImpl path) {
196+
this( template, defaultCustomViolationExpressionLanguageFeatureLevel, path );
197+
}
198+
199+
protected NodeBuilderBase(String template, ExpressionLanguageFeatureLevel expressionLanguageFeatureLevel, PathImpl path) {
196200
this.messageTemplate = template;
201+
this.expressionLanguageFeatureLevel = expressionLanguageFeatureLevel;
197202
this.propertyPath = path;
198203
}
199204

@@ -238,7 +243,7 @@ public NodeBuilderDefinedContext addNode(String name) {
238243
dropLeafNodeIfRequired();
239244
propertyPath.addPropertyNode( name );
240245

241-
return new NodeBuilder( messageTemplate, propertyPath );
246+
return new NodeBuilder( messageTemplate, expressionLanguageFeatureLevel, propertyPath );
242247
}
243248

244249
@Override
@@ -279,8 +284,8 @@ private void dropLeafNodeIfRequired() {
279284
protected class NodeBuilder extends NodeBuilderBase
280285
implements NodeBuilderDefinedContext, LeafNodeBuilderDefinedContext, ContainerElementNodeBuilderDefinedContext {
281286

282-
protected NodeBuilder(String template, PathImpl path) {
283-
super( template, path );
287+
protected NodeBuilder(String template, ExpressionLanguageFeatureLevel expressionLanguageFeatureLevel, PathImpl path) {
288+
super( template, expressionLanguageFeatureLevel, path );
284289
}
285290

286291
@Override
@@ -322,8 +327,7 @@ private DeferredNodeBuilder(String template,
322327
PathImpl path,
323328
String nodeName,
324329
ElementKind leafNodeKind) {
325-
super( template, path );
326-
this.expressionLanguageFeatureLevel = expressionLanguageFeatureLevel;
330+
super( template, expressionLanguageFeatureLevel, path );
327331
this.leafNodeName = nodeName;
328332
this.leafNodeKind = leafNodeKind;
329333
this.leafNodeContainerType = null;
@@ -336,8 +340,7 @@ private DeferredNodeBuilder(String template,
336340
String nodeName,
337341
Class<?> leafNodeContainerType,
338342
Integer leafNodeTypeArgumentIndex) {
339-
super( template, path );
340-
this.expressionLanguageFeatureLevel = expressionLanguageFeatureLevel;
343+
super( template, expressionLanguageFeatureLevel, path );
341344
this.leafNodeName = nodeName;
342345
this.leafNodeKind = ElementKind.CONTAINER_ELEMENT;
343346
this.leafNodeContainerType = leafNodeContainerType;
@@ -360,14 +363,14 @@ public DeferredNodeBuilder inContainer(Class<?> containerClass, Integer typeArgu
360363
public NodeBuilder atKey(Object key) {
361364
propertyPath.makeLeafNodeIterableAndSetMapKey( key );
362365
addLeafNode();
363-
return new NodeBuilder( messageTemplate, propertyPath );
366+
return new NodeBuilder( messageTemplate, expressionLanguageFeatureLevel, propertyPath );
364367
}
365368

366369
@Override
367370
public NodeBuilder atIndex(Integer index) {
368371
propertyPath.makeLeafNodeIterableAndSetIndex( index );
369372
addLeafNode();
370-
return new NodeBuilder( messageTemplate, propertyPath );
373+
return new NodeBuilder( messageTemplate, expressionLanguageFeatureLevel, propertyPath );
371374
}
372375

373376
@Override

engine/src/main/java/org/hibernate/validator/internal/engine/constraintvalidation/CrossParameterConstraintValidatorContextImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public NodeBuilderDefinedContext addParameterNode(int index) {
7575
dropLeafNode();
7676
propertyPath.addParameterNode( methodParameterNames.get( index ), index );
7777

78-
return new NodeBuilder( messageTemplate, propertyPath );
78+
return new NodeBuilder( messageTemplate, expressionLanguageFeatureLevel, propertyPath );
7979
}
8080

8181
private void dropLeafNode() {

engine/src/test/java/org/hibernate/validator/test/el/CustomViolationExpressionLanguageFeatureLevelTest.java

Lines changed: 176 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
import java.lang.annotation.Documented;
1919
import java.lang.annotation.Retention;
2020
import java.lang.annotation.Target;
21+
import java.util.Collections;
22+
import java.util.List;
23+
import java.util.Map;
2124

2225
import jakarta.validation.Constraint;
2326
import jakarta.validation.ConstraintValidator;
@@ -111,7 +114,14 @@ public void enable_el_bean_properties() {
111114
assertThat( validator.validate( new EnableELBeanPropertiesBean( "value" ) ) )
112115
.containsOnlyViolations( violationOf( EnableELBeanPropertiesConstraint.class ).withMessage( "Variable: value" ),
113116
violationOf( EnableELBeanPropertiesConstraint.class ).withMessage( "Bean property: 118" ),
114-
violationOf( EnableELBeanPropertiesConstraint.class ).withMessage( "Method execution: ${'aaaa'.substring(0, 1)}" ) );
117+
violationOf( EnableELBeanPropertiesConstraint.class ).withMessage( "Method execution: ${'aaaa'.substring(0, 1)}" ),
118+
violationOf( EnableELBeanPropertiesConstraint.class ).withMessage( "Variable List: value" ),
119+
violationOf( EnableELBeanPropertiesConstraint.class ).withMessage( "Bean property List: 118" ),
120+
violationOf( EnableELBeanPropertiesConstraint.class ).withMessage( "Method execution List: ${'aaaa'.substring(0, 1)}" ),
121+
violationOf( EnableELBeanPropertiesConstraint.class ).withMessage( "Variable Map: value" ),
122+
violationOf( EnableELBeanPropertiesConstraint.class ).withMessage( "Bean property Map: 118" ),
123+
violationOf( EnableELBeanPropertiesConstraint.class ).withMessage( "Method execution Map: ${'aaaa'.substring(0, 1)}" )
124+
);
115125
}
116126

117127
@Test
@@ -125,7 +135,13 @@ public void enable_el_bean_methods() {
125135
assertThat( validator.validate( new EnableELBeanMethodsBean( "value" ) ) )
126136
.containsOnlyViolations( violationOf( EnableELBeanMethodsConstraint.class ).withMessage( "Variable: value" ),
127137
violationOf( EnableELBeanMethodsConstraint.class ).withMessage( "Bean property: 118" ),
128-
violationOf( EnableELBeanMethodsConstraint.class ).withMessage( "Method execution: a" ) );
138+
violationOf( EnableELBeanMethodsConstraint.class ).withMessage( "Method execution: a" ),
139+
violationOf( EnableELBeanMethodsConstraint.class ).withMessage( "Variable List: value" ),
140+
violationOf( EnableELBeanMethodsConstraint.class ).withMessage( "Bean property List: 118" ),
141+
violationOf( EnableELBeanMethodsConstraint.class ).withMessage( "Method execution List: a" ),
142+
violationOf( EnableELBeanMethodsConstraint.class ).withMessage( "Variable Map: value" ),
143+
violationOf( EnableELBeanMethodsConstraint.class ).withMessage( "Bean property Map: 118" ),
144+
violationOf( EnableELBeanMethodsConstraint.class ).withMessage( "Method execution Map: a" ) );
129145
}
130146

131147
@Test
@@ -174,7 +190,13 @@ public void run() {
174190
assertThat( validator.validate( new EnableELBeanMethodsBean( "value" ) ) )
175191
.containsOnlyViolations( violationOf( EnableELBeanMethodsConstraint.class ).withMessage( "Variable: value" ),
176192
violationOf( EnableELBeanMethodsConstraint.class ).withMessage( "Bean property: 118" ),
177-
violationOf( EnableELBeanMethodsConstraint.class ).withMessage( "Method execution: a" ) );
193+
violationOf( EnableELBeanMethodsConstraint.class ).withMessage( "Method execution: a" ),
194+
violationOf( EnableELBeanMethodsConstraint.class ).withMessage( "Variable List: value" ),
195+
violationOf( EnableELBeanMethodsConstraint.class ).withMessage( "Bean property List: 118" ),
196+
violationOf( EnableELBeanMethodsConstraint.class ).withMessage( "Method execution List: a" ),
197+
violationOf( EnableELBeanMethodsConstraint.class ).withMessage( "Variable Map: value" ),
198+
violationOf( EnableELBeanMethodsConstraint.class ).withMessage( "Bean property Map: 118" ),
199+
violationOf( EnableELBeanMethodsConstraint.class ).withMessage( "Method execution Map: a" ) );
178200
}
179201
} );
180202
}
@@ -262,7 +284,7 @@ public EnableELBean(String value) {
262284
@Target({ FIELD, METHOD, PARAMETER, ANNOTATION_TYPE })
263285
@Retention(RUNTIME)
264286
@Documented
265-
@Constraint(validatedBy = { EnableELBeanPropertiesStringValidator.class })
287+
@Constraint(validatedBy = { EnableELBeanPropertiesStringValidator.class, EnableELBeanPropertiesMapValidator.class, EnableELBeanPropertiesListValidator.class })
266288
private @interface EnableELBeanPropertiesConstraint {
267289

268290
String message() default "-";
@@ -294,20 +316,94 @@ public boolean isValid(String value, ConstraintValidatorContext context) {
294316
}
295317
}
296318

319+
public static class EnableELBeanPropertiesMapValidator implements ConstraintValidator<EnableELBeanPropertiesConstraint, Map<String, String>> {
320+
321+
@Override
322+
public boolean isValid(Map<String, String> value, ConstraintValidatorContext context) {
323+
HibernateConstraintValidatorContext hibernateContext = (HibernateConstraintValidatorContext) context;
324+
325+
hibernateContext.disableDefaultConstraintViolation();
326+
327+
String key = value.keySet().iterator().next();
328+
hibernateContext.addExpressionVariable( "key", key );
329+
330+
hibernateContext.buildConstraintViolationWithTemplate( "Variable Map: ${validatedValue[key]}" )
331+
.enableExpressionLanguage( ExpressionLanguageFeatureLevel.BEAN_PROPERTIES )
332+
.addBeanNode()
333+
.inIterable()
334+
.atKey( key )
335+
.addConstraintViolation();
336+
hibernateContext.buildConstraintViolationWithTemplate( "Bean property Map: ${validatedValue[key].bytes[0]}" )
337+
.enableExpressionLanguage( ExpressionLanguageFeatureLevel.BEAN_PROPERTIES )
338+
.addBeanNode()
339+
.inIterable()
340+
.atKey( key )
341+
.addConstraintViolation();
342+
hibernateContext.buildConstraintViolationWithTemplate( "Method execution Map: ${'aaaa'.substring(0, 1)}" )
343+
.enableExpressionLanguage( ExpressionLanguageFeatureLevel.BEAN_PROPERTIES )
344+
.addBeanNode()
345+
.inIterable()
346+
.atKey( key )
347+
.addConstraintViolation();
348+
349+
return false;
350+
}
351+
}
352+
353+
public static class EnableELBeanPropertiesListValidator implements ConstraintValidator<EnableELBeanPropertiesConstraint, List<String>> {
354+
355+
@Override
356+
public boolean isValid(List<String> value, ConstraintValidatorContext context) {
357+
HibernateConstraintValidatorContext hibernateContext = (HibernateConstraintValidatorContext) context;
358+
359+
hibernateContext.disableDefaultConstraintViolation();
360+
int index = 0;
361+
hibernateContext.addExpressionVariable( "index", index );
362+
hibernateContext.buildConstraintViolationWithTemplate( "Variable List: ${validatedValue[index]}" )
363+
.enableExpressionLanguage( ExpressionLanguageFeatureLevel.BEAN_PROPERTIES )
364+
.addBeanNode()
365+
.inIterable()
366+
.atIndex( index )
367+
.addConstraintViolation();
368+
hibernateContext.buildConstraintViolationWithTemplate( "Bean property List: ${validatedValue[index].bytes[0]}" )
369+
.enableExpressionLanguage( ExpressionLanguageFeatureLevel.BEAN_PROPERTIES )
370+
.addBeanNode()
371+
.inIterable()
372+
.atIndex( index )
373+
.addConstraintViolation();
374+
hibernateContext.buildConstraintViolationWithTemplate( "Method execution List: ${'aaaa'.substring(0, 1)}" )
375+
.enableExpressionLanguage( ExpressionLanguageFeatureLevel.BEAN_PROPERTIES )
376+
.addBeanNode()
377+
.inIterable()
378+
.atIndex( index )
379+
.addConstraintViolation();
380+
381+
return false;
382+
}
383+
}
384+
297385
public static class EnableELBeanPropertiesBean {
298386

299387
public EnableELBeanPropertiesBean(String value) {
300388
this.value = value;
389+
this.map = Collections.singletonMap( value, value );
390+
this.list = Collections.singletonList( value );
301391
}
302392

303393
@EnableELBeanPropertiesConstraint
304394
public String value;
395+
396+
@EnableELBeanPropertiesConstraint
397+
public Map<String, String> map;
398+
399+
@EnableELBeanPropertiesConstraint
400+
public List<String> list;
305401
}
306402

307403
@Target({ FIELD, METHOD, PARAMETER, ANNOTATION_TYPE })
308404
@Retention(RUNTIME)
309405
@Documented
310-
@Constraint(validatedBy = { EnableELBeanMethodsStringValidator.class })
406+
@Constraint(validatedBy = { EnableELBeanMethodsStringValidator.class, EnableELBeanMethodsListValidator.class, EnableELBeanMethodsMapValidator.class })
311407
private @interface EnableELBeanMethodsConstraint {
312408

313409
String message() default "-";
@@ -339,14 +435,89 @@ public boolean isValid(String value, ConstraintValidatorContext context) {
339435
}
340436
}
341437

438+
public static class EnableELBeanMethodsListValidator implements ConstraintValidator<EnableELBeanMethodsConstraint, List<String>> {
439+
440+
@Override
441+
public boolean isValid(List<String> value, ConstraintValidatorContext context) {
442+
HibernateConstraintValidatorContext hibernateContext = (HibernateConstraintValidatorContext) context;
443+
444+
hibernateContext.disableDefaultConstraintViolation();
445+
446+
int index = 0;
447+
hibernateContext.addExpressionVariable( "index", index );
448+
hibernateContext.buildConstraintViolationWithTemplate( "Variable List: ${validatedValue[index]}" )
449+
.enableExpressionLanguage( ExpressionLanguageFeatureLevel.BEAN_METHODS )
450+
.addBeanNode()
451+
.inIterable()
452+
.atIndex( index )
453+
.addConstraintViolation();
454+
hibernateContext.buildConstraintViolationWithTemplate( "Bean property List: ${validatedValue[index].bytes[0]}" )
455+
.enableExpressionLanguage( ExpressionLanguageFeatureLevel.BEAN_METHODS )
456+
.addBeanNode()
457+
.inIterable()
458+
.atIndex( index )
459+
.addConstraintViolation();
460+
hibernateContext.buildConstraintViolationWithTemplate( "Method execution List: ${'aaaa'.substring(0, 1)}" )
461+
.enableExpressionLanguage( ExpressionLanguageFeatureLevel.BEAN_METHODS )
462+
.addBeanNode()
463+
.inIterable()
464+
.atIndex( index )
465+
.addConstraintViolation();
466+
467+
return false;
468+
}
469+
}
470+
471+
public static class EnableELBeanMethodsMapValidator implements ConstraintValidator<EnableELBeanMethodsConstraint, Map<String, String>> {
472+
473+
@Override
474+
public boolean isValid(Map<String, String> value, ConstraintValidatorContext context) {
475+
HibernateConstraintValidatorContext hibernateContext = (HibernateConstraintValidatorContext) context;
476+
477+
hibernateContext.disableDefaultConstraintViolation();
478+
479+
String key = value.keySet().iterator().next();
480+
hibernateContext.addExpressionVariable( "key", key );
481+
482+
hibernateContext.buildConstraintViolationWithTemplate( "Variable Map: ${validatedValue[key]}" )
483+
.enableExpressionLanguage( ExpressionLanguageFeatureLevel.BEAN_METHODS )
484+
.addBeanNode()
485+
.inIterable()
486+
.atKey( key )
487+
.addConstraintViolation();
488+
hibernateContext.buildConstraintViolationWithTemplate( "Bean property Map: ${validatedValue[key].bytes[0]}" )
489+
.enableExpressionLanguage( ExpressionLanguageFeatureLevel.BEAN_METHODS )
490+
.addBeanNode()
491+
.inIterable()
492+
.atKey( key )
493+
.addConstraintViolation();
494+
hibernateContext.buildConstraintViolationWithTemplate( "Method execution Map: ${'aaaa'.substring(0, 1)}" )
495+
.enableExpressionLanguage( ExpressionLanguageFeatureLevel.BEAN_METHODS )
496+
.addBeanNode()
497+
.inIterable()
498+
.atKey( key )
499+
.addConstraintViolation();
500+
501+
return false;
502+
}
503+
}
504+
342505
public static class EnableELBeanMethodsBean {
343506

344507
public EnableELBeanMethodsBean(String value) {
345508
this.value = value;
509+
this.map = Collections.singletonMap( value, value );
510+
this.list = Collections.singletonList( value );
346511
}
347512

348513
@EnableELBeanMethodsConstraint
349514
public String value;
515+
516+
@EnableELBeanMethodsConstraint
517+
public Map<String, String> map;
518+
519+
@EnableELBeanMethodsConstraint
520+
public List<String> list;
350521
}
351522

352523
@Target({ FIELD, METHOD, PARAMETER, ANNOTATION_TYPE })

0 commit comments

Comments
 (0)