1

I want to validate a field birthYear in way: "User's age has to be below 50."

So I want to use JSR-303 annotation validation like this:

@Max(Calendar.getInstance().get(Calendar.YEAR) - 50)
private int birthYear;

But the compiler says "Attribute value must be constant."

Is there a way to do it in a simple way, such as this? Or is it necessary to implement my own validator for that?

StaNov
  • 332
  • 1
  • 4
  • 17
  • possible duplicate of [The value for annotation attribute Min.value must be a constant expression](http://stackoverflow.com/questions/16744067/the-value-for-annotation-attribute-min-value-must-be-a-constant-expression) – BalusC Sep 16 '13 at 16:56
  • Yeah, you're right. I wasn't able to google it. – StaNov Sep 16 '13 at 16:57
  • But still, is there a way to do it? Easier than implementing custom validator? – StaNov Sep 16 '13 at 16:59
  • Just copypaste the exact error message into search field. E.g. https://www.google.com/search?q=bean+validation+%22Attribute+value+must+be+constant%22 – BalusC Sep 16 '13 at 16:59

3 Answers3

1

The problem is that the annotations params need to have a value that can be resolved at compile time, but the Call to Calendar.getInstance().get(Calendar.YEAR) can only be resolved at runtime thus the compiler error.

You are better off in this type of situation to write the validation logic in the setter logic, something like

public  void setBirthYear( int year){ 
   if( Calendar.getInstance().get(Calendar.YEAR) - year < 50) {
   {
     throw IllegalAgumentException()
   }
   this.birthYear = year;
} 

The alternative is that you can write a custom JSR 303 Annotation something like @VerifyAge(maxAge=50) then in the handler for the annotation you can check that the value is less than 50.

See http://docs.jboss.org/hibernate/validator/5.0/reference/en-US/html/validator-customconstraints.html for details on how to write a custom validation annotation.

ams
  • 60,316
  • 68
  • 200
  • 288
0

As your error message suggests, you cannot have expressions in annotation values and therefore you'll need to use a custom validation annotation.

It's relatively easy to do this:

Annotation

@Constraint(validatedBy = AgeConstraintValidator.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface MaxAge {

/**
 * The age against which to validate.
 */
int value();

String message() default "com.mycompany.validation.MaxAge.message";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

Constraint Validator

public class AgeConstraintValidator implements ConstraintValidator<MaxAge, Integer> {

private int maximumAge;

@Override
public void initialize(MaxAge constraintAnnotation) {
    this.maximumAge = constraintAnnotation.value();
}

@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
    if (value == null) {
        return true;
    }

    return value.intValue() <= this.maximumAge;
}

}

Then you can just annotate your field with @MaxAge(50) and it should work.

ATG
  • 1,679
  • 14
  • 25
0

If you’re using the Spring Framework then you can use the Spring Expression Language (SpEL) for that. I’ve wrote a small library that provides JSR-303 validator based on SpEL. Take a look at https://github.com/jirutka/validator-spring.

With this library you can write your validation like this:

@SpELAssert("#this < T(java.util.Calendar).getInstance().get(T(java.util.Calendar).YEAR) - 50")
private int birthYear;

However, the code to obtain the current year is quite ugly, isn’t it? Let’s put it into a helper class!

public class CalendarHelper {
    public static int todayYear() {
        return Calendar.getInstance().get(Calendar.YEAR);
    }
}

And then you can do this:

@SpELAssert(value="#this < #todayYear() - 50", helpers=CalendarHelper.class)
private int birthYear;
Jakub Jirutka
  • 10,269
  • 4
  • 42
  • 35