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

Community
  • 1
  • 1
Vogel612
  • 5,620
  • 5
  • 48
  • 73
  • I am not sure I understand your problem? What is the property path you expect in the end? Why don't you use addNode? It's deprecated, but still there. In fact, since you are using Bean Validation 1.0 it is not even deprecated in that environment. The alternative is to upgrade the Bean Validation libraries in your app server. – Hardy Sep 26 '14 at 18:42

1 Answers1

1

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
Vogel612
  • 5,620
  • 5
  • 48
  • 73