JavaAssist的进阶使用

JavaAssist的进阶使用
1、 JavaAssist的介绍与常见使用方法
众所周知,JavaAssist和CGlib作为两个著名的操作Java的ByteCode方式,笔者认为JavaAssist更加灵活些,而CGlib更偏向定制化的应用,比如SpringBoot;而JavaAssist有一级项目吗?笔者知道的有Dubbo和Mybaits。我们先看JavaAssist的常用功能。
1.1 ClassPool的获取
通常我们用以下方式来获取默认ClassPool池:
ClassPool pool = ClassPool.getDefault();
而ClassPool还支持级联Pool:
ClassPool pool = ClassPool.getDefault();
ClassPool child = new ClassPool(pool);
1.2 ClassPool创建Class与获取Class
ClassPool创建或者获取的Class为CtClass,其中创建Class按照以下的方式:
CtClass ctClass = pool.makeClass(“com.javaassisttest.test”);
而获取已有的Class方式为:
CtClass ctClass = pool.get(“com.javaassisttest.test”);
在获取Class的时候,可能需要注意的是:当Class使用自定义的ClassLoader加载的时候,这时候由于JavaAssist使用的是AppClassLoader的加载,因此是找不到该class,需要添加ClassPath,添加ClassPath的方式如下:
pool.appendClassPath(“路径”);
可支持多次添加。
1.3 ClassPool的Import
Pool支持以下方式进行import:
pool.importPackage(“java.util”);
但是,笔者的尝试是经常会产生比较奇怪的反编译代码,笔者建议还是采用完成的名称来定义更为合适。
2、 CtClass中的CtMethod与CtField
我们知道在Class可能存在成员变量和方法,我们可以通过以下方式进行成员变量的添加
CtField f = CtField.make(String.format(“private %s %s;”, field.getTypeName(), field.getName()), ctClass);
ctClass.addField(f);
同样,我们可以通过以下方式进行方法的添加:
String methodName = field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
CtMethod get = CtMethod.make(String.format(getMethod, field.getTypeName(), methodName, field.getName()), ctClass);
ctClass.addMethod(get);
CtMethod set = CtMethod.make(String.format(setMethod, methodName, field.getTypeName(), field.getName()), ctClass);
ctClass.addMethod(set);
这里是get和set方法的添加,其中getMethod和setMethod的定义如下:
private final static String getMethod = “public %s get%s() { return %s;}”;
private final static String setMethod = “public void set%s( %s $v) { %s = $v;}”;

至此,我们把JavaAssist的基本功能就讲解完了,下面我们还是进阶的部分。
3、 两个例子来看进阶的操作
笔者使用JavaAssist需要创建如下两个类:
其中类一:
@Data
@Table(name = “goods”)
public class TkGoods {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "name")
private String name;
@Column(name = "color")
private Integer color;
@Column(name = "suit")
private Integer suit;
@Column(name = "state")
private Integer state;
@Column(name = "addTime")
private Date addTime;
@Column(name = "updateTime")
private Date updateTime;

}
类二:
public interface TkGoodsDao extends Mapper {

}
也就是tkMybatis的两个类,这两个类有两种操作在上一节中没有说到:
(1) 注解
(2) 泛型子类
3.1 注解的添加
JavaAssist是支持注解的添加的,给Class添加注解如下代码所示:
AnnotationsAttribute annotationsAttribute = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
Annotation annotation = new Annotation(“javax.persistence.Table”, constPool);
annotation.addMemberValue(“name”, new StringMemberValue(entity.getDbName(), constPool));
annotationsAttribute.addAnnotation(annotation);
ctClass.getClassFile().addAttribute(annotationsAttribute);
同理,我们还能给成员变量添加注解
CtField f = CtField.make(String.format(“private %s %s;”, field.getTypeName(), field.getName()), ctClass);
AnnotationsAttribute fannotationsAttribute = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
Annotation fColumn = new Annotation(“javax.persistence.Column”, constPool);
fColumn.addMemberValue(“name”, new StringMemberValue(field.getDbName(), constPool));
fannotationsAttribute.addAnnotation(fColumn);
f.getFieldInfo().addAttribute(fannotationsAttribute);
这样我们就完成了注解的添加,注:有一类注解是在编译时执行的,比如lombok,这种注解就必须手动完成get和set方法了。
3.2 泛型子类
我们先看下面这个类
class List {
T value;
T get() { return value; }
void set(T v) { value = v; }
}
在JavaAssist的官网中,也是这个类的例子,这个例子告诉我们通过setGenericSignature去设置模板,具体的代码如下:
ClassSignature cs = new ClassSignature(
new TypeParameter[] { new TypeParameter(“T”) });
cc.setGenericSignature(cs.encode()); // <T:Ljava/lang/Object;>Ljava/lang/Object;
然而,对于泛型子类的方式,官网上却没有提及,诸多查找出来的答案也是无法完成想要的效果的。最后还是找到了这样的答案,如下代码所示:
CtClass ctClass = pool.makeInterface(className);
CtClass clsMapper = pool.get(Mapper.class.getName());
ctClass.setSuperclass(clsMapper);
SignatureAttribute.ClassSignature cs = new SignatureAttribute.ClassSignature(null, null,
new SignatureAttribute.ClassType[] {new SignatureAttribute.ClassType(Mapper.class.getName(),
new SignatureAttribute.TypeArgument[]{new SignatureAttribute.TypeArgument(new SignatureAttribute.ClassType(clsEntity.getName()))})});
ctClass.setGenericSignature(cs.encode());

4、 留下的两个疑问
到此,JavaAssist的进阶功能就基本介绍完成了,细心的你一定会发现这两个类就是TkMybatis的两个类,那么
1、 我们知道通过tk.mybatis.spring.annotation.MapperScan进行Bean注入,这两个类自动生成的类用来做什么呢?
2、 如何把我们生成的两个类添加到Bean中形成MapperProxy,是Refresh吗?
具体见下一篇的分解,自动处理动态表单的标准化与插件化。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值