字节码编程javassist之生成带有注解的类

写在前面

本文看下如何使用javassist生成带有注解的类。

1:程序

  • 测试类
package com.dahuyou.javassist.huohuo.cc;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;// 保留到哪个阶段,SOURCE 仅仅在源代码中保留,编译器不保留该信息。CLASS(默认保留方式),编译器保留,但VM不保留。RUNTIME VM保留,即一直在
// SOURCE作用:给人看,有点类似于注释了,但是是源代码的一部分,比如Override,告诉我们这是重写父类的方法
// CLASS作用:编译器用?咋用???
// RUNTIME作用:程序运行使用,用的最多,比如Deprecated
@Retention(RetentionPolicy.RUNTIME)
// 用在哪里 TYPE 类上 METHOD方法上 FIELD用在字段上
@Target(ElementType.TYPE)
public @interface MyAnnotationOnClazz {boolean opened() default false;String desc() default "";int number();
}
package com.dahuyou.javassist.huohuo.cc;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;// 保留到哪个阶段,SOURCE 仅仅在源代码中保留,编译器不保留该信息。CLASS(默认保留方式),编译器保留,但VM不保留。RUNTIME VM保留,即一直在
// SOURCE作用:给人看,有点类似于注释了,但是是源代码的一部分,比如Override,告诉我们这是重写父类的方法
// CLASS作用:编译器用?咋用???
// RUNTIME作用:程序运行使用,用的最多,比如Deprecated
@Retention(RetentionPolicy.RUNTIME)
// 用在哪里 TYPE 类上 METHOD方法上 FIELD用在字段上
@Target(ElementType.METHOD)
public @interface MyAnnotationOnMethod {String typeName() default "";long payAmount();
}
  • 生成代码类
package com.dahuyou.javassist.huohuo.cc;import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.Bytecode;
import javassist.bytecode.ConstPool;
import javassist.bytecode.MethodInfo;
import javassist.bytecode.annotation.Annotation;
import javassist.bytecode.annotation.BooleanMemberValue;
import javassist.bytecode.annotation.LongMemberValue;
import javassist.bytecode.annotation.StringMemberValue;public class MyDoItttt extends ClassLoader {public static void main(String[] args) throws Exception {ClassPool pool = ClassPool.getDefault();// 创建类CtClass ctClass = pool.makeClass("com.dahuyou.javassist.huohuo.bb.Helloworld_javassist");// 创建方法
//        CtMethod queryAmount = new CtMethod(CtClass.doubleType, "queryAmount", new CtClass[]{pool.get(String.class.getName())}, ctClass);CtMethod queryAmount = new CtMethod(CtClass.doubleType, "queryAmount", new CtClass[]{}, ctClass);
//        queryAmount.addLocalVariable();
//        queryAmount.
//        CtMethod queryAmount = new CtMethod(CtClass.voidType, "queryAmount", new CtClass[]{pool.get(String.class.getName())}, ctClass);queryAmount.setModifiers(Modifier.PUBLIC);// 执行到这里,空方法public double queryAmount(String var1) {}就有了ctClass.addMethod(queryAmount);MethodInfo methodInfo = queryAmount.getMethodInfo();// 获取常量池,注意虽然是通过类信息对象获取的,但常量池是属于类级别的,只不过这里和方法做了关联ConstPool constPool = methodInfo.getConstPool();// 设置类注解AnnotationsAttribute annotationsAttribute = new AnnotationsAttribute(constPool, AnnotationsAttribute.invisibleTag);Annotation clazzAnnotation = new Annotation("com/dahuyou/javassist/huohuo/cc/MyAnnotationOnClazz", constPool);// 设置类注解的属性们/*String clazzDesc() default "";String alias() default "";long timeOut() default 350;boolean opened() default false;String desc() default "";int number();*/clazzAnnotation.addMemberValue("opened", new BooleanMemberValue(true, constPool));clazzAnnotation.addMemberValue("desc", new StringMemberValue("api描述啊", constPool));
//        clazzAnnotation.addMemberValue("number", new IntegerMemberValue(455, constPool));annotationsAttribute.setAnnotation(clazzAnnotation);ctClass.getClassFile().addAttribute(annotationsAttribute); // 画龙点睛,调用类的addAttribute添加注解,没有可不行// 添加方法注解AnnotationsAttribute methodAttribute = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);Annotation methodAnnotation = new Annotation("com/dahuyou/javassist/huohuo/cc/MyAnnotationOnMethod", constPool);methodAnnotation.addMemberValue("typeName", new StringMemberValue("查询费用111", constPool));methodAnnotation.addMemberValue("payAmount", new LongMemberValue(562L, constPool));methodAttribute.setAnnotation(methodAnnotation);methodInfo.addAttribute(methodAttribute);Bytecode bytecode = new Bytecode(constPool);bytecode.addGetstatic("java/math/BigDecimal", "TEN", "Ljava/math/BigDecimal;");bytecode.addInvokevirtual("java/math/BigDecimal", "doublevalue", "()D");bytecode.addReturn(CtClass.doubleType);methodInfo.setCodeAttribute(bytecode.toCodeAttribute());ctClass.writeFile();// 以下代码总是报:Ljava/math/BigDecimal;java.lang.ClassFormatError: Arguments can't fit into locals... 感觉是本地变量表不够大导致。但不知道该如何设置System.out.println("-------华丽的分割线-------");/* byte[] bytes = ctClass.toBytecode();Class<?> clazzNew = new MyDoItttt().defineClass("com.dahuyou.javassist.huohuo.bb.Helloworld_javassist", bytes, 0, bytes.length);MyAnnotationOnClazz annotationOnClazz = clazzNew.getAnnotation(MyAnnotationOnClazz.class);System.out.println("annotationOnClazz.opened: " + annotationOnClazz.opened());System.out.println("annotationOnClazz.desc: " + annotationOnClazz.desc());MyAnnotationOnMethod annotationOnMethod = clazzNew.getDeclaredMethod("queryAmount").getAnnotation(MyAnnotationOnMethod.class);System.out.println("annotationOnMethod.payAmount: " + annotationOnMethod.payAmount());System.out.println("annotationOnMethod.typeName: " + annotationOnMethod.typeName());*/}
}

运行后查看生成的字节码:
在这里插入图片描述

写在后面

参考文章列表

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/869433.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

保姆级教程:Linux (Ubuntu) 部署流光卡片开源 API

流光卡片 API 开源地址 Github&#xff1a;https://github.com/ygh3279799773/streamer-card 流光卡片 API 开源地址 Gitee&#xff1a;https://gitee.com/y-gh/streamer-card 流光卡片在线使用地址&#xff1a;https://fireflycard.shushiai.com/ 等等&#xff0c;你说你不…

0基础学会在亚马逊云科技AWS上搭建生成式AI云原生Serverless问答QA机器人(含代码和步骤)

小李哥今天带大家继续学习在国际主流云计算平台亚马逊云科技AWS上开发生成式AI软件应用方案。上一篇文章我们为大家介绍了&#xff0c;如何在亚马逊云科技上利用Amazon SageMaker搭建、部署和测试开源模型Llama 7B。下面我将会带大家探索如何搭建高扩展性、高可用的完全托管云原…

FullCalendar的使用,react日历组件

1.下载 yarn add fullcalendar/core fullcalendar/react fullcalendar/daygrid 2.运行 import React from react; import FullCalendar from "fullcalendar/react"; import dayGridPlugin from "fullcalendar/daygrid";const ExperimentalSchedule () …

初识STM32:寄存器编程 × 库函数编程 × 开发环境

STM32的编程模型 假如使用C语言的方式写了一段程序&#xff0c;这段程序首先会被烧录到芯片当中&#xff08;Flash存储器中&#xff09;&#xff0c;Flash存储器中的程序会逐条的进入CPU里面去执行。 CPU相当于人的一个大脑&#xff0c;虽然能执行运算和执行指令&#xff0c;…

面试官:讲一下如何终止一个 Promise 继续执行

我们知道 Promise 一旦实例化之后&#xff0c;状态就只能由 Pending 转变为 Rejected 或者 Fulfilled&#xff0c; 本身是不可以取消已经实例化之后的 Promise 了。 但是我们可以通过一些其他的手段来实现终止 Promise 的继续执行来模拟 Promise 取消的效果。 Promise.race …

SAP_MMABAP模块_MM60物料清单新增物料组描述字段

业务背景&#xff1a; 用户需要在系统标准的物料主数据查询报表MM60中&#xff0c;添加物料组描述&#xff0c;一直以来&#xff0c;我都觉得标准的MM60显示的内容字段不够多&#xff0c;不太好用。 以往都是给用户新开发一个物料主数据查询报表来解决的&#xff0c;但是这次刚…

数学建模及国赛

认识数学建模及国赛 认识数学建模 环境类&#xff1a;预测一下明天的气温 实证类&#xff1a; 评价一下政策的优缺点 农业类&#xff1a; 预测一下小麦的产量 财经类&#xff1a; 分析一下理财产品的最优组合 规划类&#xff1a; 土地利用情况进行 合理的划分 力学类&#xf…

ProFuzzBench入门教学——使用(Ubuntu22.04)

ProFuzzBench是网络协议状态模糊测试的基准测试。它包括一套用于流行协议&#xff08;例如 TLS、SSH、SMTP、FTP、SIP&#xff09;的代表性开源网络服务器&#xff0c;以及用于自动执行实验的工具。详细参考&#xff1a;阅读笔记——《ProFuzzBench: A Benchmark for Stateful …

一句话彻底搞懂Java的编译和执行过程

编译和运行可以在不同的计算机上实现。 编译阶段&#xff1a;由Javac编译器将 .Java 的源文件编译为 .class 的字节码文件&#xff1b; 运行阶段&#xff1a; jvm中Java编译器运行 .class 的字节码文件&#xff0c;运行过程中&#xff0c;类加载器从硬盘中找到该字节码文件并…

WPF引入多个控件库使用

目的 设计开发时有的控件库的一部分符合我们想要的UI样式&#xff0c;另一部分来自另一个控件库&#xff0c;想把两种库的样式做一个整合在同一个控件资源上。单纯通过引用的方式会导致原有样式被覆盖。这里通过设置全局样式的方式来实现。 1.安装控件库nuget包&#xff1a;H…

Webpack: 模块编译打包及运行时Runtime逻辑

概述 回顾最近几节内容&#xff0c;Webpack 运行过程中首先会根据 Module 之间的引用关系构建 ModuleGraph 对象&#xff1b;接下来按照若干内置规则将 Module 组织进不同 Chunk 对象中&#xff0c;形成 ChunkGraph 关系图。 接着&#xff0c;构建流程将来到最后一个重要步骤…

Argo CD入门、实战指南

1. Argo CD概述 1.1 什么是 Argo CD Argo CD 是针对 Kubernetes 的声明式 GitOps 持续交付工具。 1.2 为什么选择 Argo CD 应用程序定义、配置和环境应具有声明性并受版本控制。应用程序部署和生命周期管理应自动化、可审计且易于理解。 2. Argo CD基础知识 在有效使用 Ar…

中职网络安全B模块渗透测试server2003

通过本地PC中渗透测试平台Kali对服务器场景Windows进⾏系统服务及版本扫描渗透测 试&#xff0c;并将该操作显示结果中Telnet服务对应的端⼝号作为FLAG提交 使用nmap扫描发现目标靶机开放端口232疑似telnet直接进行连接测试成功 Flag&#xff1a;232 通过本地PC中渗透测试平台…

使用 Hugging Face 的 Transformers 库加载预训练模型遇到的问题

题意&#xff1a; Size mismatch for embed_out.weight: copying a param with shape torch.Size([0]) from checkpoint - Huggingface PyTorch 这个错误信息 "Size mismatch for embed_out.weight: copying a param with shape torch.Size([0]) from checkpoint - Hugg…

Elasticsearch基础(四):Elasticsearch语法与案例介绍

文章目录 Elasticsearch语法与案例介绍 一、Restful API 二、查询语法 1、ES分词器 2、ES查询 2.1、match 2.2、match_phrase 2.3、multi_match 2.4、term 2.5、terms 2.6、fuzzy 2.7、range 2.8、bool Elasticsearch语法与案例介绍 一、Restful API Elastics…

服务攻防——中间件Jboss

文章目录 一、Jboss简介二、Jboss渗透2.1 JBoss 5.x/6.x 反序列化漏洞&#xff08;CVE-2017-12149&#xff09;2.2 JBoss JMXInvokerServlet 反序列化漏洞&#xff08;CVE-2015-7501&#xff09;2.3 JBossMQ JMS 反序列化漏洞&#xff08;CVE-2017-7504&#xff09;2.4 Adminis…

Java如何自定义注解及在SpringBoot中的应用

注解 注解&#xff08;Annotation&#xff09;&#xff0c;也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性&#xff0c;与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面&#xff0c;用来对这些元素进行说…

leetcode:LCR 018. 验证回文串(python3解法)

难度&#xff1a;简单 给定一个字符串 s &#xff0c;验证 s 是否是 回文串 &#xff0c;只考虑字母和数字字符&#xff0c;可以忽略字母的大小写。 本题中&#xff0c;将空字符串定义为有效的 回文串 。 示例 1: 输入: s "A man, a plan, a canal: Panama" 输出: t…

【C++】开源:坐标转换和大地测量GeographicLib库配置使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍坐标转换和大地测量GeographicLib库配置使用。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关…

Effective C++笔记之二十一:One Definition Rule(ODR)

ODR细节有点复杂&#xff0c;跨越各种情况。基本内容如下&#xff1a; ●普通&#xff08;非模板&#xff09;的noninline函数和成员函数、noninline全局变量、静态数据成员在整个程序中都应当只定义一次。 ●class类型&#xff08;包括structs和unions&#xff09;、模板&…