java list转json报错_一个fastjson转换JSON字符串的报错排查

今天给一个java类加了几个字段,没想到转为json字符串的时候报错了,定位了一下原因,觉得这种情况遇到的应该不多,又想起来很久没写博客了,于是就把遇到的问题以及定位过程记下来,省了以后遇到的人再花时间定位了

调用的是JSON.toJSONString(Object object)方法,具体的报错信息如下:Caused by: com.alibaba.fastjson.JSONException: write javaBean error

at com.alibaba.fastjson.serializer.JavaBeanSerializer.write(JavaBeanSerializer.java:234)

at Serializer_5.write1(Unknown Source)

at Serializer_5.write(Unknown Source)

at com.alibaba.fastjson.serializer.JSONSerializer.write(JSONSerializer.java:369)

at com.alibaba.fastjson.JSON.toJSONString(JSON.java:393)

at com.alibaba.fastjson.JSON.toJSONString(JSON.java:567)

at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)

at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:689)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)

at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:55)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)

at

... 81 common frames omitted

Caused by: com.alibaba.fastjson.JSONException: create asm serializer error, class class com.feifei.bean.TestBean

at com.alibaba.fastjson.serializer.SerializeConfig.createJavaBeanSerializer(SerializeConfig.java:113)

at com.alibaba.fastjson.serializer.JSONSerializer.getObjectWriter(JSONSerializer.java:527)

at com.alibaba.fastjson.serializer.ListSerializer.write(ListSerializer.java:81)

at com.alibaba.fastjson.serializer.ObjectFieldSerializer.writeValue(ObjectFieldSerializer.java:118)

at com.alibaba.fastjson.serializer.ObjectFieldSerializer.writeProperty(ObjectFieldSerializer.java:67)

at com.alibaba.fastjson.serializer.JavaBeanSerializer.write(JavaBeanSerializer.java:216)

... 94 common frames omitted

Caused by: java.lang.ClassFormatError: JVMCFRE042 bytecode array size > 65535; class=Serializer_57, offset=53261

at java.lang.ClassLoader.defineClassImpl(Native Method)

at java.lang.ClassLoader.defineClass(ClassLoader.java:275)

at com.alibaba.fastjson.util.ASMClassLoader.defineClassPublic(ASMClassLoader.java:42)

at com.alibaba.fastjson.serializer.ASMSerializerFactory.createJavaBeanSerializer(ASMSerializerFactory.java:287)

at com.alibaba.fastjson.serializer.ASMSerializerFactory.createJavaBeanSerializer(ASMSerializerFactory.java:36)

at com.alibaba.fastjson.serializer.SerializeConfig.createASMSerializer(SerializeConfig.java:78)

at com.alibaba.fastjson.serializer.SerializeConfig.createJavaBeanSerializer(SerializeConfig.java:106)

... 99 common frames omitted

可以看到,代码在执行到ASMClassLoader.defineClassPublic这个方法时报错了,报的错是:JVMCFRE042 bytecode array size > 65535

字节数组超长,这个长度65535,很显然是长度规定了2的16次方(65536),也就是64K大小。

再来看看ASMClassLoader这个类,这个类继承了java的类装载器ClassLoader,fastjson内嵌了ASM框架来动态生成类;public class ASMClassLoader extends ClassLoader {

并且报错的方法其实就是调用了ClassLoader的类定义方法defineClass,本质上调用的是JVM的native功能public Class> defineClassPublic(String name, byte[] b, int off, int len) throws ClassFormatError {

Class> clazz = defineClass(name, b, off, len, DOMAIN);

return clazz;

}

这里其实也就是传的需要生成的类的字节码,在这里也就对应着我们需要转换成JSON串的对象类的字节码,所以这个报错应该就是对象类字节码超长了,也就是类里面的东西太多了,试着删掉这个bean里的一些变量,测试一把,果然不报错了。

那到底是什么太长了呢?这也好办,继续写个单元测试,把ASMSerializerFactory类拷出来,把字节码输出看看

单元测试:@Test

public void test(){

try{

this.asmSerial(TestBean.class);

}catch(Exception e){

System.out.println(e);

}

}

private void asmSerial(Class> clazz) throws Exception{

ASMSerializerFactory fac = new ASMSerializerFactory();

fac.createJavaBeanSerializer(clazz);

}

在拷出来的ASMSerializerFactory类的createJavaBeanSerializer方法中新增输出逻辑:byte[] code = cw.toByteArray();

// 输出class文件

File outputFile = new File("C:\\Users\\feifei\\Desktop\\ooo\\out.class");

FileOutputStream outputFileStream = null;

try {

outputFileStream = new FileOutputStream(outputFile);

} catch (FileNotFoundException e) {

}

outputFileStream.write(code);

System.out.println("code:length: " + code.length);

执行一把,果然报错了,而且class文件也成功生成了,先看看控制台输出:[TestNG] Running:

C:\Users\feifei\AppData\Local\Temp\testng-eclipse-1963807168\testng-customsuite.xml

code:length: 191423

FAILED: test

java.lang.ClassFormatError: Invalid method Code length 65904 in class file Serializer_1

at java.lang.ClassLoader.defineClass1(Native Method)

at java.lang.ClassLoader.defineClass(Unknown Source)

at com.alibaba.fastjson.util.ASMClassLoader.defineClassPublic(ASMClassLoader.java:42)

at ASMSerializerFactory.createJavaBeanSerializer(ASMSerializerFactory.java:299)

at ASMSerializerFactory.createJavaBeanSerializer(ASMSerializerFactory.java:42)

at tt.asmSerial(tt.java:19)

at tt.test(tt.java:11)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

at java.lang.reflect.Method.invoke(Unknown Source)

可见报错更加细化了java.lang.ClassFormatError: Invalid method Code length 65904 in class file Serializer_1

这个报错意思更加明显了,方法的长度不合法,这个方法的长度是65904,结合上面报出来的大于65535,那么问题就很明显了,java里规定了类的一个方法最大不能超过64K。

我们继续打开刚刚生成的class文件,可以看到,我们bean里面的字段都在里面,而里面最大的方法是write和write1,分别占13000多行,所以应该就是这两方法超长了。

d5fe78317893787ca1f4268679f715b2.png

至此,问题就定位清晰了,就是bean里面字段太多,导致序列化后,生成class文件的方法超长,也就导致转为json字符串失败了,这个除了拆分bean,貌似也没什么好办法了,而且这个bean确实太大了,拆开可读性也会好很多

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值