Erfan Ahmed
Erfan Ahmed

Reputation: 1613

Java annotation: using a field value into another field

I have the following annotation class

public @interface Size {
  int min() default 1;
  int max() default 100;
  String message() default "Age between min - max";
}

Here at the default message() I want the default value of min() and max(). Simply writing String message() default "Age between" + min() + "-" + max(); doesn't work here. Is there any direct way to do it?

EDIT 1: I have a person class too

public class Person {

  @Size(max = 10)
  private String name;

  @Size(min = 18, message = "Age can not be less than {min}")
  private int age;

  public Person(String s, int i) {
    this.name = s;
    this.age = i;
  }
}

Now, Here the min() and max() value can be set. Therefore if the user gives wrong input then the message() will be printer accordingly.

EDIT 2: As @nicolas wanted. Here the AnnonatedValidator class that validated the inputs and print error message.

public class AnnotatedValidator {

public static void validate(Person p, List<ValidationError> errors) {

    try {
        Field[] fields = p.getClass().getDeclaredFields();
        for(Field field : fields) {
            if(field.getType().equals(String.class)){
                field.setAccessible(true);
                String string = (String)field.get(p);

                Annotation[] annotationsName = field.getDeclaredAnnotations();
                for (Annotation annotation : annotationsName){
                    if (annotation instanceof Size){
                        Size size = (Size) annotation;
                        if (string.length() < size.min() || string.length() > size.max()) {
                            error(size, errors);
                        }
                    }
                }

            } else if (field.getType().equals(int.class)) {
                field.setAccessible(true);
                int integer = (Integer)field.get(p);

                Annotation[] annotationsAge = field.getDeclaredAnnotations();
                for (Annotation annotation : annotationsAge){
                    if (annotation instanceof Size){
                        Size size = (Size) annotation;
                        if (integer < size.min() || integer > size.max()) {
                            error(size,errors);
                        }
                    }
                }
            }
        }

    }catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}

public static void print(List<ValidationError> errors) {
    for (int i = 0; i < errors.size(); i++){
        System.out.println("Errors: " + errors.get(i).getError());
    }
}

public static void error (Size size, List<ValidationError> errors) {
    String error = size.message();
    if (!error.equals(null)) {
        if (error.contains("min")) {
            error = error.replace("min", ""+size.min());
        }
        if (error.contains("max")){
            error = error.replace("max", ""+size.max());
        }
    }

    ValidationError v = new ValidationError();
    v.setError(error);
    errors.add(v);
}
}

ValidationError is an another class that just saves the errors.

Upvotes: 2

Views: 3157

Answers (1)

Sotirios Delimanolis
Sotirios Delimanolis

Reputation: 279890

No, default values for String types must be constant expressions, as the Java Language Specification dictates.

It is a compile-time error if the element type is not commensurate with the element value. An element type T is commensurate with an element value V if and only if one of the following is true:

  • [...]
  • T is not an array type, and the type of V is assignment compatible (§5.2) with T, and:
    • [...]
    • If T is a primitive type or String, then V is a constant expression (§15.28).

An invocation of another annotation element is not a constant expression.

You would need to handle this in the component that manages the use of the annotation. Declare the default message as some special value.

String message() default "REPLACE_ME";

then check for it while constructing the message. For example

Field field = ... // get 'age' field
Size size = field.getAnnotation(Size.class);
if (size != null) {
    String message = size.message();
    if (message.equals("REPLACE_ME")) {
        message = "Age between " + size.min() + " - " + size.max() + "."; 
    }
}
int min = size.min();
int max = size.max();
// if field is of type int
int value = field.getInt(instance);
if (value > max || value < min) {
    throw new ConstraintViolationException(message);
}

Upvotes: 3

Related Questions