在运行时获取注解信息

6
我想知道在运行时是否有方法可以获取类的注释信息?因为我想获取特定注释所标注的属性。
例如:
class TestMain {
    @Field(
            store = Store.NO)
    private String  name;
    private String  password;
    @Field(
            store = Store.YES)
    private int     age;

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

注释来自hibernate-search,现在我想知道"TestMain"的哪个属性被注释为'field'(在示例中,它们是[name,age]),哪个被标记为'stored(store=store.yes)'(在示例中,它是[age])。

有什么想法吗?

更新:

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=, boost=@org.hibernate.search.annotations.Boost(value=1.0), analyzer=@org.hibernate.search.annotations.Analyzer(impl=void, definition=), bridge=@org.hibernate.search.annotations.FieldBridge(impl=void, params=[]))

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

    }
    return fieldList;
}

}


如果您添加了正在使用的编程语言的标签,您很可能会更快地得到响应。 - Matthew Frederick
2个回答

2
当然可以。你的代码示例实际上并没有获取类的注释信息,而是获取了字段的注释信息,但是代码相似。你只需要获取你感兴趣的类、方法或字段,然后在其上调用 "getAnnotation(AnnotationClass.class)" 即可。
唯一需要注意的是,注释定义必须使用适当的 RetentionPolicy,以便将注释信息存储在字节码中。例如:
@Target({ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation { ... }

我的代码是一个带注解的类,我想在其他客户端中获取它的注解信息。 - hguser
只要保留类型为RUNTIME,注解定义就会与Java字节码一起存储,并且可以在加载类的任何地方访问。唯一需要包括的是注解类本身(也许这就是您要寻找的内容?);在您的情况下,它将是“Field.class”(用于@Field注解)。 - StaxMan
嗨,谢谢。你能抽出一些时间来检查我的更新吗? :) - hguser
当然。那么你需要做的就是执行 'fi.getAnnotation(org.hibernate.search.annotations.Field.class)';之后,注释实例就有了访问器。它只是一个相当普通的对象,所以可以在其上调用方法。要知道哪些方法可用,请检查注释类型(Field)的 Javadocs。 - StaxMan

2

看起来您正在使用Hibernate Search!Hibernate Search有一个帮助类,可以检索字段信息。

FieldInfos fieldInfos = ReaderUtil.getMergedFieldInfos(indexReader);

不幸的是,FieldsInfos中没有足够的信息(通常情况下您不知道一个字段是否被存储或者我可能错过了什么)。以下是我的实现方式,用于获取所有已存储的字段:

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

那么,获取实体存储字段就很容易了:

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

它应该适用于:

  • 存储属性(Stored.YES或Stored.COMPRESS)
  • 简单属性(带有或不带有指定名称)
  • 嵌入式属性(带有或不带有前缀)
  • 多字段声明(即@Fields注释)

希望它能帮助某些人。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接