Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

get the annotation information at runtime

I wonder if there is any way I can get the annotation information of a class at runtime? Since I want to get the properties that sepcifily annotated.

Example:

class TestMain {
    @Field(
            store = Store.NO)
    private String  name;
    private String  password;
    @Field(
            store = Store.YES)
    private int     age;

    //..........getter and setter
}

The annotations come from the hibernate-search,and now what I want is get which property of the "TestMain" is annotated as a 'field'(in the example,they are [name,age]),and which is 'stored(store=store.yes)'(in the example,they are [age]) at runtime.

Any ideas?

UPDATe:

public class FieldUtil {
public static List<String> getAllFieldsByClass(Class<?> clazz) {
    Field[] fields = clazz.getDeclaredFields();
    ArrayList<String> fieldList = new ArrayList<String>();
    ArrayList<String> storedList=new ArrayList<String>();
    String tmp;
    for (int i = 0; i < fields.length; i++) {
        Field fi = fields[i];
        tmp = fi.getName();
        if (tmp.equalsIgnoreCase("serialVersionUID"))
            continue;
        if (fi.isAnnotationPresent(org.hibernate.search.annotations.Field.class)) {
            //it is a "field",add it to list.
            fieldList.add(tmp);

            //make sure if it is stored also
            Annotation[] ans = fi.getAnnotations();
            for (Annotation an : ans) {
                //here,how to get the detail annotation information
                //I print the value of an,it is something like this:
                //@org.hibernate.search.annotations.Field(termVector=NO, index=UN_TOKENIZED, store=NO, name=, [email protected](value=1.0), [email protected](impl=void, definition=), [email protected](impl=void, params=[]))

                //how to get the parameter value of this an? using the string method?split?
            }
        }

    }
    return fieldList;
}

}

like image 931
hguser Avatar asked Dec 14 '10 01:12

hguser


2 Answers

Yes, of course. Your code sample does not actually get annotation information for class, but for fields, but code is similar. You just need to get Class, Method or Field you are interested in, then call "getAnnotation(AnnotationClass.class)" on it.

The only other thing to notice is that annotation definition must use proper RetentionPolicy so that annotation information is stored in byte code. Something like:

@Target({ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation { ... }
like image 151
StaxMan Avatar answered Oct 06 '22 01:10

StaxMan


It seems you are using (Hibernate Search)! Hibernate Search has a helper class which can retrieve fields informations

FieldInfos fieldInfos = ReaderUtil.getMergedFieldInfos(indexReader);

Unfortunately FieldsInfos does not contain enough informations (typically you don't know if a field is stored or not: or perhaps I missed something). Here is my implementation to get all stored fields:

public class HBSearchHelper {

/**
 * Get all fields of a entity which are stored into Lucene
 * 
 * @param clazz
 * @param prefix
 * @return
 */
public static List<String> getStoredField(Class<?> clazz, String prefix) {
    List<Field> fields = getAllFields(clazz);
    ArrayList<String> storedList = new ArrayList<String>();
    for (Field fi : fields) {
        // @Field annotation
        if (fi.isAnnotationPresent(org.hibernate.search.annotations.Field.class)) {
            org.hibernate.search.annotations.Field annotation = fi.getAnnotation(org.hibernate.search.annotations.Field.class);
            String storedName = getStoredFieldName(fi.getName(), annotation);
            if (storedName != null) {
                storedList.add(prefix + storedName);
            }
        }
        // @Fields annotation (should contain one or more @Field annotations)
        if (fi.isAnnotationPresent(org.hibernate.search.annotations.Fields.class)) {
            org.hibernate.search.annotations.Fields annotation = fi.getAnnotation(org.hibernate.search.annotations.Fields.class);
            org.hibernate.search.annotations.Field[] subAnnotations = annotation.value();
            for (org.hibernate.search.annotations.Field subAnnotation : subAnnotations) {
                String storedName = getStoredFieldName(fi.getName(), subAnnotation);
                if (storedName != null) {
                    storedList.add(prefix + storedName);
                }
            }
        }
        // @IndexedEmbeded annotation
        if (fi.isAnnotationPresent(org.hibernate.search.annotations.IndexedEmbedded.class)) {
            org.hibernate.search.annotations.IndexedEmbedded annotation = fi.getAnnotation(org.hibernate.search.annotations.IndexedEmbedded.class);
            String name = fi.getName();
            // If the annotation has declared a prefix then use it instead of the field's name
            if (annotation.prefix() != null && !annotation.prefix().isEmpty() && !annotation.prefix().equals(".")) {
                name = annotation.prefix();
            }
            Class<?> embeddedClass = fi.getType();
            if (Collection.class.isAssignableFrom(embeddedClass)) {
                Type embeddedType = fi.getGenericType();
                if (embeddedType instanceof ParameterizedType) {
                    Type[] argsType = ((ParameterizedType) embeddedType).getActualTypeArguments();
                    if (argsType != null && argsType.length > 0) {
                        embeddedClass = (Class<?>) argsType[0];
                    }
                }
            }
            List<String> nestedFields = getStoredField(embeddedClass, prefix + name + ".");
            if (nestedFields != null && !nestedFields.isEmpty()) {
                storedList.addAll(nestedFields);
            }
        }
    }
    return storedList;
}

/**
 * Returns the @Field's name if this @Field is stored otherwise returns null
 * 
 * @param propertyName
 *            The name of the bean's property
 * @param field
 *            The declared Hibernate Search annotation
 * @return
 */
private static String getStoredFieldName(String propertyName, org.hibernate.search.annotations.Field annotation) {
    Store store = annotation.store();
    if (store == Store.YES || store == Store.COMPRESS) {
        String name = propertyName;
        // If the annotation has declared a name then use it instead of the property's name
        if (annotation.name() != null && !annotation.name().isEmpty()) {
            name = annotation.name();
        }
        return name;
    }
    return null;
}

/**
 * Get all declared fields from the class and its super types
 * 
 * @param type
 * @return
 */
private static List<Field> getAllFields(Class<?> type) {
    List<Field> fields = new ArrayList<Field>();
    if (type != null) {
        fields.addAll(Arrays.asList(type.getDeclaredFields()));
        fields.addAll(getAllFields(type.getSuperclass()));
    }
    return fields;
}
}

Then it's quite easy to retrieve stored fields of an entity:

List<String> storedFields = HBSearchHelper.getStoredFields(MyEntity.class, "");

It should work for:

  • stored attributs (Stored.YES or Stored.COMPRESS)
  • simple attributs (with or without a specified name)
  • embedded attributs (with or without a prefix)
  • multi-fields declaration (ie @Fields annotations)

Hope it can help someone.

like image 42
Eric Taix Avatar answered Oct 06 '22 00:10

Eric Taix