首页 > 其他分享 >使用annotationForMap实例化注解

使用annotationForMap实例化注解

时间:2024-02-02 15:45:48浏览次数:24  
标签:memberValues AnnoProxyTest annotationForMap 实例 result new 注解 type annotation

sun.reflect.annotation.AnnotationParser#annotationForMap

    /**
     * Returns an annotation of the given type backed by the given
     * member -> value map.
     */
    public static Annotation annotationForMap(final Class<? extends Annotation> type,
                                              final Map<String, Object> memberValues)
    {
        return AccessController.doPrivileged(new PrivilegedAction<Annotation>() {
            public Annotation run() {
                return (Annotation) Proxy.newProxyInstance(
                    type.getClassLoader(), new Class<?>[] { type },
                    new AnnotationInvocationHandler(type, memberValues));
            }});
    }

此方法可以根据typememberValues两个入参生成一个对应的注解实例,可以近似理解成使用反射技术生成一个类的实例。可以看到,他的返回值是一个很熟悉的方法,没错,就是JDK动态代理中用于实现切面逻辑的方法java.lang.reflect.Proxy#newProxyInstance。那么就好办了,我们只需要看懂new AnnotationInvocationHandler(type, memberValues)这个类就行了。下面是这个类的主要代码:

class AnnotationInvocationHandler implements InvocationHandler, Serializable {
    
    private final Class<? extends Annotation> type;
    private final Map<String, Object> memberValues;
    
	AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) {
        Class<?>[] superInterfaces = type.getInterfaces();
        if (!type.isAnnotation() ||
            superInterfaces.length != 1 ||
            superInterfaces[0] != java.lang.annotation.Annotation.class)
            throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");
        this.type = type;
        this.memberValues = memberValues;
    }

    public Object invoke(Object proxy, Method method, Object[] args) {
        String member = method.getName();
        Class<?>[] paramTypes = method.getParameterTypes();

        // Handle Object and Annotation methods
        if (member.equals("equals") && paramTypes.length == 1 &&
            paramTypes[0] == Object.class)
            return equalsImpl(args[0]);
        if (paramTypes.length != 0)
            throw new AssertionError("Too many parameters for an annotation method");

        switch(member) {
        case "toString":
            return toStringImpl();
        case "hashCode":
            return hashCodeImpl();
        case "annotationType":
            return type;
        }

        // Handle annotation member accessors
        Object result = memberValues.get(member);

        if (result == null)
            throw new IncompleteAnnotationException(type, member);

        if (result instanceof ExceptionProxy)
            throw ((ExceptionProxy) result).generateException();

        if (result.getClass().isArray() && Array.getLength(result) != 0)
            result = cloneArray(result);

        return result;
    }
    
    ...
}

invoke方法中,member是方法名,memberValues是传入的键值对,意思就是,只要传入注解的类,和类中方法名对应的值,就可以生成一个注解

编写如下代码进行测试:

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD})
    public @interface AnnoProxyTest
    {
        String value();
    }    


	private void testAnnotationForMap() {
        Map<String, Object> map = new HashMap<>();
        map.put("value", "hello");
        Annotation annotation = AnnotationParser.annotationForMap(AnnoProxyTest.class, map);
        System.err.println(annotation);
        System.err.println(annotation instanceof AnnoProxyTest);
        AnnoProxyTest annoProxyTest = (AnnoProxyTest) annotation;
        System.err.println(annoProxyTest.value());
    }

// 输出:
// > @com.xml.demo.basicknowledge.proxy.anno.AnnoProxy$AnnoProxyTest(value=hello)
// > true
// > hello

看结果就是生成了一个正常的注解。

再搞点骚操作,写一个半成的

    private void testCreateAnnotation() {
        Class<? extends Annotation> type = AnnoProxyTest.class;

        Map<String, Object> memberValues = new HashMap<>();
        memberValues.put("value", "1");

        Annotation annotation = (Annotation) Proxy.newProxyInstance(type.getClassLoader(), new Class<?>[] {type},
                (proxy, method, args) -> memberValues.get(method.getName()));

        System.err.println(annotation);
        System.err.println(annotation instanceof AnnoProxyTest);
        AnnoProxyTest annoProxyTest = (AnnoProxyTest) annotation;
        System.err.println(annoProxyTest.value());
    }

// 输出:
// > null
// > true
// > 1

也是可以正常输出的,只不过没有实现toString方法,所以输出为null,但是调用其中方法还是可以正常输出的,且类型也是正确的

总结:注解就是一个JDK代理类

AccessController.doPrivileged

AccessController.doPrivileged - 山河已无恙 - 博客园 (cnblogs.com)

标签:memberValues,AnnoProxyTest,annotationForMap,实例,result,new,注解,type,annotation
From: https://www.cnblogs.com/xmlxml/p/18003286

相关文章

  • 关于Spring5新增的Indexed注解
    前言如果我们应用中使用@ComponentScan注解扫描的package包含的类很多的时候,Spring解析耗时就会很多,相应的应用启动时间也就更长,Spring5.0引入了一个新的注解@Indexed,它可以为Spring的模式注解添加索引,以提升应用启动性能。使用<dependency><groupId>org.springframewor......
  • 【数据库数据恢复】Oracle数据库ASM磁盘组掉线,ASM实例不能挂载的数据恢复案例
    oracle数据库故障&分析:oracle数据库ASM磁盘组掉线,ASM实例不能挂载。数据库管理员尝试修复数据库,但是没有成功。oracle数据库数据恢复过程:1、将oracle数据库所涉及磁盘以只读方式备份。后续的数据分析和数据恢复操作都基于镜像文件进行,避免对原始磁盘数据造成二次破坏。2、基于......
  • Blazor里,如何在 razor 页面使用 BackgroundService 实例
    Blazor使用BackgroundService需要注册builder.Services.AddHostedService<PageStateService>();razor页面要使用 PageStateService的实例,需要 PageStateService有接口,我们给PageStateService写一个接口 IPageStateService然后在页面直接注入实例@injectIPageSt......
  • 深入理解spring注解之@ComponentScan注解
    今天主要从以下几个方面来介绍一下@ComponentScan注解:@ComponentScan注解是什么@ComponentScan注解的详细使用 1,@ComponentScan注解是什么 其实很简单,@ComponentScan主要就是定义扫描的路径从中找出标识了需要装配的类自动装配到spring的bean容器中  2,@Compone......
  • R语言GAMLSS模型对艾滋病病例、降雪量数据拟合、预测、置信区间实例可视化
    全文链接:http://tecdat.cn/?p=31996原文出处:拓端数据部落公众号GAMLSS模型是一种半参数回归模型,参数性体现在需要对响应变量作参数化分布的假设,非参数性体现在模型中解释变量的函数可以涉及非参数平滑函数,非参数平滑函数不预先设定函数关系,各个解释变量的非线性影响结果完全取决......
  • springboot整合mybatis(纯注解版)
    springboot整合mybatis1、注解:参考表@ResponseBody:表示该方法的返回结果直接写入HTTPresponsebody中,一般在异步获取数据时使用,用于构建RESTful的api。在使用@RequestMapping后,返回值通常解析为跳转路径,加上@responsebody后返回结果不会被解析为跳转路径,而是直接写入HTTPres......
  • 使用注解替换Spring配置文件&SpringMVC的配置文件
    创建初始化类,替换web.xml在Servlet3.0环境中,Web容器(Tomcat)会在类路径中查找实现javax.servlet.ServletContainerInitializer接口的类,如果找到的话就用它来配置Servlet容器。Spring提供了这个接口的实现,名为SpringServletContainerInitializer,这个类反过来又会查找实现WebA......
  • fpmarkets实例讲解止损,控制风险如此简单
    止损和止盈是交易者在交易时都需要了解的两个基本设置,在上篇文章fpmarkets澳福和各位投资者分享了止盈如何工作,今天我们继续实例讲解止损,在交易中控制不必要的风险。止损单是基本交易订单之一。如果市场走向与预期相反,它会限制损失。事实上,它是止盈的反义词。止盈为利润设定限额,止......
  • Prometheus结合Consul采集多个MySQL实例的监控指标
    本文主要介绍如何利用Prometheus官网提供的mysqld_exporter进行多MySQL实例的监控指标采集建议安装最新版的mysqld_exporter,因为从’2022-09-01’之后才支持多实例功能的。具体的官网说明详见 Supportforscrapingmultiplemysqldhosts(#651)[1]ok,开始今天的教程~1、下载安......
  • WebAssembly核心编程[1]:wasm模块实例化的N种方式
    当我们在一个Web应用中使用WebAssembly,最终的目的要么是执行wasm模块的入口程序(通过start指令指定的函数),要么是调用其导出的函数,这一切的前提需要创建一个通过WebAssembly.Instance对象表示的wasm模块实例(源代码)。一、wasm模块实例化总体流程二、利用WebAssembly.Module创建实......