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;
}
}
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 { ... }
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:
Hope it can help someone.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With