【问题标题】:Accessing the method that an annotation instance is attached to for cross-parameter validation访问注释实例附加到的方法以进行跨参数验证
【发布时间】:2021-01-18 06:09:41
【问题描述】:

我有一个 Java 注释的实例,它的目标是 METHOD:是否可以获得它所附加的 Method 对象?

我正在尝试进行跨参数验证,其中验证器将对参数组合应用逻辑以确定它们是否正确。但是,由于验证器可以应用于多种方法,所以我正在寻找一种方法来标记哪些参数是哪些。

例如,在下面的示例中,我的方法使用两个参数通过开始和结束指定范围。我想要一个验证器来检查开始不大于结束。我想在参数上使用注释来指示哪个参数是开始,哪个是结束,然后让验证器使用这些注释来确定在验证中使用哪些参数。

@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
    ) {
        // ...
    }
}

【问题讨论】:

    标签: java validation annotations java-annotations


    【解决方案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();
    }
    

    messagegroupspayload 符合标准(documentation 中有更多信息)。重要的部分是提供索引的 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() 中,上下文具有参数名称列表。但是我只设法通过接口的实现而不是通过接口本身来访问值,所以我需要将上下文转换为感觉不干净的实现。

    【讨论】:

      猜你喜欢
      • 2012-04-12
      • 1970-01-01
      • 2010-12-02
      • 1970-01-01
      • 1970-01-01
      • 2015-09-28
      • 1970-01-01
      • 2012-03-06
      • 1970-01-01
      相关资源
      最近更新 更多