SpringBootTest环境下使用easyexcel出现accessors-smart和asm冲突

背景:在正常的环境下进行Excel导出是正常的,但是在单元测试的时候发现代码运行异常,抛出的异常堆栈如下:

Caused by: java.lang.VerifyError: class net.sf.cglib.core.DebuggingClassWriter overrides final method visit.(IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
	at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
	at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
	at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	at net.sf.cglib.core.AbstractClassGenerator.<init>(AbstractClassGenerator.java:38)
	at net.sf.cglib.core.KeyFactory$Generator.<init>(KeyFactory.java:127)
	at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:112)
	at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:108)
	at net.sf.cglib.beans.BeanMap$Generator.<clinit>(BeanMap.java:64)
	at com.alibaba.excel.util.BeanMapUtils.create(BeanMapUtils.java:26)
	at com.alibaba.excel.write.executor.ExcelWriteAddExecutor.addJavaObjectToExcel(ExcelWriteAddExecutor.java:144)

分析步骤:

步骤1:从网上搜该异常的解决方法中大部分都说cglib与asm版本不兼容导致的,那我遇到的这个问题是不是也是这种情况呢?从线上环境运行正常来看,排除了这种不兼容场景的想法,把线上的版本包下载下来,解压看到相关的jar如下:cglib-2.2.jar、asm-3.1.jar。

步骤2:是不是因为SpringBootTest加载了特定版本的asm呢?于是打开项目pom.xml,切换到Dependency Analyzer模式,输入asm,确实出现了asm的5.0.4版本,见下图:

 

选中上图的asm:5.0.4这一行,右击之后选择Exclude选项来排除该jar,也就是在pom.xml中增加

<exclusion>内部的代码:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <artifactId>asm</artifactId>
                    <groupId>org.ow2.asm</groupId>
                </exclusion>
            </exclusions>
</dependency>

满心欢喜的继续执行单元测试用例,得到的结果依然如下:

Caused by: java.lang.VerifyError: class net.sf.cglib.core.DebuggingClassWriter overrides final method visit.(IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
	at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
	at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
	at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	at net.sf.cglib.core.AbstractClassGenerator.<init>(AbstractClassGenerator.java:38)
	at net.sf.cglib.core.KeyFactory$Generator.<init>(KeyFactory.java:127)
	at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:112)
	at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:108)
	at net.sf.cglib.beans.BeanMap$Generator.<clinit>(BeanMap.java:64)
	at com.alibaba.excel.util.BeanMapUtils.create(BeanMapUtils.java:26)
	at com.alibaba.excel.write.executor.ExcelWriteAddExecutor.addJavaObjectToExcel(ExcelWriteAddExecutor.java:144)

步骤3:既然已经排除了asm:5.0.4,为什么还会报这个错误呢?从报错的class net.sf.cglib.core.DebuggingClassWriter overrides final method visit.可以看到,DebuggingClassWriter重写的方法有问题,直接打开DebuggingClassWriter的源码,发现其继承自 ClassWriter,继续查看ClassWriter,这个时候惊掉了我的下巴,见下图:

 加载的ClassWriter居然是accessors-smart-1.1.jar里面的,而不是我的直觉中asm-3.1.jar的ClassWriter,见下图:

不得不说,神奇的accessors-smart-1.1.jar,超出我的想象。既然1.1的不行,升级一下该jar吧,升级到1.2看看是否OK,pom.xml里面增加:

        <dependency>
            <groupId>net.minidev</groupId>
            <artifactId>accessors-smart</artifactId>
            <version>1.2</version>
            <scope>test</scope>
        </dependency>

打开1.2的内容,发现其移除了org.objectweb.asm相关的代码,见下图:

 accessors-smart-1.2.jar依赖了asm-5.0.4.jar,将其排除,最终的pom.xml如下:

        <dependency>
            <groupId>net.minidev</groupId>
            <artifactId>accessors-smart</artifactId>
            <version>1.2</version>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <artifactId>asm</artifactId>
                    <groupId>org.ow2.asm</groupId>
                </exclusion>
            </exclusions>
        </dependency>

再次运行单元测试用例,终于跑通过了。

总结:

1、对比差异,从差异中找到问题的关键,线上可以,单元测试不行,那肯定是单测的地方引入了问题

2、深入代码,看看加载的类具体是哪个jar里面的,找到问题的根因

3、升级相关的jar并排除相关依赖,最终问题解决。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot是一个基于Spring框架的快速开发框架,它可以帮助开发者快速搭建基于Spring的Web应用程序。而EasyExcel是一个基于Java的Excel操作工具,它可以帮助开发者快速读写Excel文件。在Spring Boot中使用EasyExcel可以方便地将数据写入Excel文件,并且可以写入多个sheet页。 具体实现步骤如下: 1. 在pom.xml文件中添加EasyExcel的依赖。 2. 创建实体类,用于存储要写入Excel文件的数据。 3. 使用EasyExcel.write创建ExcelWriter对象,并指定文件名和Java对象类型。 4. 使用sheet方法指定sheet页名称。 5. 调用ExcelWriter的write方法将数据写入Excel文件。 下面是一个示例代码,演示如何使用EasyExcel在Spring Boot中写入多个sheet页的数据: ``` // 定义实体类 public class User { private String name; private int age; // 省略getter和setter方法 } // 在Controller中定义写入Excel文件的方法 @GetMapping("/export") public void export(HttpServletResponse response) throws IOException { // 设置响应头 response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); response.setHeader("Content-disposition", "attachment;filename=user.xlsx"); // 创建ExcelWriter对象 OutputStream out = response.getOutputStream(); ExcelWriter writer = EasyExcel.write(out, User.class).build(); // 写入第一个sheet页 List<User> userList1 = new ArrayList<>(); userList1.add(new User("张三", 20)); userList1.add(new User("李四", 25)); writer.write(userList1, EasyExcel.writerSheet(0, "Sheet1").build()); // 写入第二个sheet页 List<User> userList2 = new ArrayList<>(); userList2.add(new User("王五", 30)); userList2.add(new User("赵六", 35)); writer.write(userList2, EasyExcel.writerSheet(1, "Sheet2").build()); // 关闭ExcelWriter对象 writer.finish(); } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值