cavpollo
cavpollo

Reputation: 4318

How to interpolate the ConstraintValidator message on a Custom Validation Annotation

I've read some Q&As and guides (like Hibernate Documentation) as to how to work with Hibernate's ConstrainValidator, but none of them mention clearly how to interpolate a value in a specific position of a validation error message when creating your own custom validation annotation.

For example, if I have a validation error message that looks like this:

foo.bar.error=This value '{myValue}' is wrong.

I would like to obtain the following message if the validation fails:

The value 'some wrong value' is wrong.

The validation would be used like this:

public class SomeClass {

    @CustomAnnotation(message="{foo.bar.error}")
    public MyObject myObject;

    ...

}

public class MyObject {
    private String myValue;

    ...
}

Upvotes: 14

Views: 13300

Answers (2)

vicangel
vicangel

Reputation: 162

You could also try this:

public class CustomValueValidator implements ConstraintValidator<CustomAnnotation, MyObject> {


    @Override
    public boolean isValid(MyObject myObject, ConstraintValidatorContext context) {
        boolean valid;

        if (!valid) {
         context.disableDefaultConstraintViolation();
         context.buildConstraintViolationWithTemplate("validation message").addConstraintViolation();
        }

        return valid;
    }
}

check also: https://docs.jboss.org/hibernate/beanvalidation/spec/1.0/api/javax/validation/ConstraintValidatorContext.html

Upvotes: 0

cavpollo
cavpollo

Reputation: 4318

I've found a way to interpolate the message without much fuzz.

First set your ValidationMessages.properties (or wherever your validation messages are stored) as before:

foo.bar.error=This value '{wrongValue}' is wrong.

Create your annotation like you normally would:

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Documented
@Constraint(validatedBy = CustomValueValidator.class)
@Target(FIELD)
@Retention(RUNTIME)
public @interface CustomAnnotation {    
    String message() default "{foo.bar.error}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

Implement your constraint validator like this:

import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorContextImpl;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class CustomValueValidator 
        implements ConstraintValidator<CustomAnnotation, MyObject> {

    @Override
    public void initialize(final CustomAnnotation constraintAnnotation) {
        // Extract any value you would need from the annotation
    }

    @Override
    public boolean isValid(final MyObject myObject, 
                           final ConstraintValidatorContext context) {
        boolean valid;

        // Add your validations over the 'myObject' object

        if (!valid) {
            ((ConstraintValidatorContextImpl) context)
                    .addMessageParameter("wrongValue", myObject.getMyValue());
        }

        return valid;
    }
}

Now all that is left is to use the annotation:

public class SomeClass {

    // I'm using the default message. You could override it as a parameter
    @CustomAnnotation
    public MyObject anotherObject;

    ...

}

Upvotes: 19

Related Questions