Search code examples
javareflectionannotationshibernate-validator

How to access a field which is described in annotation property


Is it possible to access a field value, where field name is described in annotation which annotate another field in class.

For example:

@Entity
public class User {

    @NotBlank
    private String password;

    @Match(field = "password")
    private String passwordConfirmation;
}

Annotation:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = FieldMatchValidator.class)
@Documented
public @interface Match {

    String message() default "{}";

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

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

    String field();
}

Now, is it possible to access field password from class User in ConstraintValidator implementaion class?


Edit:

I wrote something like this:

public class MatchValidator implements ConstraintValidator<Match, Object> {

private String mainField;
private String secondField;
private Class clazz;

@Override
public void initialize(final Match match) {
    clazz = User.class;

    final Field[] fields = clazz.getDeclaredFields();
    for (Field field : fields) {
        if (field.isAnnotationPresent(Match.class)) {
            mainField = field.getName();
        }
    }

    secondField = match.field();
}

@Override
public boolean isValid(final Object value, final ConstraintValidatorContext constraintValidatorContext) {
    try {
        Object o; //Now how to get the User entity instance?

        final Object firstObj = BeanUtils.getProperty(o, mainField);
        final Object secondObj = BeanUtils.getProperty(o, secondField);

        return firstObj == null && secondObj == null || firstObj != null && firstObj.equals(secondObj);
    } catch (final Exception ignore) {
        ignore.printStackTrace();
    }
    return true;
}
}

Now the question is how can I get the User object instance and compare fields values?


Solution

  • You either need to write a class level constraint in which you get the full User instance passed into the isValid call or you can use something like @ScriptAssert.

    At the moment it is not possible to access the root bean instance as part of a "normal" field validation. There is a BVAL issue - BVAL-237 - which discusses to add this functionality, but so far it is not yet part of the Bean Validation specification.

    Note, there are good reasons why the root bean is not accessible atm. Constraints which rely on the root bean being accessible will fail for the validateValue case.