Relatively simple probably. The Java 7 documentation for the ConstraintViolationBuilder interface specifies:
addNode
ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext addNode(String name)Deprecated. since 1.1 - replaced by addPropertyNode(String) and addBeanNode()
Adds a node to the path the ConstraintViolation will be associated to. name describes a single property. In particular, dot (.) is not allowed.
"Now" the documentation also includes the methods mentioned.
I had a requirement to validate some data using this, and the code is running on a JBoss AS 7.1.1-Final.
The "Getting Started"-Page of jBoss 7 mentions: "Java SE 7 can be used with JBoss AS 7". Now what I want to achieve is simple:
I have a Validator implements ConstraintValidator<AnnotationType, DomainClass>
, there I want to create a nice-looking ConstraintViolationException, that can be nicely handled by JSF / Primefaces to show a message and mark a field as invalid, but alas:
@Override
public boolean isValid(DomainClass instance, ConstraintValidatorContext context) {
// validation logic
if (valid) {
return true;
} else {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(message)
.addPropertyNode("locationName").addConstraintViolation();
return false;
}
}
And here's where it gets problematic... As mentioned in the documentation linked above: addPropertyNode()
is only available as of version 1.1 of the Bean Validation. Unfortunately JBoss AS 7 just includes BeanValidation version 1.0 (as visible in Getting Started Page).
I analyzed stacktraces of working validations, and saw, the propertyPath in ConstraintViolationImpl instances (as used by hibernate) uses multiple dots.
The documentation explicitly states: "In particular, dot (.) is not allowed.".
There's two possiblities now:
addNode()
-method.For the purpose of this question, we rule out possibility 1 (impractical, possible required work).
In particular what is required in the placeholder for this to work properly with JSF Faces-Validation:
@Override
public boolean isValid(DomainClass instance, ConstraintValidatorContext context) {
// validation logic
if (valid) {
return true;
} else {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(message)
.addNode(/* Some awesome String */).addConstraintViolation();
return false;
}
}
Or last but not least, I am totally ... and overread a simpler approach to this :(
It seems the last option actually is the correct one :( I am dumb I am missing the forest for the trees...
What is not quite obvious from the documentation: The .addNode()
calls are supposed to be chained!
@Override
public boolean isValid (DomainClass instance, ConstraintValidatorContext context) {
//validation logic
if (valid) {
return true;
} else {
context.disableDefaultConstraintViolation();
context.buildConstrainViolationWithTemplate(message)
.addNode("tree").addNode("nodes").addNode("to")
.addNode("property").addConstraintViolation();
return false;
}
}
This solves my problem. Additionally I want to mention here, that the JSR-303 Section 4.2 - Constraint Violation defines the correct rules for building the propertyPath:
Path
is made of Node
s and is built according to the following rules: