get the annotation information at runtime
Asked Answered
I

2

6

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

}

Immense answered 14/12, 2010 at 1:11 Comment(1)
You'll likely get a response more quickly if you add a tag with the programming language you're using.Phallic
J
2

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 { ... }
Joggle answered 14/12, 2010 at 2:32 Comment(4)
My code is a Class annotated,and I want to get its annotation information in other client.Immense
As long as retention type is RUNTIME, annotation definitions are stored along with Java bytecode, and are accessible anywhere class is loaded. The only other thing to include is the annotation class itself (maybe this is what you were looking for?); in your case it would be 'Field.class' (for @Field annotation).Joggle
Hi,thanks,can you spare some time to have a check at my update? :)Immense
Sure. All you need to do then is to do 'fi.getAnnotation(org.hibernate.search.annotations.Field.class)'; and after that, annotation instance has accessors. It is just a pretty regular object so call methods on it. To know which methods are available, check Javadocs for the annotation type (Field).Joggle
R
2

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.

Rushing answered 25/4, 2013 at 11:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.