从方法创建的实例中获取方法的注释



下面是一个示例

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Annotation {

}
@Configuration
public class Configuration {

@Bean
@Annotation
public Test getTest() {
return new Test();
}
}
public class Test() {
public void test() {
// how can get the annotation `@Annotation` here?
}
}

以下是我尝试过的getClass().getAnnotations(),但它返回空数组。我可以理解为什么getClass()返回了没有注释的Test.class。如何获取创建此实例的方法,然后获取注释?

理论上,您可以检查当前线程堆栈以确定调用方的名称,然后查找类定义,定位方法,并读取其注释:

var t = Thread.currentThread().getStackTrace()[2];
var className = t.getClassName();
Class<?> clazz;
try {
clazz = Test.class.getClassLoader().loadClass(className);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Caller was loaded by a different ClassLoader :-(");
}
for (var method : clazz.getDeclaredMethods()) {
if (method.getName().equals(t.getMethodName())) {
return method.getAnnotation(YourAnnotation.class).value();
}
}
throw new RuntimeException("Method not found - I might have found the wrong class definition");

但是:

  • 检查堆栈相当缓慢,尤其是在堆栈较深的情况下
  • 相对于重构,检查堆栈是很脆弱的(人们不认为将代码分解到实用程序方法中会改变行为(
  • 编译器无法检查调用程序是否提供了所需的注释
  • 只有当所有代码都由同一个ClassLoader加载时,这才可靠
  • 这无法区分重载方法

因此,这是一个相当脆弱的破解。你确定没有更好的选择吗?例如,要求调用方将值作为方法参数传递不会有这些缺点。。。

您可以使用ConfigurableListableBeanFactory按名称获取任何Bean的元数据。使用BeanNameAware接口检索Bean名称。

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface CustomAnnotation {
}
@org.springframework.context.annotation.Configuration
public static class ContextConfiguration {
@Bean(name = "TEST")
@CustomAnnotation
public TestObject getTest() {
return new TestObject();
}
}
public class TestObject implements BeanNameAware {
private String beanName;
@Autowired
ConfigurableListableBeanFactory beanFactory;
@Override
public void setBeanName(String name) {
this.beanName = name;
}
public void test() {
CustomAnnotation customAnnotation = (CustomAnnotation) getBeanAnnotation(beanName, CustomAnnotation.class);
}
private Annotation getBeanAnnotation(String beanName, java.lang.Class<? extends Annotation> clazz) {
Annotation annotation = null;
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
if( beanDefinition != null && beanDefinition.getSource() instanceof StandardMethodMetadata) {
StandardMethodMetadata metadata = (StandardMethodMetadata) beanDefinition.getSource();
annotation = Arrays.stream(metadata.getIntrospectedMethod().getDeclaredAnnotations()).filter(annot -> annot.annotationType().equals(clazz)).findFirst().orElse(null);
}
return annotation;
}
}

最新更新