开发者

Is there a way to pass a Java annotation as a parameter?

Guys is there a way to pass a Annotation as a direct parameter (ra开发者_如何学Gother by doing all the reflection overhead)? For example in the following code, I have a annotation Number that holds a int value, I want to pass as a parameter to the addImpl method, how can I do that (other than by reflection)?

Code Snippet:

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


Yes, you can pass around annotations like this (just as if they were normal interfaces).

The only thing you can't do is to create instances of that interface at runtime. You can only take existing annotations and pass them around.

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


You can do it like:

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

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

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

Since Number is basically an interface, you have to create an instance of an anonymous class that implements that interface, and pass that to the method.

Although why you want to do this is beyond me. If you need to pass a value to something, you should really use a class.


To the best of my knowledge, there's no such thing as an "annotation literal" as you want to use it in your add implementation.

I think the closest thing to this would be to declare the method to take a parameter of type java.lang.annotation.Annotation - but then you'd still need to obtain those instances via reflection from the class/method objects.


Number is also a good old interface, you can implement a concrete class.

Guys, this is useful. While a module mostly deals with annotations which are fixed at compile time, sometimes we need to feed it other info obtained at runtime from other sources(like xml, gush!) We can over-architect the thing, or we can simply creat a runtime object of the annotaion type.


If you need to pass annotation in test, you can make mock of it. For example test of JSR 303 validator could look like this:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜