Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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;

    ...
}
like image 561
cavpollo Avatar asked Jan 23 '19 02:01

cavpollo


People also ask

Can we create custom annotation for validation?

In this way, we can create different custom annotations for validation purposes. You can find the full source code here. It is easy to create and use custom annotations in Java. Java developers will be relieved of redundant code by using custom annotations.

Where do I put ValidationMessages properties?

By default, ValidationMessages. properties can be located in root of my classpath.

How do I find Constraintvalidatorcontext?

Basically you need to use the ValidatorFactory to obtain a Validator interface, then call validate(c) on that interface, where the parameter c is an instance of the class containing the bean validation annotations.

What is the purpose of custom Validator annotation?

A custom validation annotation can also be defined at the class level to validate more than one attribute of the class. A common use case for this scenario is verifying if two fields of a class have matching values.


1 Answers

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;

    ...

}
like image 130
cavpollo Avatar answered Nov 11 '22 22:11

cavpollo