是否可以在Java中读取注释的值?


98

这是我的代码:

@Column(columnName="firstname")


private String firstName;

 @Column(columnName="lastname")
 private String lastName;

 public String getFirstName() {
  return firstName;
 }

 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }

 public String getLastName() {
  return lastName;
 }

 public void setLastName(String lastName) {
  this.lastName = lastName;
 }

是否可以在另一个类中读取我的注释@Column(columnName =“ xyz123”)的值?

Answers:


122

是的,如果您的Column批注具有运行时保留

@Retention(RetentionPolicy.RUNTIME)
@interface Column {
    ....
}

你可以做这样的事情

for (Field f: MyClass.class.getFields()) {
   Column column = f.getAnnotation(Column.class);
   if (column != null)
       System.out.println(column.columnName());
}

更新:要获取私有字段,请使用

Myclass.class.getDeclaredFields()

1
我喜欢你的解决方案。我们如何使它更通用而不是MyClass我想对T使用它呢?(Field f:T.class.getFields())if(column!= null)System.out.println(column.columnName()); }
ATHER

1
究竟!我也一直在努力解决这个问题。如果我想要一个不需要显式提供类名的注释处理器怎么办?是否可以从上下文中进行选择?'这个'??
5122014009 2014年

我不确定我是否了解你们两个。请以完整示例的形式提出新问题。如果需要,可以在这里链接。
Cephalopod

3
使用Myclass.class.getDeclaredFields()让私人领域
q0re

它为我工作。谢谢。我一直在寻找超类私有字段,因此我使用了clsName.getSuperclass()。getDeclaredFields()
Shashank

88

当然是的。这是一个示例注释:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {

    String testText();
}

和一个示例注释的方法:

class TestClass {

    @TestAnnotation(testText="zyx")
    public void doSomething() {}
}

另一个类中的示例方法将打印testText的值:

Method[] methods = TestClass.class.getMethods();
for (Method m : methods) {
    if (m.isAnnotationPresent(TestAnnotation.class)) {
        TestAnnotation ta = m.getAnnotation(TestAnnotation.class);
        System.out.println(ta.testText());
    }
}

像您这样的字段注释没有太大区别。

加油!


21

我从来没有做过,但是反射似乎提供了此功能。Field是一个AnnotatedElement,所以它有一个getAnnotation这一页有一个示例(复制如下);如果您知道注释的类,并且注释策略在运行时保留了注释,则非常简单。当然,如果保留策略未在运行时保留注释,则您将无法在运行时查询它。

此答案已被删除(?),提供了指向注释教程的有用链接,您可能会觉得有帮助;我已在此处复制链接,以便人们可以使用它。

此页面上的示例:

import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno {
  String str();

  int val();
}

class Meta {
  @MyAnno(str = "Two Parameters", val = 19)
  public static void myMeth(String str, int i) {
    Meta ob = new Meta();

    try {
      Class c = ob.getClass();

      Method m = c.getMethod("myMeth", String.class, int.class);

      MyAnno anno = m.getAnnotation(MyAnno.class);

      System.out.println(anno.str() + " " + anno.val());
    } catch (NoSuchMethodException exc) {
      System.out.println("Method Not Found.");
    }
  }

  public static void main(String args[]) {
    myMeth("test", 10);
  }
}

6

详细说明@Cephalopod的答案,如果您想要列表中的所有列名,则可以使用以下oneliner:

List<String> columns = 
        Arrays.asList(MyClass.class.getFields())
              .stream()
              .filter(f -> f.getAnnotation(Column.class)!=null)
              .map(f -> f.getAnnotation(Column.class).columnName())
              .collect(Collectors.toList());

Objects.nonNull完全接受的Java 8 :) .filter(F - >非空(f.getAnnotation(Column.class)))
dehumanizer

4

尽管到目前为止给出的所有答案都是完全正确的,但也应牢记Google反射库,以便使用一种更通用,更轻松的注释扫描方法,例如

 Reflections reflections = new Reflections("my.project.prefix");

 Set<Field> ids = reflections.getFieldsAnnotatedWith(javax.persistence.Id.class);

3

在我的情况下,您还可以使用泛型类型,并在执行类似操作之前考虑到上述所有内容:

public class SomeTypeManager<T> {

    public SomeTypeManager(T someGeneric) {

        //That's how you can achieve all previously said, with generic types.
        Annotation[] an = someGeneric.getClass().getAnnotations();

    }

}

请记住,这不会等同于SomeClass.class.get(...)();

但是可以做到的...


3

通常情况下,您具有字段的私有访问权限,因此您不能在反射中使用getFields。代替此,您应该使用getDeclaredFields

因此,首先,您应该知道Column批注是否具有运行时保留:

@Retention(RetentionPolicy.RUNTIME)
@interface Column {
}

之后,您可以执行以下操作:

for (Field f: MyClass.class.getDeclaredFields()) {
   Column column = f.getAnnotation(Column.class);
       // ...
}

显然,您想对字段做些事情-使用注释值设置新值:

Column annotation = f.getAnnotation(Column.class);
if (annotation != null) {
    new PropertyDescriptor(f.getName(), Column.class).getWriteMethod().invoke(
        object,
        myCoolProcessing(
            annotation.value()
        )
    );
}

因此,完整的代码如下所示:

for (Field f : MyClass.class.getDeclaredFields()) {
    Column annotation = f.getAnnotation(Column.class);
    if (annotation != null)
        new PropertyDescriptor(f.getName(), Column.class).getWriteMethod().invoke(
                object,
                myCoolProcessing(
                        annotation.value()
                )
        );
}

2

对于要求通用方法的少数人,这应该会对您有所帮助(5年后:p)。

对于下面的示例,我从具有RequestMapping批注的方法中提取RequestMapping URL值。要对此进行调整,只需更改

for (Method method: clazz.getMethods())

for (Field field: clazz.getFields())

然后将RequestMapping的用法换成您要阅读的注释。但是请确保注释具有@Retention(RetentionPolicy.RUNTIME)

public static String getRequestMappingUrl(final Class<?> clazz, final String methodName)
{
    // Only continue if the method name is not empty.
    if ((methodName != null) && (methodName.trim().length() > 0))
    {
        RequestMapping tmpRequestMapping;
        String[] tmpValues;

        // Loop over all methods in the class.
        for (Method method: clazz.getMethods())
        {
            // If the current method name matches the expected method name, then keep going.
            if (methodName.equalsIgnoreCase(method.getName()))
            {
                // Try to extract the RequestMapping annotation from the current method.
                tmpRequestMapping = method.getAnnotation(RequestMapping.class);

                // Only continue if the current method has the RequestMapping annotation.
                if (tmpRequestMapping != null)
                {
                    // Extract the values from the RequestMapping annotation.
                    tmpValues = tmpRequestMapping.value();

                    // Only continue if there are values.
                    if ((tmpValues != null) && (tmpValues.length > 0))
                    {
                        // Return the 1st value.
                        return tmpValues[0];
                    }
                }
            }
        }
    }

    // Since no value was returned, log it and return an empty string.
    logger.error("Failed to find RequestMapping annotation value for method: " + methodName);

    return "";
}

0

我使用它的方法之一:

protected List<Field> getFieldsWithJsonView(Class sourceClass, Class jsonViewName){
    List<Field> fields = new ArrayList<>();
    for (Field field : sourceClass.getDeclaredFields()) {
        JsonView jsonViewAnnotation = field.getDeclaredAnnotation(JsonView.class);
        if(jsonViewAnnotation!=null){
            boolean jsonViewPresent = false;
            Class[] viewNames = jsonViewAnnotation.value();
            if(jsonViewName!=null && Arrays.asList(viewNames).contains(jsonViewName) ){
                fields.add(field);
            }
        }
    }
    return fields;
}    
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.