Java 如何创建注释的实例
我正在尝试做一些Java注释魔术。我必须说,我仍在掌握注释技巧,某些事情对我来说还不是很清楚 所以。。。我有一些带注释的类、方法和字段。我有一个方法,它使用反射对类运行一些检查,并向类中注入一些值。这一切都很好 然而,我现在面临一个需要注释实例的情况。所以注释与常规接口不同,您不能对类进行匿名实现。我明白了。我在这里查阅了一些关于类似问题的帖子,但我似乎找不到我所寻找的答案Java 如何创建注释的实例,java,reflection,annotations,Java,Reflection,Annotations,我正在尝试做一些Java注释魔术。我必须说,我仍在掌握注释技巧,某些事情对我来说还不是很清楚 所以。。。我有一些带注释的类、方法和字段。我有一个方法,它使用反射对类运行一些检查,并向类中注入一些值。这一切都很好 然而,我现在面临一个需要注释实例的情况。所以注释与常规接口不同,您不能对类进行匿名实现。我明白了。我在这里查阅了一些关于类似问题的帖子,但我似乎找不到我所寻找的答案 我基本上希望获得注释的名称和实例,并能够使用反射设置它的一些字段(我想)。有没有办法做到这一点?嗯,显然没那么复杂newu
我基本上希望获得注释的名称和实例,并能够使用反射设置它的一些字段(我想)。有没有办法做到这一点?嗯,显然没那么复杂<真的强> 正如一位同事所指出的,您可以简单地创建注释的匿名实例(如任何接口),如下所示: MyAnnotation:
public @interface MyAnnotation
{
String foo();
}
调用代码:
class MyApp
{
MyAnnotation getInstanceOfAnnotation(final String foo)
{
MyAnnotation annotation = new MyAnnotation()
{
@Override
public String foo()
{
return foo;
}
@Override
public Class<? extends Annotation> annotationType()
{
return MyAnnotation.class;
}
};
return annotation;
}
}
classmyapp
{
MyAnnotation GetInstanceOffNotation(最终字符串foo)
{
MyAnnotation=新建MyAnnotation()
{
@凌驾
公共字符串foo()
{
返回foo;
}
@凌驾
public Class您可以使用诸如Hibernate Validator项目中的注释代理(免责声明:我是此项目的提交者)。您可以使用sun.reflect.annotation.AnnotationParser.annotationForMap(类,映射)
:
缺点:来自sun.*
的类在以后的版本中可能会发生更改(尽管此方法自Java 5以来就存在,并且具有相同的签名),并且不适用于所有Java实现,请参阅
如果这是一个问题:您可以使用自己的InvocationHandler
创建一个通用代理-这正是AnnotationParser
在内部为您所做的。或者您使用自己定义的MyAnnotation
实现。在这两种情况下,您都应该记住实现annotationType()
、equals()
和hashCode()
作为结果,专门为java.lang.Annotation
记录了代理方法,如中所建议,已在中实现:
以这种方式生成的注释实例的行为与Java通常生成的注释实例完全相同,并且它们的hashCode
和equals
已经正确地实现了兼容性,因此没有像在接受的答案中直接实例化注释那样奇怪的警告h:
库本身很小,没有依赖性(并且不依赖于JDK内部API)
披露:我是GeantyRef的开发人员。在Apache Commons的帮助下使用代理方法相当粗糙
publicstatic(可能也是),没有使用内部Java API的缺点,如我这样做是为了在我的焊接单元测试中添加注释参考:
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ METHOD, FIELD, PARAMETER })
public @interface AuthenticatedUser {
String value() default "foo";
@SuppressWarnings("all")
static class Literal extends AnnotationLiteral<AuthenticatedUser> implements AuthenticatedUser {
private static final long serialVersionUID = 1L;
public static final AuthenticatedUser INSTANCE = new Literal();
private Literal() {
}
@Override
public String value() {
return "foo";
}
}
}
@限定符
@保留(RetentionPolicy.RUNTIME)
@目标({方法,字段,参数})
public@interface AuthenticatedUser{
字符串值()默认为“foo”;
@抑制警告(“全部”)
静态类文字扩展AnnotationLiteral实现AuthenticatedUser{
私有静态最终长serialVersionUID=1L;
public static final AuthenticatedUser实例=new Literal();
私有文本(){
}
@凌驾
公共字符串值(){
返回“foo”;
}
}
}
用法:
Bean<?> createUserInfo() {
return MockBean.builder()
.types(UserInfo.class)
.qualifiers(AuthenticatedUser.Literal.INSTANCE)
.create((o) -> new UserInfo())
.build();
}
Bean createUserInfo(){
返回MockBean.builder()
.types(UserInfo.class)
.qualifiers(AuthenticatedUser.Literal.INSTANCE)
.create((o)->newuserinfo())
.build();
}
您也可以愚蠢地(但简单地)创建一个虚拟注释目标并从中获取它
@MyAnnotation(foo="bar", baz=Blah.class)
private static class Dummy {}
及
创建以方法/参数为目标的注释实例可能要复杂一些,但是这种方法的好处是获得注释实例,就像JVM通常所做的那样。
不用说,这是最简单的方法。@Gunnar的答案是大多数Web服务最简单的方法,因为我们已经有了hibernate,
例如
KafkaListener KafkaListener=new org.hibernate.validator.internal.util.annotation.AnnotationDescriptor.Builder(KafkaListener.class,ImmutableMap.of(“主题”,新字符串[]{“我的主题”})).build().getAnnotation();
和所有其他属性将保持默认状态。您无法实例化或修改批注。在运行代码时批注已经存在。您只能检索它们。您可以给出一些代码示例来说明您正在尝试执行的操作吗?您尝试过getAnnotation()吗可以在java.lang.Class/java.lang.reflect.Method中找到有趣的问题。我试着四处看看,得到了这些。只要看看拉尔夫的第一个答案。我想应该可以。这会有帮助吗?你试过getClass().getAnnotations()了吗?我不想检查一个类是否用某个注释进行了注释。我已经使用反射实现了注入的这一部分。我有一个特例,我必须将MyAnnotation
添加到Set
中,我没有注释的实例。嗯,看起来你也需要实现。大概是这样只需返回MyAnnotation.class
。值得注意的是,我实际上让IDE生成了方法,但没有注意到它也实现了这些方法。它只需返回null
,就可以工作了。我已经将它设置为注释的类类型,尽管我不确定它到底应该是什么。警告:匿名实例MyAnnotation的e是类的实例,而不是annotation,i
public static <A extends Annotation> A mockAnnotation(Class<A> annotationClass, Map<String, Object> properties) {
return (A) Proxy.newProxyInstance(annotationClass.getClassLoader(), new Class<?>[] { annotationClass }, (proxy, method, args) -> {
Annotation annotation = (Annotation) proxy;
String methodName = method.getName();
switch (methodName) {
case "toString":
return AnnotationUtils.toString(annotation);
case "hashCode":
return AnnotationUtils.hashCode(annotation);
case "equals":
return AnnotationUtils.equals(annotation, (Annotation) args[0]);
case "annotationType":
return annotationClass;
default:
if (!properties.containsKey(methodName)) {
throw new NoSuchMethodException(String.format("Missing value for mocked annotation property '%s'. Pass the correct value in the 'properties' parameter", methodName));
}
return properties.get(methodName);
}
});
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ METHOD, FIELD, PARAMETER })
public @interface AuthenticatedUser {
String value() default "foo";
@SuppressWarnings("all")
static class Literal extends AnnotationLiteral<AuthenticatedUser> implements AuthenticatedUser {
private static final long serialVersionUID = 1L;
public static final AuthenticatedUser INSTANCE = new Literal();
private Literal() {
}
@Override
public String value() {
return "foo";
}
}
}
Bean<?> createUserInfo() {
return MockBean.builder()
.types(UserInfo.class)
.qualifiers(AuthenticatedUser.Literal.INSTANCE)
.create((o) -> new UserInfo())
.build();
}
@MyAnnotation(foo="bar", baz=Blah.class)
private static class Dummy {}
final MyAnnotation annotation = Dummy.class.getAnnotation(MyAnnotation.class)