2010-07-19 5 views
19

Les gars est-il un moyen de passer une annotation comme un paramètre direct (plutôt que de faire tous les frais généraux de réflexion)? Par exemple dans le code suivant, j'ai un numéro d'annotation qui contient une valeur int, je veux passer en paramètre à la méthode addImpl, comment puis-je faire cela (autre que par réflexion)?Existe-t-il un moyen de transmettre une annotation Java en tant que paramètre?

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

Pourquoi Nombre défini comme une annotation plutôt qu'une classe ordinaire? Le but des annotations est d'attacher statiquement des méta-données au moment de la compilation. Si ce n'est pas votre objectif, quelle est la raison pour laquelle il est défini comme une annotation? – jthg

+0

Le numéro est juste un exemple de chose que je suis venu, je fais cela pour rendre un protocole impl plus facile;) –

Répondre

17

Oui, vous pouvez passer autour des annotations comme celle-ci (comme si elles étaient des interfaces normales). La seule chose que vous ne pouvez pas faire est de créer des instances de cette interface lors de l'exécution. Vous ne pouvez prendre que les annotations existantes et les transmettre.

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 - y a-t-il des cas d'utilisation dans le monde réel pour cela? –

+1

@Andreas_D: bien sûr, où que vous réagissiez sur une annotation, vous pouvez facilement refactoriser le code pour faire son travail dans plusieurs méthodes (ou même des classes) et être capable de faire circuler l'annotation peut être très utile. –

+2

Un autre cas d'utilisation pourrait être le test d'un validateur JSR 303. Il a une méthode initialize() qui prend des annotations. –

3

Au meilleur de ma connaissance, il n'y a pas une telle chose comme une « annotation littérale » que vous voulez l'utiliser dans votre mise en œuvre add.

Je pense que la chose la plus proche de ceci serait de déclarer la méthode pour prendre un paramètre de type java.lang.annotation.Annotation - mais alors vous auriez encore besoin d'obtenir ces instances par réflexion à partir des objets de classe/méthode.

8

Vous pouvez le faire comme:

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

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

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

Depuis numéro est essentiellement une interface, vous devez créer une instance d'une classe anonyme qui implémente cette interface, et passer que la méthode.

Bien que la raison pour laquelle vous voulez faire cela est au-delà de moi. Si vous devez passer une valeur à quelque chose, vous devriez vraiment utiliser une classe.

+0

Le nombre n'est qu'un exemple: 3 –

+0

Notez que cette implémentation est assez bonne pour ce cas d'utilisation spécifique mais qu'elle ne suffira pas pour d'autres utilisations comme les qualificatifs 'CDI' où' equals' et 'hashcode' devraient être implémentés selon Documentation 'Annotation'. –

1

Le numéro est aussi une bonne vieille interface, vous pouvez implémenter une classe concrète.

Les gars, c'est utile. Tandis qu'un module traite principalement des annotations qui sont fixées au moment de la compilation, nous devons parfois lui fournir d'autres informations obtenues à l'exécution d'autres sources (comme xml, gush!). Nous pouvons sur-architecturer la chose, ou créer simplement un runtime objet du type annotaion.

+1

L'implémentation d'interfaces d'annotation dans vos propres classes est au moins une odeur de code. –

+0

l'odeur de la maîtrise est bonne. – irreputable

1

Si vous devez passer une annotation en test, vous pouvez en faire une simulation. Par exemple test de la JSR 303 validateur pourrait ressembler à ceci:

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