views:

1254

answers:

1

While working with Hibernate Validator, I noticed that the @NotEmpty and @NotNull annotations produce duplicate messages in the InvalidValue array returned by getInvalidValues(...).

If I specify a message like @NotEmpty(message = "My error message."), then I'll get one InvalidValue of "My error message." and a second of "may not be null or empty"

If i don't include a message (eg @NotEmpty by itself), then I get two copies of the InvalidValue with a message field of "may not be null or empty".

Why does Hibernate Validator do this?? Shouldn't I get one message, either the value that I override using the parameter, or the default message, but not both??


For some more context:

I am extending ClassValidator<T> with my own ClassValidator<MyClass> implementation. I do so to add some custom validations which cannot be done by annotation. I need to see the run time value of more than one property of the class in order to determine the validation.

I get the validations when I call myClassValidator.getInvalidValues(), which I override. Inside my implementation of getInvalidValues() I call super.getInvalidValues() to create the initial error list, and then I add my custom errors to that list. In any case, the call to super.getInvalidValues() contains the duplicate messages, one matching the message property passed into the annotation, and a second with the stock value of the annotation message.


+1  A: 

Justin,

I've been working with Hibernate Validator for the last couple of months. While I have not run into the same issue that you've described, I also have not extended ClassValidator. For custom validation, the Hibernate Reference Guide indicates that writing custom constraints is the way to go.

I have been able to use the built-in constraints almost exclusively on my current project. In one case, where I needed to do some very specific calculations on an integer field, I wrote a custom constraint as described in the reference guide; it was a breeze.

Speaking to your specific problem, I wrote a simple test app as a sort of sanity check on my part:

import org.hibernate.validator.*;

public class HibernateValidatorTest {
    @NotEmpty
    @NotNull
    private String validateMe;

    public static void main ( String[] args ) {
     ClassValidator<HibernateValidatorTest> validator = 
      new ClassValidator<HibernateValidatorTest>( HibernateValidatorTest.class ); 

     InvalidValue[] inVals = 
      validator.getInvalidValues( new HibernateValidatorTest() );

     for ( InvalidValue inVal : inVals ) {
      System.out.println( inVal.getMessage() );
     }
    }
}

With both Hibernate constraints on the validateMe field, the console output is:

may not be null or empty
may not be null

Removing one or the other has the expected effect of printing only a single message to the console.

I hope this is helpful.

Brian T. Grant

Brian T. Grant
Yyou would of course get two errors if you do both @NotNull and @NotEmpty, but that is not what I'm doing. I only annotate with the single constraint, for example: @NotNull(message = "foo"), and if it is processed via the extended class validator, I get two messages: "foo" and "may not be null"
Justin Standard
You are right that it is better to use a custom constraint, but this does not work if you need to compare the runtime value of more than one property in the class in order to perform the validation. Annotations cannot do such a thing. One option is to try class level annotations, assuming you can override the property path to point to the field you are really validating...
Justin Standard
Justin,I must have missed the importance of inspecting runtime values of multiple fields. An option for dealing with such a situation may be to annotate a method on your class which validates those fields. If you put @AssertTrue on method, then you could do all of your multi-field comparison/validation within that method and return true/false based on whether those fields are valid. I realize that your basic question/trouble may still be the ClassValidator subclass. I'm merely suggesting that you may be able to get what you need without having to extend ClassValidator.
Brian T. Grant