#java #validation #annotations #java-annotations
#java #проверка #аннотации #java-аннотации
Вопрос:
У меня есть экземпляр аннотации Java, который имеет цель МЕТОДА: возможно ли получить объект метода, к которому он присоединен?
Я пытаюсь выполнить проверку кросс-параметров, где валидатор будет применять логику к комбинации параметров, чтобы определить, верны ли они. Однако, поскольку средство проверки может применяться к нескольким методам, я ищу способ указать, какие параметры являются какими.
Например, в приведенном ниже примере у меня есть методы, которые используют два аргумента для указания диапазона по началу и концу. Я хочу, чтобы средство проверки проверяло, что начало не больше конца. Я хочу использовать аннотации к параметрам, чтобы указать, какой параметр является начальным, а какой конечным, а затем попросить средство проверки использовать эти аннотации, чтобы определить, какие параметры использовать при проверке.
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface StartParam {}
/***************************/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface EndParam {}
/***************************/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = RangeParamsValidator.class)
@SupportedValidationTarget(ValidationTarget.PARAMETERS)
public @interface RangeParams { }
/***************************/
public class RangeParamsValidator implements ConstraintValidator<RangeParams, Object[]> {
private int indexOfStartArg;
private int indexOfEndArg;
@Override
public void initialize(
RangeParams constraintAnnotation
) {
// This is where I'm hoping to get the method that `constraintAnnotation`
// is attached to, so I can iterate over its params and see which are
// annotated with @StartParam and @EndParam so I can set indexOfStartArg
// and indexOfEndArg;
}
@Override
public boolean isValid(Object[] value, ConstraintValidatorContext context) {
Integer start = value[indexOfStartArg];
Integer end = value[indexOfEndArg];
return start <= end;
}
}
/***************************/
// Example use:
class Whatever {
@RangeParams
void doSomething(
String ignoreThisArg,
@StartParam int start,
@FinishParam int finish,
Object ignoreThisToo
) {
// ...
}
}
Ответ №1:
Я не смог понять это, используя имена параметров, хотя может быть способ. Но вот решение с положением параметров.
Сначала вам нужно создать свойства в ограничении, чтобы можно было передавать положение полей.
@Constraint(validatedBy = RangeParamsValidator.class)
@Target( {ElementType.CONSTRUCTOR, ElementType.METHOD} )
@Retention(RetentionPolicy.RUNTIME)
public @interface RangeParams {
String message() default "Constraint violated";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
int indexOfStartArg();
int indexOfEndArg();
}
message
, groups
и payload
должны соответствовать стандарту (подробнее в документации). Важной частью являются 2 дополнительных параметра для предоставления индекса. Если вы установите значение по умолчанию, параметры будут необязательными.
Затем при инициализации средства проверки вы получаете значения.
public class RangeParamsValidator implements ConstraintValidator<RangeParams, Object[]> {
private int indexOfStartArg;
private int indexOfEndArg;
@Override
public void initialize(RangeParams constraintAnnotation) {
indexOfStartArg = constraintAnnotation.indexOfStartArg();
indexOfEndArg = constraintAnnotation.indexOfEndArg();
}
...
И вы можете использовать значения по своему усмотрению.
Затем, чтобы указать значения, вы делаете это в аннотации следующим образом:
@RangeParams(indexOfStartArg = 1, indexOfEndArg = 2)
void doSomething(
String ignoreThisArg,
int start,
int finish,
Object ignoreThisToo
) {
// ...
}
Я думаю, что это можно сделать с именами параметров, поскольку в isValid()
контексте есть список имен параметров. Но мне удалось получить доступ к значениям только через реализацию интерфейса, а не через сам интерфейс, поэтому мне нужно было бы добавить контекст к реализации, которая не кажется чистой.