问题引申
使用javassist 动态生成了一个类,通过IDEA运行没有任何问题,但是通过IDEA JUnit运行则报VerifyError异常。
案发现场
代码如下:
//模拟代码0
public interface SharpHelper {
Object run(String group, String name,int timeout, Callable callable);
Object run(String group,int timeout,Callable callable);
}
//模拟代码1
public interface AppleService {
String get(String value);
}
//模拟代码2
public class C1 implements Callable{
private AppleService target;
public Object call() throws Exception {
java.lang.String result = null;
result = target.get(this.args0);
return result;
}
public void setTarget(AppleService target) {
this.target = target;
}
public void setParam(java.lang.String args0) {
this.args0 = args0;
}
}
//模拟代码3
public class C2 implements AppleService {
private AppleService target;
@Autowired
private SharpHelper sharp;
public java.lang.String get(String args0){
try {
C1 callable = new C1();
callable.setTarget(this.target);
callable.setParam(args0);
//return (java.lang.String)sharp.run("goods","",10000,callable);
//在使用 javassist 3.27.0-GA 编译可以通过,并且正常运行,当然这样的代码是不对的
//但是也正常运行了,
return sharp.run("goods","",10000,callable);
} catch (Exception e) {
throw e;
}
}
}
但是使用JUnit运行,则无法启动,提示VerifyError异常。
通过类加载机制,原因是触发了类加载机制中的校验 原文链接:类加载机制-深入理解jvm - 简书,错误的源代码无法校验通过。 原文链接:类加载机制-深入理解jvm - 简书
![](https://img-blog.csdnimg.cn/img_convert/e003bfdf2c53c6692efba22e083bd8fd.png)
通过查阅IDEA 启动项目后的JVM参数(通过jdk工具 jps)
执行命令:jps -v
16580 ProductApplication
-XX:TieredStopAtLevel=1
-Xverify:none
-Dspring.output.ansi.enabled=always
-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2021.1.3\lib\idea_rt.jar=49400:C:\P
rogram Files\JetBrains\IntelliJ IDEA 2021.1.3\bin
-Dcom.sun.management.jmxremote
-Dspring.jmx.enabled=true
-Dspring.liveBeansView.mbeanDomain
-Dspring.application.admin.enabled=true
-Dfile.encoding=UTF-8
参数释义
-Xverify[:<option>]
如果不使用任何参数,那么将启用验证器,这是缺省值。 因此,如果单独使用而不带任何参数,如 -Xverify,那么此选项将不执行任何操作。可选参数如下所示:
- all - 启用最完整的验证
- none - 禁用验证器
- remote - 对远程装入的类启用严格的类装入检查
缺省情况下,验证器处于开启状态,必须针对所有生产服务器启用验证器。不支持在关闭验证器的情况下运行。 如果遇到问题,并且使用 -Xverify:none 关闭了验证器,那么请除去此选项并尝试重现问题。
查阅JUnit下的JVM 参数
5840 JUnitStarter
-agentlib:jdwp=transport=dt_socket,address=127.0.0.1:50452,suspend=y,server=n
-ea
-Didea.test.cyclic.buffer.size=1048576
-javaagent:C:\Users\jiangj\AppData\Local\JetBra
ins\IntelliJIdea2021.1\captureAgent\debugger-agent.jar
-Dfile.encoding=UTF-8
没有发现-Xverify参数的定义,那么默认将启用检验,所以错误的源代码无法运行,会抛出VerifyError异常。
解决方案
1.Junit 下增加 JVM 参数 -noverify(强烈建议加最后) 关闭类的校验
2.书写正确的源代码(这个坑其实是BUG产生的)
疑惑
为什么错误的源代码在-Xverify:none下依然可以运行?
本人猜测:因为java关闭了类的校验,所以代码不严谨(例如类型不严谨)的问题就被略去了,JAVA本身实现一些特性靠的就是剑走偏锋(例如泛型)。只要运行时是能过关的,很多问题人们可能就也不会去追究了。
之前本人还遇到过,声明的变量为List<Student> 的集合。内部实际装载的是List<JSONObject>
运行也没问题,因为泛型擦除后所有List 内部都是Object。
当然这样的异常效果都是运行时才能得到(通过javassist骚操作),这个例子似乎好像可以解释,为什么源代码都有误,但是不影响运行,姑且这样信下去,直到有一天,产生新的认知。