È possibile leggere il valore di un'annotazione in java?


99

questo è il mio codice:

@Column(columnName="firstname")


private String firstName;

 @Column(columnName="lastname")
 private String lastName;

 public String getFirstName() {
  return firstName;
 }

 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }

 public String getLastName() {
  return lastName;
 }

 public void setLastName(String lastName) {
  this.lastName = lastName;
 }

è possibile leggere il valore della mia annotazione @Column ( columnName = "xyz123") in un'altra classe?

Risposte:


122

Sì, se l'annotazione della colonna ha la conservazione del runtime

@Retention(RetentionPolicy.RUNTIME)
@interface Column {
    ....
}

puoi fare qualcosa di simile

for (Field f: MyClass.class.getFields()) {
   Column column = f.getAnnotation(Column.class);
   if (column != null)
       System.out.println(column.columnName());
}

AGGIORNAMENTO: Per ottenere l'uso di campi privati

Myclass.class.getDeclaredFields()

1
mi piace la tua soluzione. Come possiamo renderlo più generico come invece di MyClass voglio usare T come per (Field f: T.class.getFields ()) {Column column = f.getAnnotation (Column.class); if (colonna! = null) System.out.println (column.columnName ()); }
ATHER

1
Esattamente! Ho lottato anche per capirlo. Cosa succede se voglio avere un processore di annotazioni a cui non è necessario fornire esplicitamente un nome di classe? Può essere fatto per riprenderlo dal contesto; 'Questo'??
5122014009

Non sono sicuro di aver capito di cosa avete bisogno. Ponetela come nuova domanda con un esempio completo. Puoi collegarlo qui se lo desideri.
Cefalopode

3
Utilizzare Myclass.class.getDeclaredFields()per ottenere campi privati
q0re

Ha funzionato per me. Grazie. Stavo cercando campi privati ​​della superclasse, quindi ho usato clsName.getSuperclass (). GetDeclaredFields ()
Shashank

88

Ovviamente è. Ecco un'annotazione di esempio:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {

    String testText();
}

E un metodo annotato di esempio:

class TestClass {

    @TestAnnotation(testText="zyx")
    public void doSomething() {}
}

E un metodo di esempio in un'altra classe che stampa il valore di testText:

Method[] methods = TestClass.class.getMethods();
for (Method m : methods) {
    if (m.isAnnotationPresent(TestAnnotation.class)) {
        TestAnnotation ta = m.getAnnotation(TestAnnotation.class);
        System.out.println(ta.testText());
    }
}

Non molto diverso per le annotazioni di campo come la tua.

Cheerz!


21

Non l'ho mai fatto, ma sembra che Reflection lo fornisca. Fieldè un AnnotatedElemente così è stato getAnnotation. Questa pagina ha un esempio (copiato sotto); abbastanza semplice se si conosce la classe dell'annotazione e se la politica di annotazione mantiene l'annotazione in fase di esecuzione. Naturalmente se il criterio di conservazione non mantiene l'annotazione in fase di esecuzione, non sarà possibile interrogarla in fase di esecuzione.

Una risposta che è stata cancellata (?) Ha fornito un collegamento utile a un tutorial sulle annotazioni che potresti trovare utile; Ho copiato il collegamento qui in modo che le persone possano usarlo.

Esempio da questa pagina :

import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno {
  String str();

  int val();
}

class Meta {
  @MyAnno(str = "Two Parameters", val = 19)
  public static void myMeth(String str, int i) {
    Meta ob = new Meta();

    try {
      Class c = ob.getClass();

      Method m = c.getMethod("myMeth", String.class, int.class);

      MyAnno anno = m.getAnnotation(MyAnno.class);

      System.out.println(anno.str() + " " + anno.val());
    } catch (NoSuchMethodException exc) {
      System.out.println("Method Not Found.");
    }
  }

  public static void main(String args[]) {
    myMeth("test", 10);
  }
}

6

Elaborando la risposta di @Cephalopod, se volessi tutti i nomi di colonna in un elenco potresti usare questo oneliner:

List<String> columns = 
        Arrays.asList(MyClass.class.getFields())
              .stream()
              .filter(f -> f.getAnnotation(Column.class)!=null)
              .map(f -> f.getAnnotation(Column.class).columnName())
              .collect(Collectors.toList());

Objects.nonNull di abbracciare pienamente Java 8 :) .filter (F -> non nulli (f.getAnnotation (Column.class)))
Dehumanizer

4

Sebbene tutte le risposte fornite finora siano perfettamente valide, si dovrebbe anche tenere a mente la libreria di riflessioni di Google per un approccio più generico e facile alla scansione delle annotazioni, ad es.

 Reflections reflections = new Reflections("my.project.prefix");

 Set<Field> ids = reflections.getFieldsAnnotatedWith(javax.persistence.Id.class);

3

Puoi anche usare tipi generici, nel mio caso, tenendo conto di tutto ciò che è stato detto prima di poter fare qualcosa come:

public class SomeTypeManager<T> {

    public SomeTypeManager(T someGeneric) {

        //That's how you can achieve all previously said, with generic types.
        Annotation[] an = someGeneric.getClass().getAnnotations();

    }

}

Ricorda che questo non sarà equivalente al 100% a SomeClass.class.get (...) ();

Ma può fare il trucco ...


3

Nel caso comune hai accesso privato ai campi, quindi NON PUOI usare getFields in reflection. Invece di questo dovresti usare getDeclaredFields

Quindi, in primo luogo, dovresti essere consapevole se l'annotazione della colonna ha la conservazione del runtime:

@Retention(RetentionPolicy.RUNTIME)
@interface Column {
}

Dopodiché puoi fare qualcosa del genere:

for (Field f: MyClass.class.getDeclaredFields()) {
   Column column = f.getAnnotation(Column.class);
       // ...
}

Ovviamente, vorresti fare qualcosa con il campo: imposta un nuovo valore usando il valore di annotazione:

Column annotation = f.getAnnotation(Column.class);
if (annotation != null) {
    new PropertyDescriptor(f.getName(), Column.class).getWriteMethod().invoke(
        object,
        myCoolProcessing(
            annotation.value()
        )
    );
}

Quindi, il codice completo può essere simile a questo:

for (Field f : MyClass.class.getDeclaredFields()) {
    Column annotation = f.getAnnotation(Column.class);
    if (annotation != null)
        new PropertyDescriptor(f.getName(), Column.class).getWriteMethod().invoke(
                object,
                myCoolProcessing(
                        annotation.value()
                )
        );
}

2

Per le poche persone che chiedono un metodo generico, questo dovrebbe aiutarti (5 anni dopo: p).

Per il mio esempio di seguito, sto estraendo il valore dell'URL RequestMapping dai metodi che hanno l'annotazione RequestMapping. Per adattarlo ai campi, basta modificare il file

for (Method method: clazz.getMethods())

per

for (Field field: clazz.getFields())

E scambia l'utilizzo di RequestMapping con qualsiasi annotazione che stai cercando di leggere. Ma assicurati che l'annotazione abbia @Retention (RetentionPolicy.RUNTIME) .

public static String getRequestMappingUrl(final Class<?> clazz, final String methodName)
{
    // Only continue if the method name is not empty.
    if ((methodName != null) && (methodName.trim().length() > 0))
    {
        RequestMapping tmpRequestMapping;
        String[] tmpValues;

        // Loop over all methods in the class.
        for (Method method: clazz.getMethods())
        {
            // If the current method name matches the expected method name, then keep going.
            if (methodName.equalsIgnoreCase(method.getName()))
            {
                // Try to extract the RequestMapping annotation from the current method.
                tmpRequestMapping = method.getAnnotation(RequestMapping.class);

                // Only continue if the current method has the RequestMapping annotation.
                if (tmpRequestMapping != null)
                {
                    // Extract the values from the RequestMapping annotation.
                    tmpValues = tmpRequestMapping.value();

                    // Only continue if there are values.
                    if ((tmpValues != null) && (tmpValues.length > 0))
                    {
                        // Return the 1st value.
                        return tmpValues[0];
                    }
                }
            }
        }
    }

    // Since no value was returned, log it and return an empty string.
    logger.error("Failed to find RequestMapping annotation value for method: " + methodName);

    return "";
}

0

uno dei modi in cui l'ho usato:

protected List<Field> getFieldsWithJsonView(Class sourceClass, Class jsonViewName){
    List<Field> fields = new ArrayList<>();
    for (Field field : sourceClass.getDeclaredFields()) {
        JsonView jsonViewAnnotation = field.getDeclaredAnnotation(JsonView.class);
        if(jsonViewAnnotation!=null){
            boolean jsonViewPresent = false;
            Class[] viewNames = jsonViewAnnotation.value();
            if(jsonViewName!=null && Arrays.asList(viewNames).contains(jsonViewName) ){
                fields.add(field);
            }
        }
    }
    return fields;
}    
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.