2010-12-15 89 views
46

Je veux connaître les annotations d'une variable membre d'une classe, j'utilise BeanInfo beanInfo = Introspector.getBeanInfo(User.class) pour introspecter une classe et utiliser BeanInfo.getPropertyDescriptors() pour trouver une propriété spécifique, et utiliser la classe type = propertyDescriptor.getPropertyType() pour obtenir la classe de la propriété.Comment obtenir des annotations d'une variable membre?

Mais je ne sais pas comment ajouter les annotations à la variable membre?

J'ai essayé type.getAnnotations() et type.getDeclaredAnnotations(), mais les deux renvoient les annotations de la classe, pas ce que je veux. Par exemple:

class User 
{ 
    @Id 
    private Long id; 

    @Column(name="ADDRESS_ID") 
    private Address address; 

    // getters , setters 
} 

@Entity 
@Table(name = "Address") 
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) 
class Address 
{ 
    ... 
} 

Je veux obtenir l'annotation de l'adresse: les annotations de @Column, pas de classe Adresse (@Entity, @Table, @Cache). Comment l'atteindre? Merci.

+1

@Bozho Il pourrait être utile si vous copiez des objets DB, comme cela semble être le cas ici. La copie ne peut pas avoir le même ID, si elle est supposée devenir une entité DB différente. Un algorithme de copie générique pourrait exclure n'importe quoi avec Annotation '@Id'. – Hok

Répondre

61

Ceci est une variation du code mkoryak sauf qu'il ne dépend pas de Class.newInstance (et il compile).

for(Field field : cls.getDeclaredFields()){ 
    Class type = field.getType(); 
    String name = field.getName(); 
    Annotation[] annotations = field.getDeclaredAnnotations(); 
} 

Voir aussi: http://docs.oracle.com/javase/tutorial/reflect/class/classMembers.html

8

Vous devez utiliser la réflexion pour obtenir tous les champs membres de User classe, itérer à travers eux et trouver leurs annotations

quelque chose comme ceci:

public void getAnnotations(Class clazz){ 
    for(Field field : clazz.getDeclaredFields()){ 
     Class type = field.getType(); 
     String name = field.getName(); 
     field.getDeclaredAnnotations(); //do something to these 
    } 
} 
+1

Merci, mais mon clazz n'a aucun constructeur public no-arg ... (Désolé ne mentionne pas cela). Donc, clazz.newInstance() ne fonctionnera pas. – smallufo

+1

Juste omettre la ligne clazz.newInstance(), je ne sais pas pourquoi mkoryak l'a inclus - il n'est pas utilisé par quoi que ce soit. – qualidafial

+1

oups, je n'ai pas coller le code correct. il est effectivement utilisé – mkoryak

5

Vous pouvez obtenir des annotations sur la méthode de lecture:

propertyDescriptor.getReadMethod().getDeclaredAnnotations(); 

Obtenir les annotations d'un champ privé semble être une mauvaise idée ... si la propriété est même pas soutenu par un champ, ou est soutenu par un champ avec un nom différent? Même en ignorant ces cas, vous brisez l'abstraction en regardant des choses privées.

+0

Merci, mais que faire si je ne peux pas modifier le code de la classe? Que faire si je dois obtenir les annotations du champ privé? – smallufo

+0

@smallufo Je suis vraiment curieux de savoir pourquoi vous en auriez besoin. Si les annotations étaient sur des champs privés, vous n'étiez pas censé les connaître. –

+3

Salut, parce que nos codes suivent beaucoup de tutoriels de JPA. La plupart des tutoriels/livres JPA ajoutent directement des annotations dans les champs privés. Et ce que je veux creuser, c'est ces annotations JPA. – smallufo

2
package be.fery.annotation; 

import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.Id; 
import javax.persistence.PrePersist; 

@Entity 
public class User { 
    @Id 
    private Long id; 

    @Column(name = "ADDRESS_ID") 
    private Address address; 

    @PrePersist 
    public void doStuff(){ 

    } 
} 

Et une classe d'essai:

package be.fery.annotation; 

import java.lang.annotation.Annotation; 
import java.lang.reflect.Field; 
import java.lang.reflect.Method; 

public class AnnotationIntrospector { 

    public AnnotationIntrospector() { 
     super(); 
    } 

    public Annotation[] findClassAnnotation(Class<?> clazz) { 
     return clazz.getAnnotations(); 
    } 

    public Annotation[] findMethodAnnotation(Class<?> clazz, String methodName) { 

     Annotation[] annotations = null; 
     try { 
      Class<?>[] params = null; 
      Method method = clazz.getDeclaredMethod(methodName, params); 
      if (method != null) { 
       annotations = method.getAnnotations(); 
      } 
     } catch (SecurityException e) { 
      e.printStackTrace(); 
     } catch (NoSuchMethodException e) { 
      e.printStackTrace(); 
     } 
     return annotations; 
    } 

    public Annotation[] findFieldAnnotation(Class<?> clazz, String fieldName) { 
     Annotation[] annotations = null; 
     try { 
      Field field = clazz.getDeclaredField(fieldName); 
      if (field != null) { 
       annotations = field.getAnnotations(); 
      } 
     } catch (SecurityException e) { 
      e.printStackTrace(); 
     } catch (NoSuchFieldException e) { 
      e.printStackTrace(); 
     } 
     return annotations; 
    } 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     AnnotationIntrospector ai = new AnnotationIntrospector(); 
     Annotation[] annotations; 
     Class<User> userClass = User.class; 
     String methodDoStuff = "doStuff"; 
     String fieldId = "id"; 
     String fieldAddress = "address"; 

     // Find class annotations 
     annotations = ai.findClassAnnotation(be.fery.annotation.User.class); 
     System.out.println("Annotation on class '" + userClass.getName() 
       + "' are:"); 
     showAnnotations(annotations); 

     // Find method annotations 
     annotations = ai.findMethodAnnotation(User.class, methodDoStuff); 
     System.out.println("Annotation on method '" + methodDoStuff + "' are:"); 
     showAnnotations(annotations); 

     // Find field annotations 
     annotations = ai.findFieldAnnotation(User.class, fieldId); 
     System.out.println("Annotation on field '" + fieldId + "' are:"); 
     showAnnotations(annotations); 

     annotations = ai.findFieldAnnotation(User.class, fieldAddress); 
     System.out.println("Annotation on field '" + fieldAddress + "' are:"); 
     showAnnotations(annotations); 

    } 

    public static void showAnnotations(Annotation[] ann) { 
     if (ann == null) 
      return; 
     for (Annotation a : ann) { 
      System.out.println(a.toString()); 
     } 
    } 

} 

Hope it helps ...

;-)

71

Tout le monde décrit question avec obtenir un nnotations, mais le problème est dans la définition de votre annotation. Vous devez ajouter à votre définition d'annotation d'une @Retention(RetentionPolicy.RUNTIME):

@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.FIELD) 
public @interface MyAnnotation{ 
    int id(); 
} 
-2

Ou vous pouvez essayer cette

try { 
    BeanInfo bi = Introspector.getBeanInfo(User.getClass()); 
    PropertyDescriptor[] properties = bi.getPropertyDescriptors(); 
    for(PropertyDescriptor property : properties) { 
     //One way 
     for(Annotation annotation : property.getAnnotations()){ 
      if(annotation instanceof Column) { 
       String string = annotation.name(); 
      } 
     } 
     //Other way 
     Annotation annotation = property.getAnnotation(Column.class); 
     String string = annotation.name(); 
    } 
}catch (IntrospectonException ie) { 
    ie.printStackTrace(); 
} 

Espérons que cela aidera.

+6

Je ne vois pas 'getAnnotations()' n'importe où dans l'API pour 'PropertyDescriptor' dans Java 6 ou 7. Ai-je raté quelque chose? http://docs.oracle.com/javase/7/docs/api/java/beans/PropertyDescriptor.html –

+0

getReadMethod() –

12

Si vous avez besoin de savoir si une annotation spécifique est présente. Vous pouvez le faire:

Field[] fieldList = obj.getClass().getDeclaredFields(); 

     boolean isAnnotationNotNull, isAnnotationSize, isAnnotationNotEmpty; 

     for (Field field : fieldList) { 

      //Return the boolean value 
      isAnnotationNotNull = field.isAnnotationPresent(NotNull.class); 
      isAnnotationSize = field.isAnnotationPresent(Size.class); 
      isAnnotationNotEmpty = field.isAnnotationPresent(NotEmpty.class); 

     } 

Et ainsi de suite pour les autres annotations ...

J'espère que quelqu'un d'aide.

0

Ma façon

import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 

import java.beans.BeanInfo; 
import java.beans.Introspector; 
import java.beans.PropertyDescriptor; 

public class ReadAnnotation { 
    private static final Logger LOGGER = LoggerFactory.getLogger(ReadAnnotation.class); 

    public static boolean hasIgnoreAnnotation(String fieldName, Class entity) throws NoSuchFieldException { 
     return entity.getDeclaredField(fieldName).isAnnotationPresent(IgnoreAnnotation.class); 
    } 

    public static boolean isSkip(PropertyDescriptor propertyDescriptor, Class entity) { 
     boolean isIgnoreField; 
     try { 
      isIgnoreField = hasIgnoreAnnotation(propertyDescriptor.getName(), entity); 
     } catch (NoSuchFieldException e) { 
      LOGGER.error("Can not check IgnoreAnnotation", e); 
      isIgnoreField = true; 
     } 
     return isIgnoreField; 
    } 

    public void testIsSkip() throws Exception { 
     Class<TestClass> entity = TestClass.class; 
     BeanInfo beanInfo = Introspector.getBeanInfo(entity); 

     for (PropertyDescriptor propertyDescriptor : beanInfo.getPropertyDescriptors()) { 
      System.out.printf("Field %s, has annotation %b", propertyDescriptor.getName(), isSkip(propertyDescriptor, entity)); 
     } 
    } 

}