2010-07-19 10 views
19

Ragazzi c'è un modo per passare un'annotazione come parametro diretto (piuttosto facendo tutto il sovraccarico di riflessione)? Per esempio nel codice seguente, ho un numero di annotazione che contiene un valore int, voglio passare come parametro al metodo addImpl, come posso farlo (oltre che per riflessione)?C'è un modo per passare un'annotazione Java come parametro?

Snippet di codice:

@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

Perché numero definito come annotazione piuttosto che una classe normale? Lo scopo delle annotazioni è di associare staticamente i metadati al momento della compilazione. Se questo non è il tuo obiettivo, qual è la ragione per cui è definito come un'annotazione? – jthg

+0

Il numero è solo un esempio di cosa sono venuto, lo sto facendo per semplificare un protocollo impl;) –

risposta

17

Sì, è possibile passare in giro per le annotazioni come questo (proprio come se fossero normali interfacce).

L'unica cosa che non si può fare è creare istanze di tale interfaccia in fase di runtime. Puoi solo prendere annotazioni esistenti e passarle in giro.

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 - ci sono alcuni casi di utilizzo del mondo reale per questo? –

+1

@Andreas_D: certo, ovunque tu risponda ad alcune annotazioni puoi facilmente refactoring il codice per fare il suo lavoro in diversi metodi (o anche classi) e essere in grado di aggirare l'annotazione può essere molto utile. –

+2

Un altro caso d'uso potrebbe essere il test di un validatore JSR 303. Ha metodo initialize() che prende annotazioni. –

3

Al meglio della mia conoscenza, non esiste una cosa come un "annotazione letterale", come si desidera utilizzare nel vostro add implementazione.

Penso che la cosa più vicina a questo sarebbe dichiarare il metodo per prendere un parametro di tipo java.lang.annotation.Annotation - ma poi avresti ancora bisogno di ottenere quelle istanze tramite riflessione dagli oggetti classe/metodo.

8

Si può fare come:

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

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

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

Dal numero è fondamentalmente un'interfaccia, è necessario creare un'istanza di una classe anonima che implementa tale interfaccia, e passare che per il metodo.

Anche se il motivo per cui vuoi farlo è oltre me. Se devi passare un valore a qualcosa, dovresti davvero usare una classe.

+0

Il numero è solo un esempio: 3 –

+0

Si noti che questa implementazione è abbastanza buona per questo specifico caso d'uso ma potrebbe non essere sufficiente per altri usi come 'CDI' qualificatori in cui' equals' e 'hashcode' dovrebbero essere implementati secondo Documentazione 'Annotation'. –

1

Il numero è anche una buona interfaccia precedente, è possibile implementare una classe concreta.

Ragazzi, questo è utile. Mentre un modulo si occupa principalmente di annotazioni che sono fissate in fase di compilazione, a volte abbiamo bisogno di alimentarle altre informazioni ottenute in fase di runtime da altre fonti (come xml, gush!) Possiamo sovra-progettare la cosa, oppure possiamo semplicemente creare un runtime oggetto del tipo di annotaion.

+1

L'implementazione delle interfacce di annotazione nelle proprie classi è almeno un odore di codice. –

+0

l'odore della maestria è buono. – irreputable

1

Se è necessario passare l'annotazione nel test, è possibile crearne uno. Per esempio prova della JSR 303 validatore potrebbe assomigliare a questo:

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