在Java中,是否有可能读取注释的值?

132

这是我的代码:

@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")的值,这是否可能?

10个回答

152

是的,如果您的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
我喜欢你的解决方案。我们如何使其更通用,例如使用T而不是MyClass,像这样: for (Field f: T.class.getFields()) { Column column = f.getAnnotation(Column.class); if (column != null) System.out.println(column.columnName()); } - ATHER
1
没错!我也一直在努力弄清楚这个问题。如果我想要一个注解处理器,它不需要显式地提供类名怎么办?它能否从上下文中获取;'this'? - 5122014009
我不确定我理解你们两个需要什么。请用完整的示例作为新问题提出。如果您愿意,可以在此处链接它。 - Cephalopod
3
使用Myclass.class.getDeclaredFields()来获取私有字段。 - q0re
它对我有用。谢谢。我正在寻找超类私有字段,所以我使用了clsName.getSuperclass().getDeclaredFields()。 - Shashank
显示剩余2条评论

97

当然可以。以下是一个示例注解:

@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());
    }
}

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


25

我从未尝试过,但是看起来 反射技术 可以提供这个功能。 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);
  }
}

7

对于@Cephalopod的回答进行补充,如果您想要将所有列名放在一个列表中,您可以使用以下一行代码:

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());

.filter(f -> Objects.nonNull(f.getAnnotation(Column.class))) - dehumanizer

6

虽然目前为止给出的所有答案都是完全有效的,但也应该记住Google Reflections库,它提供了一种更通用、更易于使用的注解扫描方法,例如:

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

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

4
在通常情况下,字段具有私有访问权限,因此您无法在反射中使用getFields。相反,您应该使用getDeclaredFields
因此,首先,您应该了解您的列注释是否具有运行时保留:
@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()
                )
        );
}

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(...)();

但可以解决问题...


2

对于那些寻求通用方法的人,这篇文章应该会对你有所帮助(5年之后 :p)。

在我的下面的例子中,我从带有RequestMapping注释的方法中提取了RequestMapping URL值。 要适应字段,请更改

for (Method method: clazz.getMethods())

to

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

要读取Java中注释的值,请尝试按照以下步骤进行:

  1. 创建一个注释。
  2. 按照下面目标类中的逻辑进行操作。
  3. 像输出中那样访问该值。

注释

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE}) // make annotation usable only for classes
@Retention(RetentionPolicy.RUNTIME) // make annotation available at the runTime
public @interface EntryPoint {
    String url();
}

目标

// just remember to import your annotation in this case "EntryPoint"

import java.lang.annotation.Annotation;

@EntryPoint(url = "api/v1/demo")
public class Demo {
    // get class of this.
    private final Class<? extends Demo> demo = this.getClass();
    // get specific annotation (EntryPoint.class)
    private final Annotation annotation = demo.getAnnotation(EntryPoint.class);
    // instantiate annotation and assign it value from the class annotation.
    final EntryPoint entryPoint = (EntryPoint) annotation;
}

输出

public class Main {
    public static void main(String[] args) {
        // create an object of the class with the annotation.
        Demo demo = new Demo();
        System.out.println(demo.entryPoint.url());
    }
}

结果是 "api/v1/demo"


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

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