我是靠谱客的博主 缓慢裙子,最近开发中收集的这篇文章主要介绍javassist动态创建类并添加注解,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

有一个场景我需要在一个类的一个字段上加上@JSONField(serialize = false),让它在转换成json字符串的时候忽略指定字段,可是这个类是通过javassist生成的,于是乎就有了下面的内容

依赖

<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.25.0-GA</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.25</version>
</dependency>

创建一个类

package com.mytest;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import javassist.*;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.ClassFile;
import javassist.bytecode.ConstPool;
import javassist.bytecode.annotation.Annotation;
import javassist.bytecode.annotation.BooleanMemberValue;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Method;
/**
* @Author: RR
* @Date: 2021/1/6 10:22
*/
public class JavassistTest {
@Test
public void test() throws Exception {
//用javassist动态创建一个Person类,并将类存放在classLoader中
loadPerson();
//从classLoader中取出Person类的类对象
ClassLoader classLoader = ClassPool.getDefault().getClassLoader();
Class<?> clazz = classLoader.loadClass("com.mytest.Person");
//创建一个Person类的对象,并通过反射的形式给它设值
Object person = clazz.newInstance();
Method setAge = clazz.getMethod("setAge", Integer.class);
Method setName = clazz.getMethod("setName", String.class);
setAge.invoke(person, 1);
setName.invoke(person, "名字");
//打印对象
System.out.println("toString:"+person);
System.out.println("toJSONString:"+JSONObject.toJSONString(person));
}
private void loadPerson() throws Exception{
//声明一个Person类
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass("com.mytest.Person");
/*
为Person类添加两个变量:
private String name;
private Integer age;
*/
CtField name = new CtField(pool.get(String.class.getCanonicalName()), "name", ctClass);
name.setModifiers(Modifier.PRIVATE);
ctClass.addField(name);
CtField age = new CtField(pool.get(Integer.class.getCanonicalName()), "age", ctClass);
age.setModifiers(Modifier.PRIVATE);
ctClass.addField(age);
//关于这段操作我也不太懂,都是零零散散地收集网上看到的,有大佬懂的话希望帮我解答解答~
ClassFile classFile = ctClass.getClassFile();
ConstPool constPool = classFile.getConstPool();
AnnotationsAttribute annotationsAttribute = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
//创建要添加的注解
Annotation jsonFileAnnotation = new Annotation(JSONField.class.getCanonicalName(), constPool);
//设置注解中的属性和值
jsonFileAnnotation.addMemberValue("serialize", new BooleanMemberValue(false, constPool));
//把这个注解放到一个AnnotationsAttribute对象里面
annotationsAttribute.addAnnotation(jsonFileAnnotation);
//把这个对象怼到要打上这个注解的字段/类上面
age.getFieldInfo().addAttribute(annotationsAttribute);
//添加getter setter方法
ctClass.addMethod(CtNewMethod.setter("setName", name));
ctClass.addMethod(CtNewMethod.setter("setAge", age));
ctClass.addMethod(CtNewMethod.getter("getName", name));
ctClass.addMethod(CtNewMethod.getter("getAge", age));
//添加toString方法
StringBuilder builder = new StringBuilder();
builder.append("return "Person{" +n" +
"
"name='" + name + '\'' +n" +
"
", age='" + age + '\'' +n" +
"
'}';");
CtMethod toStringMethod = new CtMethod(pool.get("java.lang.String"), "toString", null, ctClass);
toStringMethod.setBody(builder.toString());
ctClass.addMethod(toStringMethod);
//生成字节码文件,方便查看创建出来的类的结果
ctClass.writeFile("D:\IDEAProject\MyTestProject\target\test-classes");
//
也可以用这种方式,不用生成.class文件也可以直接使用动态生成的类
//
ctClass.toClass(ClassPool.getDefault().getClassLoader(), Class.class.getProtectionDomain());
}
}
  1. 在代码后面的ctClass.writeFile方法,可以把路径修改成自己想要的路径,运行这个测试类,可以找到生成的.class文件,内容如下
public class Person {
private String name;
@JSONField(
serialize = false
)
private Integer age;
//getter setter和无参构造方法省略
  1. 也可以看到我们测试类打印出来的person对象,只打印出name字段的信息,age字段成功被我们打入注解然后忽略掉了
toString:Person{name='名字', age='1'}
toJSONString:{"name":"名字"}

最后

以上就是缓慢裙子为你收集整理的javassist动态创建类并添加注解的全部内容,希望文章能够帮你解决javassist动态创建类并添加注解所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(42)

评论列表共有 0 条评论

立即
投稿
返回
顶部