2010-07-19 14 views
19

Chicos ¿hay alguna manera de pasar una Anotación como un parámetro directo (más bien haciendo toda la reflexión por encima)? Por ejemplo, en el siguiente código, tengo un número de anotación que contiene un valor int, quiero pasar como un parámetro al método addImpl, ¿cómo puedo hacer eso (que no sea por reflexión)?¿Hay alguna forma de pasar una anotación Java como parámetro?

Fragmento de código:

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

¿Por qué es el número define como una anotación en lugar de una clase regular? El objetivo de las anotaciones es adjuntar los metadatos estáticamente en tiempo de compilación. Si ese no es su objetivo, ¿cuál es la razón por la que se define como una anotación? – jthg

+0

El número es solo una muestra de lo que surgió, estoy haciendo esto para hacer que un protocolo sea más fácil;) –

Respuesta

17

Sí, se puede pasar alrededor de las anotaciones de este tipo (como si fueran las interfaces normales).

Lo único que no puede hacer es crear instancias de esa interfaz en tiempo de ejecución. Solo puede tomar anotaciones existentes y pasarlas.

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

Okaaay - ¿hay algunos casos de uso del mundo real para esto? –

+1

@Andreas_D: seguro, donde quiera que reaccione en alguna anotación puede refactorizar fácilmente el código para hacer su trabajo en varios métodos (o incluso clases) y poder pasar la anotación puede ser muy útil. –

+2

Otro caso de uso podría ser probar un validador JSR 303. Tiene el método initialize() que toma la anotación. –

3

A lo mejor de mi conocimiento, no hay tal cosa como una "anotación literal" como se desea utilizarlo en su aplicación add.

Creo que lo más parecido a esto sería declarar el método para tomar un parámetro del tipo java.lang.annotation.Annotation - pero aún tendría que obtener esas instancias a través de la reflexión de los objetos de clase/método.

8

Puede hacerlo como:

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

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

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

Puesto Número es básicamente una interfaz, se debe crear una instancia de una clase anónima que implementa esa interfaz, y pasar a que el método.

Aunque no puedo entender por qué quieres hacer esto. Si necesita pasarle un valor a algo, realmente debería usar una clase.

+0

El número es solo una muestra: 3 –

+0

Tenga en cuenta que esta implementación es lo suficientemente buena para este caso de uso específico, pero podría no ser suficiente para otros usos como calificadores 'CDI' donde' igual' y 'código hash' deberían implementarse según Documentación 'Annotation'. –

1

El número también es una buena interfaz anterior, puede implementar una clase concreta.

Chicos, esto es útil. Mientras que un módulo trata principalmente con anotaciones que se arreglan en tiempo de compilación, a veces necesitamos alimentarlo con otra información obtenida en tiempo de ejecución de otras fuentes (como xml, gush!) Podemos sobre-diseñar el asunto, o simplemente podemos crear un tiempo de ejecución objeto del tipo de anotación

+1

La implementación de interfaces de anotación en sus propias clases es al menos un olor a código. –

+0

el olor a maestría es bueno. – irreputable

1

Si necesita pasar una anotación en la prueba, puede hacer una prueba de ello. Por ejemplo prueba de JSR 303 validador podría tener este aspecto:

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