fastjson解析自定义get方法导致空指针问题
背景
为了在日志中把出入参打印出来,以便验证链路和排查问题,在日志中将入参用fastjson格式化成字符串输出,结果遇到了NPE。

问题复现
示例代码
public static void main(String[] args) {OrganizationId orgId = new OrganizationId();NodeName name = new NodeName("test");Node node = new Node();node.setName(name);node.setOrganizationId(orgId);System.out.println(JSONObject.toJSONString(node));
}
错误提示

发现是OrganizationId对象里的方法报空指针了,赶紧看一眼这个类:
public class OrganizationId {private String id;public Long getIdToLong() {return Long.valueOf(this.id);}
}
怎么会运行到 getIdToLong 方法呢?
问题排查
对 JSONObject.toJSONString 方法进行反复 debug 之后,终于发现了原因,以下是具体路径:
public static String toJSONString(Object object, SerializeConfig config, SerializeFilter[] filters, String dateFormat,int defaultFeatures, SerializerFeature... features) {SerializeWriter out = new SerializeWriter(null, defaultFeatures, features);try {JSONSerializer serializer = new JSONSerializer(out, config);if (dateFormat != null && dateFormat.length() != 0) {serializer.setDateFormat(dateFormat);serializer.config(SerializerFeature.WriteDateUseDateFormat, true);}if (filters != null) {for (SerializeFilter filter : filters) {serializer.addFilter(filter);}}serializer.write(object);return out.toString();} finally {out.close();}
}
往下到 serializer.write 方法:
public final void write(Object object) {if (object == null) {out.writeNull();return;}Class<?> clazz = object.getClass();ObjectSerializer writer = getObjectWriter(clazz);try {writer.write(this, object, null, null, 0);} catch (IOException e) {throw new JSONException(e.getMessage(), e);}}

再到 getObjectWriter,注意入参create传了true:
public ObjectSerializer getObjectWriter(Class<?> clazz) {return getObjectWriter(clazz, true);
}
在 getObjectWriter 的核心具体实现中,走到了自定义对象序列化的流程:
// ......
if (create) {writer = createJavaBeanSerializer(clazz);put(clazz, writer);
}
createJavaBeanSerializer 往下到 TypeUtils.buildBeanInfo:
public final ObjectSerializer createJavaBeanSerializer(Class<?> clazz) {SerializeBeanInfo beanInfo = TypeUtils.buildBeanInfo(clazz, null, propertyNamingStrategy, fieldBased);if (beanInfo.fields.length == 0 && Iterable.class.isAssignableFrom(clazz)) {return MiscCodec.instance;}return createJavaBeanSerializer(beanInfo);
}

在 buildBeanInfo 中,由于入参 fieldBased 是false,会走到 computeGetters 的逻辑:
List<FieldInfo> fieldInfoList = fieldBased? computeGettersWithFieldBase(beanType, aliasMap, false, propertyNamingStrategy) //: computeGetters(beanType, jsonType, aliasMap, fieldCacheMap, false, propertyNamingStrategy);

看到 computeGetters 的名字,感觉八成是这里了,发现里面有一段逻辑是扫描以 get 开头的方法名,把方法后缀变成一个属性,后续在获取对应属性时,会去运行对应的 getter 方法:
if(methodName.startsWith("get")){// 省略...// 从方法名中解析出属性名propertyName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
}


从上面这段代码可以获取到 propertyName 的值为 idToLong,并且对应的 fieldInfo 是 getIdToLong 方法。
到这里基本水落石出了,原来是fastjson序列化是扫描以 “get”(还有“is”) 开头的方法,并且从该方法名中提取属性,如果对应的方法中存在问题,那么这里就可能遇到对应的异常,就像本文遇到的NPE。
解决方案
1、 业务逻辑中处理:保证 node 对象中的 orgId 不为空,避免NPE。
2、日志打印中处理:不序列化整个对象,只打出关键信息,避开可能为空的字段。
3、 在调用JSON.toJSONString的时候,加上SerializerFeature.IgnoreNonFieldGetter参数,忽略掉所有没有对应成员变量(Field)的getter函数,可以正常序列化。
JSONObject.toJSONString(node, SerializerFeature.IgnoreNonFieldGetter)
4、 通过在函数上 getXxx() 增加@JSONField(serialize = false)注解,也能达到同样的效果。
@JSONField(serialize = false)
public Long getIdToLong() {return Long.valueOf(this.id);
}
computeGetters 中消费注解的代码:
JSONField annotation = method.getAnnotation(JSONField.class);// ...if(annotation != null){if(!annotation.serialize()){continue;}// ...if(methodName.startsWith("get")){
// ...
总结
fastjson 将对象转为 string 时,会把以“get”开头的方法认为是属性的 getter,把 getXXX 方法后面的 XXX 变成一个属性,并通过 getXXX 方法去获取,如果get方法内存在异常逻辑,就可能报错。可以尽量避免使用JSON打日志。
附录
1、阿里巴巴开发规约

2、默认根据get方法进行序列化,根据java bean的定义,通过反射来获取,javaBean定义见:什么是JavaBean、bean?
相关文章:
fastjson解析自定义get方法导致空指针问题
背景 为了在日志中把出入参打印出来,以便验证链路和排查问题,在日志中将入参用fastjson格式化成字符串输出,结果遇到了NPE。 问题复现 示例代码 public static void main(String[] args) {OrganizationId orgId new OrganizationId();N…...
github新手用法详解
GitHub是一个非常强大的版本控制工具,它为程序员提供了一个便捷的方式来管理代码、协作开发和参与开源项目。但对于新手来说,可能会觉得GitHub的使用有些复杂。因此,本篇文章将详细介绍GitHub的基本用法,帮助新手快速上手并充分利…...
MAC电脑系统清理空间免费版软件CleanMyMac X2024
大家好,我是那个总是被苹果电脑“内存已满”提示搞得焦头烂额的专业博主。如果你也像我一样,在使用Mac时经常遭遇卡顿、慢吞吞的情况,那么今天的Mac清理空间妙招分享绝对适合你! CleanMyMac X全新版下载如下: https://wm.makedi…...
notepad++运行python闪一下就没啦
问题:Notepad直接快捷键运行Python代码,出现闪一下就没了 解决措施: ①点击菜单运行(Run) --> 运行(Run)弹出的对话框 ②把 cmd /k python "$(FULL_CURRENT_PATH)" & ECHO. & PAUSE & EXIT 粘贴进入这个对话框内 ③点击保存&a…...
基于springboot+vue的课程答疑系统(前后端分离)
博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战,欢迎高校老师\讲师\同行交流合作 主要内容:毕业设计(Javaweb项目|小程序|Pyt…...
【工具类】非 sudo 运行 docker
非 root 运行 docker 命令 sudo groupadd docker sudo usermod -aG docker $USER newgrp docker sudo chown root:docker /var/run/docker.sock sudo chown "$USER":"$USER" /home/"$USER"/.docker -R sudo chmod grwx "$HOME/.docker&quo…...
力扣49.字母异位词分组
题目描述: 49. 字母异位词分组 难度 中等 给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 1: 输入: strs ["eat", "tea"…...
git操作--->在远程删除了某个分支,但本地使用git branch -r的时候还是会显示某个分支存在是什么原因
💕又迷糊了哈哈,以为自己命令执行错了,结果可能是缓存的原因:💕 😂如果你发现使用 git branch -r 命令显示了一个远程没有的分支,这可能是由以下几个原因造成的:😂 缓存…...
合并Windows电脑的不同分区(不同的盘)的方法
本文介绍在Windows操作系统的电脑中,将磁盘上的不同分区(例如E盘与F盘)加以合并的方法。 最近,想着将新电脑的2个分区加以合并;如下图所示,希望将E盘与F盘合并为一个分区。本文就介绍一下实现这一需求的具体…...
web前端安全性——iframe安全问题
1、概念 iframe安全问题可称作界面劫持,像点击劫持、拖放劫持、触屏劫持。就是我们的点击,拖放,触屏操作被劫持了,而去操作了其它的透明隐藏的界面。 **原理是利用透明层iframe,使用了CSS中的opacity或z-index等属性,…...
从零开始学习Netty - 学习笔记 - NIO基础 - 网络编程: Selector
4.网络编程 4.1.非阻塞 VS 阻塞 在网络编程中,**阻塞(Blocking)和非阻塞(Non-blocking)**是两种不同的编程模型,描述了程序在进行网络通信时的行为方式。 阻塞(Blocking)࿱…...
useRef有什么用?
看一下官网定义 useRef是一个React Hook,它能帮助引用一个不需要渲染的值 这句话透露出一个信息,不需要渲染的值可以用useRef引用,那需要渲染的值用什么引用呢?当然是useState了,需要渲染的值指的就是状态嘛࿰…...
vue3中,ref()、reactive()、computed()、watch() 和 watchEffect()的区别
ref()、reactive()、computed()、watch() 和 watchEffect() 是 Vue 3 中常用的响应式处理函数,它们的主要区别如下: ref():ref() 函数用于将一个普通的 JavaScript 值转化为响应式对象。它返回一个具有 value 属性的对象,我们可以…...
Java基于SpringBoot的校园轻博客系统,附源码
博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…...
webstorm光标变成方块解决办法_webstorm光标变粗不能换行
webstorms光标变了 键盘上的insert是切换的快捷键,敲insert就可以来回切换了...
从计网的角度讲明白什么是网关
网关(Gateway)又称网间连接器、协议转换器。网关在传输层上以实现网络互连,是最复杂的网络互连设备,仅用于两个高层协议不同的网络互连。网关的结构也和路由器类似,不同的是互连层。网关既可以用于广域网互连,也可以用于局域网互连…...
如何选择最适合的图纸加密软件?安秉网盾软件用户体验及性价比
安秉网盾图纸加密软件是一款功能强大的图纸加密工具,具有以下特点和优势: 全盘加密:安秉网盾采用先进的加密算法,能对文件、文件夹、磁盘等数据进行全面加密,确保数据在存储和传输过程中的安全性。 监控与审计&#x…...
Spring Security学习(六)——配置多个Provider(存在两种认证规则)
前言 《Spring Security学习(五)——账号密码的存取》一文已经能满足一般应用的情况。但实际商业应用也会存在如下的情况:用户提交的账号密码,能在本地的保存的账号密码匹配上,或者能在远端服务认证中匹配上ÿ…...
Js如何判断两个数组是否相等?
本文目录 1、通过数组自带方法比较2、通过循环判断3、toString()4、join()5、JSON.stringify() 日常开发,时不时会遇到需要判定2个数组是否相等的情况,需要实现考虑的场景有: 先判断长度,长度不等必然不等元素位置其他情况考虑 1…...
Salesforce顾问如何拿到更高的薪水?
顾问的角色已经在Salesforce生态系统存在了一段时间,随着Salesforce针对职业发展的Trailhead培训模块的发布,该角色的热度又达到了新的浪潮。越来越多人走上了Salesforce顾问这条职业道路。 当然其薪资水平也非常可观,据调查,美国…...
关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...
基于单片机的宠物屋智能系统设计与实现(论文+源码)
本设计基于单片机的宠物屋智能系统核心是实现对宠物生活环境及状态的智能管理。系统以单片机为中枢,连接红外测温传感器,可实时精准捕捉宠物体温变化,以便及时发现健康异常;水位检测传感器时刻监测饮用水余量,防止宠物…...
npm安装electron下载太慢,导致报错
npm安装electron下载太慢,导致报错 背景 想学习electron框架做个桌面应用,卡在了安装依赖(无语了)。。。一开始以为node版本或者npm版本太低问题,调整版本后还是报错。偶尔执行install命令后,可以开始下载…...
多模态学习路线(2)——DL基础系列
目录 前言 一、归一化 1. Layer Normalization (LN) 2. Batch Normalization (BN) 3. Instance Normalization (IN) 4. Group Normalization (GN) 5. Root Mean Square Normalization(RMSNorm) 二、激活函数 1. Sigmoid激活函数(二分类&…...
