2010-12-15 19 views
46

Quiero saber las anotaciones de una variable miembro de una clase, uso BeanInfo beanInfo = Introspector.getBeanInfo(User.class) para introspectar una clase, y uso BeanInfo.getPropertyDescriptors(), para encontrar una propiedad específica, y uso la clase type = propertyDescriptor.getPropertyType() para obtener la clase de la propiedad.¿Cómo obtener anotaciones de una variable miembro?

¿Pero no sé cómo obtener las anotaciones agregadas a la variable miembro?

Intenté type.getAnnotations() y type.getDeclaredAnnotations(), pero ambas devuelven las anotaciones de la Clase, no es lo que quiero. Por ejemplo:

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 
{ 
    ... 
} 

Quiero conseguir la anotación de la dirección: anotaciones @Column, no la clase de la dirección (@Entity, @Table, @Cache). ¿Cómo lograrlo? Gracias.

+1

@Bozho Podría ser útil si copia los objetos de base de datos, como parece ser el caso aquí. La copia no puede tener la misma ID, si se supone que se convierta en una entidad DB diferente. Un algoritmo de copia genérico podría excluir cualquier cosa con Annotation '@Id'. – Hok

Respuesta

61

Esta es una variación del código mkoryak excepto que no se basa en Class.newInstance (y compila).

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

Consulte también: http://docs.oracle.com/javase/tutorial/reflect/class/classMembers.html

8

usted tiene que utilizar la reflexión para obtener todos los campos miembros de User clase, iterar a través de ellos y encontrar sus anotaciones

algo como esto:

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

Gracias, pero mi clazz no tiene ningún constructor público sin argumentos ... (Lo siento, no mencioné eso). Entonces, clazz.newInstance() no funcionará. – smallufo

+1

Simplemente omita la línea clazz.newInstance(), no estoy seguro de por qué mkoryak incluyó eso, no es usado por nada. – qualidafial

+1

Vaya, no pegué el código en correcto. de hecho se usa – mkoryak

5

usted puede conseguir anotaciones en el método de obtención:

propertyDescriptor.getReadMethod().getDeclaredAnnotations(); 

conseguir las anotaciones de un campo privado parece una mala idea ... ¿y si la propiedad no está aún respaldado por un campo, o es respaldado por un campo con un nombre diferente? Incluso ignorando esos casos, estás rompiendo la abstracción mirando cosas privadas.

+0

Gracias, pero ¿qué pasa si no puedo modificar el código de la clase? ¿Qué pasa si tengo que obtener las anotaciones del campo privado? – smallufo

+0

@smallufo Tengo mucha curiosidad por saber por qué necesitarías esto. Si las anotaciones estaban en campos privados, entonces no se suponía que debías saber sobre ellas. –

+3

Hola, porque nuestros códigos siguen muchos de los tutoriales de JPA. La mayoría de los tutoriales/libros de JPA agregan directamente anotaciones en los campos privados. Y lo que quiero excavar son estas anotaciones 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(){ 

    } 
} 

y una clase de prueba:

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

} 

creo que sirve ...

;-)

71

Todo el mundo describe tema con conseguir un nnotaciones, pero el problema está en la definición de tu anotación. Usted debe agregar a la definición de la anotación de un @Retention(RetentionPolicy.RUNTIME):

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

O usted podría intentar esto

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

Esperamos que esto ayude.

+6

No veo 'getAnnotations()' en ninguna parte de la API para 'PropertyDescriptor' en Java 6 o 7. ¿Me falta algo? http://docs.oracle.com/javase/7/docs/api/java/beans/PropertyDescriptor.html –

+0

getReadMethod() –

12

Si necesita saber si una anotación específica está presente. Puede hacerlo:

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

     } 

Y así sucesivamente para las otras anotaciones ...

espero ayudar a alguien.

0

Mi manera

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

} 
Cuestiones relacionadas