【Javassist】快速入门系列11 当检测到显示类型转换时用代码块替换

系列文章目录

01 在方法体的开头或结尾插入代码
02 使用Javassist实现方法执行时间统计
03 使用Javassist实现方法异常处理
04 使用Javassist更改整个方法体
05 当有指定方法调用时替换方法调用的内容
06 当有构造方法调用时替换方法调用的内容
07 当检测到字段被访问时使用语句块替换访问
08 当检测到对象(不包括数组)创建时用代码块替换
09 当检测到对象(不包括数组)创建时用代码块替换
10 当检测到instanceof表达式时用代码块替换
11 当检测到显示类型转换时用代码块替换



前言

上一章我们介绍了当检测到instanceof表达式时用代码块替换,学习了 method.instrument的用法。以及参数为Instanceof 的重载方法edit的含义。本章主要介绍当检测到显示类型转换时用代码块替换。


引入Javassist jar包

在上几篇文章已经引入了javassist的jar包,如果你是第一次观看本系列文章,也可以复制以下maven依赖将jar包导入工程。

        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.28.0-GA</version>
        </dependency>

当检测到显示类型转换时用代码块替换

/**
 * 【Javassist】快速入门系列11 当检测到显示类型转换时用代码块替换
 * 公众号&B站:精致的王同学
 * @author 精致的王同学
 * @date 2022/12/28 17:51
 */
public class Basic11Cast {
    public static void main(String[] args) throws Exception{
        // 获取javassist默认类池
        ClassPool pool = ClassPool.getDefault();
        // 获取basic.Basic11Test类的ctclass文件
        CtClass ctClass = pool.get("basic.Basic11Test");
        // 获取basic.Basic11Test类的main方法
        CtMethod method = ctClass.getDeclaredMethod("main");
        // 检测到显示类型转换时用代码块替换
        method.instrument(new ExprEditor() {
            @Override
            public void edit(Cast c) throws CannotCompileException {
                try {
                    if (c.getType().equals(pool.get("java.lang.Long"))) {
                        c.replace("$_=$proceed($$);System.out.println(\"Cast,type:\"+$type+\";value:\"+$1);");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        // 将类写成文件
        ctClass.writeFile();
        // 获取修改后的class对象
        Class<?> clazz = ctClass.toClass();
        // 获取修改后的实例
        Object obj = clazz.newInstance();
        // 获取修改后的方法
        Method main = clazz.getDeclaredMethod("main", String[].class);
        // 调用修改后的方法
        main.invoke(obj,(Object) new String[0]);
    }
}

以上Basic11Cast 类创建了一个main方法,该方法中首先获取javassist的类池pool,然后调用pool.get(“basic.Basic11Test”)方法获取到basic包下的Basic11Testt类。Basic11Test类源码如下:

/**
 * 第11节测试类
 * 公众号&B站:精致的王同学
 * @author 精致的王同学
 * @date 2022/12/28 17:54
 */
public class Basic11Test {
    public static void main(String[] args) {
        HashMap<String,Object> map = new HashMap<>();
        Long skuId = 1L;
        map.put("skuId",skuId);

        Object obj = map.get("skuId");
        if (obj instanceof Long) {
            Long skuId1 = (Long) obj;
            System.out.println("skuId:"+skuId1);
        }
    }
}

该类中有一个main方法,创建了一个HashMap<String,Object>对象。然后将Long类型的skuid放入map中。在通过get方法取出。
取出的skuId类型是Object。

判断如果改对象是Long类型则进行强制类型转换,在屏幕上打印skuId的值

回到Basic11Cast 的main方法,在获取到Basic11Test 类的ctClass的对象之后,获取其main方法的方法对象。

接着调用method.instrument(ExprEditor editor)方法搜索method内的instanceof表达式。调用c.getType()方法获取强制转换的ctclass文件判断是否是java.lang.Long类型的,如果是则调用c.replace(“ = _= =proceed($ ) ; S y s t e m . o u t . p r i n t l n ( C ¨ a s t , t y p e : + ¨ );System.out.println(\"Cast,type:\"+ );System.out.println(C¨ast,type:+¨type+”;value:“+$1);”);表示替换显示类型转换。

instrument方法接收一个ExprEditor 类型的对象,该类有很多重载的edit方法,其中参数为Cast 的重载方法代表搜索方法内的显示类型转换。

在replace的代码块中,以下符号有特殊含义:

$0  null。
$1  显式转换类型的值。
$_  表达式的结果值。$_的类型显式转换之后的类型相同,即由()包围的类型。
$r  显式转换后的类型,或由()包围的类型。
$type  表示与$r相同类型的java.lang.Class对象。
$proceed  执行原始类型转换的虚拟方法的名称。它接受java.lang.Object类型的一个参数,并在原始表达式指定的显式类型转换之后返回它。

最后模拟调用修改后的main方法结果如下:
main方法结果

总结

本篇文章介绍了使用Javassist当检测到显示类型转换时用代码块替换,学习了 method.instrument的用法。以及参数为Cast 的重载方法edit的含义。

说明

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值