几点说明:
- 我所在的项目密级很高,所以我需要项目相关的信息打码,抱歉更无法提供项目源码(更新,已经提供了一份脱敏的源码)
- 我会尽量用描述的方式描述清楚问题,并给出自己的分析过程
环境: java 8 fastjson 1.2.61(1.2.58也试过)
背景: 我们有一个类SkDto.java,这个类的字段比较多,且含有一些内部static类。而且我们用lombok标注它。 我们用这种方式跑单测: str = "{}"; // 原始值不是{},此处简化下,因为{}也能复现 SkDto skDto= JSON.parseObject(str, SkDto.class);
在一次升级之后,我们增加了几个字段之后,这一行代码无法通过单测。 报错是: testcase XXXXXXXXXXXXXXX > testDTO: java.lang.VerifyError: (class: com/alibaba/fastjson/parser/deserializer/FastjsonASMDeserializer_4_SkDTO, method: deserialze signature: (Lcom/alibaba/fastjson/parser/DefaultJSONParser;Ljava/lang/reflect/Type;Ljava/lang/Object;I)Ljava/lang/Object;) Illegal target of jump or branch
我们给SkDTO.java删字段,发现删除long类型的一个成员变量之后,仍然无法工作。但是删除一个Arraylist类型的成员变量 或者随便多删除几个成员变量之后,即可工作。所以猜测我们是超出了某个大小限制,只有把类缩减到这个限制以下之后,才能工作。 这个限制不是简单的数量限制,因为删除一个long类型的成员变量 和删除一个Arraylist类型的成员变量 的结果不同。
开始验证猜测:
分别打开两个IDE,一个IDE用有问题的SkDTO.java,一个IDE用“删除一个Arraylist类型的成员变量 ”之后的SkDTO.java。
JSON.java 560行:return parseObject(text, clazz, new Feature[0]); 调用了
JSON.java 383行:T value = (T) parser.parseObject(clazz, null); 调用了
DefaultJSONParser.java 673行: ObjectDeserializer deserializer = config.getDeserializer(type); 调用了
ParseConfig.java 411行:return getDeserializer((Class<?>) type, type); 调用了 ParseConfig.java 678行:deserializer = createJavaBeanDeserializer(clazz, type); 调用了
ParseConfig.java 840行:return asmFactory.createJavaBeanDeserializer(this, beanInfo); 调用了
ASMDeserializerFactory.java 89-90行: Class<?> deserClass = classLoader.defineClassPublic(classNameFull, code, 0, code.length); Constructor<?> constructor = deserClass.getConstructor(ParserConfig.class, JavaBeanInfo.class);
在此之前,两个IDE的debug都看不出来明显区别,在这里出现了完全不同的反应:
其中一个IDE在90行抛出了异常。
分别在两个IDE的第90行打断点:
比较两个class,发现两个ASM类有明显不同,一个有构造函数,一个没有:
看构造的过程,都是ClassLoader的,唯一区别就是传入的参数:

本行之上都是描述事实,本行之下是猜想内容:
- 当类大小比较大的时候,或者触发了某个条件,ASM生成的字节码不正常。
- 当一个类的大小超过64K时候,用protected final Class<?> defineClass(String name, byte[] b, int off, int len, ProtectionDomain protectionDomain)生成的类和ASMSerializerFactory配合的不好;
我查了不少资料,我和这位朋友的状态非常相似: https://github.com/alibaba/fastjson/issues/1207
和这个帖子里面的评论的朋友也有一些相似,但是不完全相同: https://github.com/alibaba/fastjson/issues/1092 我的症状是只能减字段才能解决,不能加字段;他的症状是增减字段都能解决