记一次FastJson报错

文章目录

  • 报错内容
  • 原因探寻
  • 原因及解决方案

报错内容

起因是一段很普通的字符串转Java对象的代码,在本地和内网测试都没有问题,偏偏外网一跑就报错,错误如下:
在这里插入图片描述
报错的代码特别简单,涉及到公司代码这里用测试代码演示,就是将Json字符串转成java对象,示例代码:

List<PojoTest> list = JSONObject.parseObject(json, new TypeReference<>() {});
PojoTest pojo = JSONObject.parseObject(json, PojoTest.class);

PojoTest就是一个特别简单的类:

public class PojoTest {private long id;private int sn;private int num;public PojoTest(long id){this.id = id;}public  boolean isGood(){return id > 100;}public long getId() {return id;}public void setId(long id) {this.id = id;}public int getSn() {return sn;}public void setSn(int sn) {this.sn = sn;}public int getNum() {return num;}public void setNum(int num) {this.num = num;}
}

一个没有默认构造函数的简单对象.

原因探寻

翻看错误日志,可以找到最终报错的代码是ASM试图读取一个class源文件,执行ClassReader构造函数,报了数组越界,ClassReader构造函数源码如下:

    public ClassReader(InputStream is) throws IOException {{//is是class文件的二进制流//这个大括号内的代码是把二进制流读取到this.b的byte数组内ByteArrayOutputStream out = new ByteArrayOutputStream();byte[] buf = new byte[1024];for (; ; ) {int len = is.read(buf);if (len == -1) {break;}if (len > 0) {out.write(buf, 0, len);}}is.close();this.b = out.toByteArray();}//items数组存放的是Class的常量池items = new int[readUnsignedShort(8)];int n = items.length;strings = new String[n];// parses the constant poolint max = 0;int index = 10;try {//这个for循环就是根据class文件的二进制数组读取常量池并且存放到items数组中for (int i = 1; i < n; ++i) {items[i] = index + 1;int size;switch (b[index]) {//报错的就是这一行,index过大导致数组越界case 9: // FIELD:case 10: // METH:case 11: //IMETH:case 3: //INT:case 4: //FLOAT:case 18: //INVOKEDYN:case 12: //NAME_TYPE:size = 5;break;case 5: //LONG:case 6: //DOUBLE:size = 9;++i;break;case 15: //MHANDLE:size = 4;break;case 1: //UTF8:size = 3 + readUnsignedShort(index + 1);if (size > max) {max = size;}break;// case HamConstants.CLASS:// case HamConstants.STR:default:size = 3;break;}index += size;}} catch (Exception e) {System.out.println("加载class报错,className:");throw e;}maxStringLength = max;// the class header information starts just after the constant poolheader = index;} 

关于字节码相关知识可以查看之前的文章字节码详解.
通过源码可以看出ClassReader初始化报错的代码并没有做其他操作,只是要把class文件对应的常量池读取出来,而读取常量池这个操作也没有任何问题。因为字节码技术保证生成的class文件需要跨平台使用,达到一次编译,到处运行的效果,所以class文件的读取解析方式不会因为平台不同而出现字段不同含义的情况。这个不同平台包括windows与Linux操作系统的不同,也包括大小端的不同,class不管什么样的平台编译,都只会以大端形式存储。
也就是说,只要class正常编译后,都是可以按照大端顺序通过字节顺序读取出来,那上面的报错就只能是class文件格式被修改导致的。

原因及解决方案

开发者本地环境和内网环境之所以没有报错,是因为使用的都是原始的class文件,而为了保证代码安全性,公司运维会在拉取项目jar包时对jar包进行加密,运行时加上-agent解密保证项目本身可以稳定运行。但是对于第三方直接拉取class二进制并按照原始顺序去解析的行为就不支持了,因为加密行为是公司层面为了杜绝代码外泄而进行的,所以不会因为这个报错而选择不加密。
目前最简单的解决方案是:通过修改代码,json转换时确保FastJson不会走asm相关读取class文件的逻辑,比如先将String转成JsonObject对象,再读取对象相关属性赋值到自己的类中,或者保证要转换的java对象有默认构造函数,如例子中的PojoTest类,加上默认构造函数后便不会再报错。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/174772.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

循环服务器

一、服务器模型 在网络程序里面,通常都是一个服务器处理多 个客户机。为了处理多个客户机的请求, 服务器端的程序有不同的处理方式。 1、循环服务器模型 socket()&#xff1b; bind(); liste(); while(1) { accept(); while(1) { recv ret0; break; } close(acceptfd); } close…

【C++11/高级语法】bind绑定器和function函数对象

目录 bind1st和bind2nd什么时候会用到bind1st和bind2nd的底层实现原理function函数对象类型的应用示例lambda表达式的应用实践 橙色 绑定器和函数对象operator() 函数对象就是对象拥有()运算符重载函数&#xff0c;这个对象使用起来就跟函数调用特别相似。 1.C STL中的绑定器…

前端学习笔记--面试题系列总结

event loop它的执行顺序&#xff1a; 一开始整个脚本作为一个宏任务执行执行过程中同步代码直接执行&#xff0c;宏任务进入宏任务队列&#xff0c;微任务进入微任务队列当前宏任务执行完出队&#xff0c;检查微任务列表&#xff0c;有则依次执行&#xff0c;直到全部执行完执…

Hadoop入门——数据分析基本步骤

文章目录 1.概述2.分析步骤2.1第一步 明确分析目的和思路2.2第二步 数据收集2.3第三步 数据处理2.4第四步 数据分析2.5第五步 数据展现2.6第六步 报告撰写 3.总结 1.概述 2.分析步骤 2.1第一步 明确分析目的和思路 2.2第二步 数据收集 2.3第三步 数据处理 2.4第四步 数据分析 …

如何使用Docker搭建Drupal内容管理系统并远程访问

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525;个人专栏:《Linux深造日志》《C干货基地》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 前言1. Docker安装Drupal2. 本地局域网访问3 . Linux 安装cpolar4. 配置Drupal公网访问地址5. 公网远程访问Drupal…

Kakaotalk如何注册?常见问题解答

kakaoTalk是一款韩国即时通讯软件&#xff0c;使用程度类似于国内的微信&#xff0c;他还包含叫车服务、食品外送、餐厅预订、支付和游戏等多种功能&#xff0c;几乎每个韩国人都在使用KakaoTalk。 因此&#xff0c;对于要发展韩国市场的独立站人&#xff0c;这款软件必定是营…

人大金仓物理备份异机恢复

概述 KingbaseES V8支持使用RMAN物理备份在异机环境恢复&#xff0c;通过重新克隆方式完扩展主备集群。 原集群环境&#xff1a;演示用例&#xff0c;仅供参考 查看原集群备份和物理备份路径 异机恢复 前置条件 *获取原集群物理备份文件&#xff0c;包括全量备份、增量备份…

Java项目maven打包,打jar包中不包含项目引用第三方jar包,以及打war包不能将其放到lib的问题

在使用maven进行打包项目中&#xff0c;想要将第三方的jar包放入&#xff0c;有两种方法&#xff1a;一种将jar包上传到maven库中&#xff0c;第二种再pom.xml中进行配置&#xff0c;第三种 情况是需要打包成war包放入tomcat中&#xff1b;具体如下&#xff1a; 第一种&#x…

nacos集群配置(超完整)

win配置与linux一样&#xff0c;换端口或者换ip&#xff0c;文章采用的 linux不同IP&#xff0c;同一端口 节点ipportnacos1192.168.253.168848nacos2192.168.253.178848nacos3192.168.253.188848 单IP多个端口 1.复制两个&#xff0c;重命名 2.修改 conf目录下的 application…

Ubuntu 20.04编译Chrome浏览器

本文记录chrome浏览器编译过程&#xff0c;帮助大家避坑qaq 官网文档&#xff1a;https://chromium.googlesource.com/chromium/src//main/docs/linux/build_instructions.md 一.系统要求 一台64位的英特尔机器&#xff0c;至少需要8GB的RAM。强烈推荐超过16GB。至少需要100…

淘宝京东优惠券信息API接口系列

获取淘宝优惠券信息接口需要使用淘宝开放平台提供的API接口。以下是获取优惠券信息的步骤&#xff1a; 进入淘宝开放平台&#xff0c;注册并登录账号。在开放平台页面中&#xff0c;找到“优惠券”或“营销工具”等相关的API接口&#xff0c;根据需要进行选择。根据接口文档&a…

Java 设计模式——组合模式

目录 1.概述2.结构3.实现3.1.抽象构件3.2.容器构件3.3.叶子节点3.4.测试 4.分类5.使用场景6.优点 1.概述 &#xff08;1&#xff09;大家对于上面这个图片肯定非常熟悉&#xff0c;上图我们可以看做是一个文件系统&#xff0c;对于这样的结构我们称之为树形结构。在树形结构中可…