Как получить доступ к полю, которое описано в свойстве аннотации

Можно ли получить доступ к значению поля, где имя поля описано в аннотации, которое аннотирует другое поле в классе.

Например:

@Entity
public class User {

    @NotBlank
    private String password;

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

Аннотация:

@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();
}

Теперь, возможно ли получить доступ к паролю пароля из класса User в классе реализации ConstraintValidator?


Edit:

Я написал что-то вроде этого:

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;
}
}

Теперь вопрос в том, как я могу получить экземпляр объекта User и сравнить значения полей?

Ответ 1

Вам нужно либо написать ограничение уровня класса, в котором вы получаете полный экземпляр пользователя, переданный в вызов isValid, или вы можете использовать что-то вроде @ScriptAssert.

В настоящий момент невозможно получить доступ к корневому экземпляру bean как к частичной проверки правильности поля. Существует проблема BVAL - BVAL-237 - в которой обсуждается возможность добавления этой функции, но пока она еще не является частью bean Validation спецификация.

Заметьте, есть веские причины, по которым root bean недоступен atm. Ограничения, зависящие от доступного корня bean, будут недействительными для case validateValue.

Ответ 2

@Hardy Thenks для подсказки. Наконец написал код, который соответствует (более или менее) ожидаемому результату.

Я вложу его сюда, возможно, поможет кому-то решить его проблему.

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Match {

    String field();

    String message() default "";
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MatchValidator.class)
@Documented
public @interface EnableMatchConstraint {

    String message() default "Fields must match!";

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

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

public class MatchValidator implements  ConstraintValidator<EnableMatchConstraint, Object> {

    @Override
    public void initialize(final EnableMatchConstraint constraint) {}

    @Override
    public boolean isValid(final Object o, final ConstraintValidatorContext context) {
        boolean result = true;
        try {
            String mainField, secondField, message;
            Object firstObj, secondObj;

            final Class<?> clazz = o.getClass();
            final Field[] fields = clazz.getDeclaredFields();

            for (Field field : fields) {
                if (field.isAnnotationPresent(Match.class)) {
                    mainField = field.getName();
                    secondField = field.getAnnotation(Match.class).field();
                    message = field.getAnnotation(Match.class).message();

                    if (message == null || "".equals(message))
                        message = "Fields " + mainField + " and " + secondField + " must match!";

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

                    result = firstObj == null && secondObj == null || firstObj != null && firstObj.equals(secondObj);
                    if (!result) {
                        context.disableDefaultConstraintViolation();
                        context.buildConstraintViolationWithTemplate(message).addPropertyNode(mainField).addConstraintViolation();
                        break;
                    }
                }
            }
        } catch (final Exception e) {
            // ignore
            //e.printStackTrace();
        }
        return result;
    }
}

И как его использовать...? Вот так:

@Entity
@EnableMatchConstraint
public class User {

    @NotBlank
    private String password;

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