Search code examples
bean-validationhibernate-validator

addPropertyNode - equivalent in version 1.0?


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:

  1. Change the application server to Wildfly (or similar, where JSR 349 is implemented)
  2. Solve the problem using JSR 303 only using the addNode()-method.

For the purpose of this question, we rule out possibility 1 (impractical, possible required work).

How would I do this using Bean Validation 1.0?

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 :(


Solution

  • 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 Nodes and is built according to the following rules:

    • if the failing object is the root object, a Node with name set to null is added to the Path.
    • When an association is traversed:
      • a Node object whose name equals the name of the association property (field name or Java Bean property name) is added to Path
      • if the association is a List or an array, the following Node object added contains the index value in getIndex.
      • if the association is a Map, the following Node object added (representing a given map entry) contains the key value in getKey
      • for all Iterable or Map, the following Node object added is marked as inIterable (isInIterable)
    • For a property level constraint (field and getter)
      • a Node object is added to Path whose name equals the name of the property (field name or Java Bean property name)
      • the property path is considered complete
    • For a class level constraint:
      • a Node object is added to Path whose name is null
      • the property path is considered complete