【问题标题】:Is there a way to pass a Java annotation as a parameter?有没有办法将 Java 注释作为参数传递?
【发布时间】:2010-07-19 15:00:50
【问题描述】:

伙计们有没有办法将注释作为直接参数传递(而不是通过执行所有反射开销)?例如在下面的代码中,我有一个包含 int 值的注释 Number,我想作为参数传递给 addImpl 方法,我该怎么做(除了反射)?

代码片段:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
public @interface Number {
    int value();
}

public void add(int x2) {
    addImpl(@Number(value = 10) lol, x2);
}

public void addImpl(Number a, int b) {
    System.out.println(a.value() + b);
}

public static void main(String[] args) {
    new TestClass().add(3);
}

【问题讨论】:

  • 为什么 Number 被定义为注解而不是常规类?注释的目的是在编译时静态附加元数据。如果那不是您的目标,那么将其定义为注释的原因是什么?
  • 数字只是我想出的一个示例,我这样做是为了使协议实现更容易;)

标签: java annotations


【解决方案1】:

是的,您可以像这样传递注释(就像它们是普通接口一样)。

您唯一不能做的就是在运行时创建该接口的实例。您只能获取现有注释并传递它们。

import java.lang.annotation.*;

public class Example {

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public static @interface Number {
        int value();
    }

    @Number(value = 42)
    public int adder(final int b) throws SecurityException, NoSuchMethodException {
        Number number = getClass().getMethod("adder", int.class).getAnnotation(Number.class);
        return addImpl(number, b);
    }

    public int addImpl(final Number a, final int b) {
        return a.value() + b;
    }

    public static void main(final String[] args) throws SecurityException, NoSuchMethodException {
        System.out.println(new Example().adder(0));
    }
}

【讨论】:

  • Okaaay - 有一些实际的用例吗?
  • @Andreas_D:当然,无论您对某个注释做出反应,您都可以轻松地重构代码以在多个方法(甚至类)中完成其工作,并且能够传递注释可能非常有用。
  • 另一个用例可能是测试 JSR 303 验证器。它有方法 initialize() 需要注释。
【解决方案2】:

你可以这样做:

public void add(int x2) {
    addImpl(new Number() {

        @Override
        public int value() {
            return 10;
        }

        @Override
        public Class<? extends Annotation> annotationType() {
            return Number.class;
        }
    }, x2);
}

由于 Number 基本上是一个接口,因此您必须创建一个实现该接口的匿名类的实例,并将其传递给方法。

虽然你为什么要这样做,但我无法理解。如果你需要传递一个值给某个东西,你真的应该使用一个类。

【讨论】:

  • 数字只是一个示例:3
  • 请注意,这个实现对于这个特定的用例来说已经足够好了,但是对于像CDI 限定符这样的其他用途可能还不够,其中equalshashcode 应该根据@987654325 来实现@ 文档。
【解决方案3】:

据我所知,没有您想在 add 实现中使用“注释文字”之类的东西。

我认为与此最接近的方法是声明方法以获取 java.lang.annotation.Annotation 类型的参数 - 但是您仍然需要通过类/方法对象的反射来获取这些实例。

【讨论】:

    【解决方案4】:

    Number也是一个不错的老接口,可以实现一个具体的类。

    伙计们,这很有用。虽然一个模块主要处理在编译时固定的注释,但有时我们需要向它提供在运行时从其他来源获得的其他信息(如 xml,gush!)我们可以过度架构这个东西,或者我们可以简单地创建一个运行时注释类型的对象。

    【讨论】:

    • 在自己的类中实现注解接口至少是代码异味。
    【解决方案5】:

    如果你需要在测试中传递注解,你可以模拟它。 例如,JSR 303 验证器的测试可能如下所示:

    public void test() {
        final TextLengthValidator validator = new TextLengthValidator();
        validator.initialize(mock(TextLength.class));
        final boolean valid = validator.isValid("some text", mock(ConstraintValidatorContext.class));
        assertThat(valid, is(true));
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-10
      • 2021-12-20
      • 2020-04-29
      • 1970-01-01
      • 1970-01-01
      • 2020-01-18
      • 2015-07-08
      • 1970-01-01
      相关资源
      最近更新 更多