Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you change an annotation message at run time?

I'm trying to include a dynamic message in my annotation that changes the main body of the text based on the values that are found in the other variables that are passed to it. I set a default message, but when a certain indicator is set, I want to display a different message. Is this possible?

Here's my annotation -

@Target({TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = FieldMatchValidator.class)
@Documented
public @interface FieldMatch
{
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
    String first();
    String second();
    String third() default "";
    String match() default "true";
    String message() default "{error.theseValuesDontMatch}";

    /**
     * Defines several <code>@FieldMatch</code> annotations on the same element
     *
     * @see FieldMatch
     */
    @Target({TYPE, ANNOTATION_TYPE})
    @Retention(RUNTIME)
    @Documented @interface List
    {
        FieldMatch[] value();
    }
}

Here's the validator class used by the annotation -

public class FieldMatchValidator implements ConstraintValidator<FieldMatch, Object>
{
    private String firstFieldName;
    private String secondFieldName;
    private String thirdFieldName;
    private String match;
    private String message;

    @Override
    public void initialize(FieldMatch constraintAnnotation)
    {
        firstFieldName = constraintAnnotation.first();
        secondFieldName = constraintAnnotation.second();
        thirdFieldName = constraintAnnotation.third();
        match = constraintAnnotation.match();
        if(match != null && !Boolean.getBoolean(match)){
            message = "error.theseValuesMustNotMatch";
        }
    }

    @Override
    public boolean isValid(final Object value, final ConstraintValidatorContext context)
    {
        try
        {
            final Object firstObj = BeanUtils.getProperty(value, firstFieldName);
            final Object secondObj = BeanUtils.getProperty(value, secondFieldName);
            final Object thirdObj = BeanUtils.getProperty(value, thirdFieldName);
            final String same = BeanUtils.getProperty(value, match);

            boolean valid = false;
            if(same != null && Boolean.getBoolean(same)){
                if("".equals(thirdObj)){
                    valid = firstObj == null && secondObj == null || firstObj != null && firstObj.equals(secondObj) ;
                }
                else{
                    valid = firstObj != null && firstObj.equals(secondObj) && firstObj.equals(thirdObj) ;   
                }
            }
            else{
                if("".equals(thirdObj)){
                    valid = firstObj == null && secondObj == null || firstObj != null && !firstObj.equals(secondObj) ;
                }
                else{
                    valid = firstObj != null && !(firstObj.equals(secondObj) && firstObj.equals(thirdObj)) ;   
                }
            }
            return valid ;
        }
        catch (final Exception ignore)
        {
            // ignore
        }
        return true;
    }
}

The piece I'm most interested in is the code that reads -

    if(match != null && !Boolean.getBoolean(match)){
        message = "password.error.theseValuesMustNotMatch";
    }
like image 455
coder Avatar asked May 18 '11 17:05

coder


People also ask

How do I set annotation value at runtime?

extends Annotation>, Annotation> map; We will update this map to alter annotation at runtime. Approach to access this map differs in various JDK implementation. We will discuss it for JDK7 and JDK8.

Can you extend an annotation?

In Java SE 6, annotations cannot subclass one another, and an annotation is not allowed to extend/implement any interfaces.


1 Answers

Here's how I was able to do this -

@Override public void initialize(FieldMatch constraintAnnotation) {     firstFieldName = constraintAnnotation.first();     secondFieldName = constraintAnnotation.second();     thirdFieldName = constraintAnnotation.third();     match = constraintAnnotation.match();      //set a message variable on initialization         if("true".equals(match)){         message = constraintAnnotation.message();     }     else{         message = "{password.error.threeQuestionsSameAnswer}";} }  @Override public boolean isValid(final Object value, final ConstraintValidatorContext context) {     Object firstObj = null;     Object secondObj = null;     Object thirdObj = null;      //disable existing violation message     context.disableDefaultConstraintViolation();     //build new violation message and add it     context.buildConstraintViolationWithTemplate(message).addConstraintViolation();  etc......... } 
like image 90
coder Avatar answered Sep 22 '22 06:09

coder