Est-il possible de lire la valeur d'une annotation en java?

99

c'est mon code:

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

est-il possible de lire la valeur de mon annotation @Column ( columnName = "xyz123") dans une autre classe?

Les abeilles
la source

Réponses:

122

Oui, si votre annotation Column a la rétention d'exécution

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

tu peux faire quelque chose comme ça

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

MISE À JOUR: Pour obtenir des champs privés, utilisez

Myclass.class.getDeclaredFields()
Céphalopode
la source
1
j'aime votre solution. Comment pouvons-nous le rendre plus générique comme au lieu de MyClass je veux utiliser T comme pour (Field f: T.class.getFields ()) {Column column = f.getAnnotation (Column.class); if (colonne! = null) System.out.println (column.columnName ()); }
ATHER
1
Exactement! J'ai eu du mal à comprendre cela aussi. Que faire si je veux avoir un processeur d'annotations qui n'a pas besoin d'être explicitement fourni avec un nom de classe? Peut-il être fait pour le prendre dans le contexte; 'ce'??
5122014009
Je ne suis pas sûr de comprendre ce dont vous avez besoin tous les deux. Veuillez poser cela comme une nouvelle question avec un exemple complet. Vous pouvez le lier ici si vous le souhaitez.
Cephalopod
3
Utilisez Myclass.class.getDeclaredFields()pour obtenir des champs privés
q0re
Cela a fonctionné pour moi. Merci. Je cherchais des champs privés de superclasse donc j'ai utilisé clsName.getSuperclass (). GetDeclaredFields ()
Shashank
88

Bien sûr que ça l'est. Voici un exemple d'annotation:

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

    String testText();
}

Et un exemple de méthode annotée:

class TestClass {

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

Et un exemple de méthode dans une autre classe qui imprime la valeur du 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());
    }
}

Pas très différent pour les annotations de champ comme la vôtre.

Cheerz!

Lachezar Balev
la source
21

Je ne l'ai jamais fait, mais il semble que Reflection le fournisse. Fieldest un AnnotatedElementet ainsi de suite getAnnotation. Cette page a un exemple (copié ci-dessous); assez simple si vous connaissez la classe de l'annotation et si la politique d'annotation conserve l'annotation au moment de l'exécution. Naturellement, si la politique de rétention ne conserve pas l'annotation au moment de l'exécution, vous ne pourrez pas l'interroger au moment de l'exécution.

Une réponse qui a depuis été supprimée (?) A fourni un lien utile vers un didacticiel d'annotations que vous pourriez trouver utile; J'ai copié le lien ici pour que les gens puissent l'utiliser.

Exemple de cette page :

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);
  }
}
TJ Crowder
la source
6

Élaborant à la réponse de @Cephalopod, si vous vouliez tous les noms de colonnes dans une liste, vous pouvez utiliser cet 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());
Simon Baars
la source
Objects.nonNull pour embrasser pleinement Java 8 :) .filter (f -> nonNull (f.getAnnotation (Column.class)))
déshumaniseur
4

Bien que toutes les réponses données jusqu'à présent soient parfaitement valables, il convient également de garder à l'esprit la bibliothèque de réflexions google pour une approche plus générique et plus simple de l'analyse des annotations, par exemple

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

 Set<Field> ids = reflections.getFieldsAnnotatedWith(javax.persistence.Id.class);
Fritz Duchardt
la source
3

Vous pouvez également utiliser des types génériques, dans mon cas, en tenant compte de tout ce qui a été dit avant de pouvoir faire quelque chose comme:

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

    }

}

Rappelez-vous que cela ne sera pas équivalent à 100% à SomeClass.class.get (...) ();

Mais peut faire l'affaire ...

SigmaSoldat
la source
3

Dans le cas courant, vous avez un accès privé pour les champs, vous NE POUVEZ donc PAS utiliser getFields en réflexion. Au lieu de cela, vous devez utiliser getDeclaredFields

Donc, tout d'abord, vous devez savoir si votre annotation Column a la rétention d'exécution:

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

Après cela, vous pouvez faire quelque chose comme ceci:

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

De toute évidence, vous aimeriez faire quelque chose avec le champ - définir une nouvelle valeur à l'aide de la valeur d'annotation:

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

Ainsi, le code complet peut ressembler à ceci:

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()
                )
        );
}
Oleg Poltoratskii
la source
2

Pour les quelques personnes qui demandent une méthode générique, cela devrait vous aider (5 ans plus tard: p).

Pour mon exemple ci-dessous, je tire la valeur de l'URL RequestMapping des méthodes qui ont l'annotation RequestMapping. Pour adapter cela aux champs, changez simplement le

for (Method method: clazz.getMethods())

à

for (Field field: clazz.getFields())

Et échangez l' utilisation de RequestMapping pour l'annotation que vous souhaitez lire. Mais assurez-vous que l'annotation a @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 "";
}
MattWeiler
la source
0

l'une des façons dont je l'ai utilisé:

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;
}    
RK Punjal
la source