fastjson解析自定义get方法导致空指针问题

这篇具有很好参考价值的文章主要介绍了fastjson解析自定义get方法导致空指针问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

背景

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

问题复现

示例代码

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));
}

错误提示
fastjson解析自定义get方法导致空指针问题,java,开发语言
发现是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);
        }
    }

fastjson解析自定义get方法导致空指针问题,java,开发语言
再到 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);
}

fastjson解析自定义get方法导致空指针问题,java,开发语言

在 buildBeanInfo 中,由于入参 fieldBased 是false,会走到 computeGetters 的逻辑:

List<FieldInfo> fieldInfoList = fieldBased
                ? computeGettersWithFieldBase(beanType, aliasMap, false, propertyNamingStrategy) //
                : computeGetters(beanType, jsonType, aliasMap, fieldCacheMap, false, propertyNamingStrategy);

fastjson解析自定义get方法导致空指针问题,java,开发语言

看到 computeGetters 的名字,感觉八成是这里了,发现里面有一段逻辑是扫描以 get 开头的方法名,把方法后缀变成一个属性,后续在获取对应属性时,会去运行对应的 getter 方法:

if(methodName.startsWith("get")){
    // 省略...
    // 从方法名中解析出属性名
    propertyName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
}

fastjson解析自定义get方法导致空指针问题,java,开发语言
fastjson解析自定义get方法导致空指针问题,java,开发语言

从上面这段代码可以获取到 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、阿里巴巴开发规约
fastjson解析自定义get方法导致空指针问题,java,开发语言

2、默认根据get方法进行序列化,根据java bean的定义,通过反射来获取,javaBean定义见:什么是JavaBean、bean?文章来源地址https://www.toymoban.com/news/detail-836695.html

到了这里,关于fastjson解析自定义get方法导致空指针问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 使用java.util.List的containsAll()方法可能导致的问题

    今天在偶然之间发现了一个bug,原因居然是使用了containsAll()方法,这个问题很简单,看以下代码就能发现很大的问题。 上面的结果最后一行打印的是true,因为containsAll()方法的作用类似于遍历指定的集合c,通过contains()比较集合中每个元素,如果有元素不包含在当前的list对象

    2024年02月14日
    浏览(59)
  • 微信小程序左上角home图标的解决方法之一 层级混乱导致的home图标显示的问题 自定义左上角左侧图标的返回路径

    这个项目的编辑页在tabbar上 导致跳到tabbar得使用wx.switchTab 保存后返回原来的页面就出现了左上角的home图标 本来想通过自定义home图标的跳转路径来解决这个问题 没想到居然找不到相关内容 有清楚的朋友麻烦给我留个言不胜感激 那我写一下我的骚操作   这就是观察记录页面

    2024年02月11日
    浏览(59)
  • SpringCloud + SpringGateway 解决Get请求传参为特殊字符导致400无法通过网关转发的问题

    title: “SpringCloud + SpringGateway 解决Get请求传参为特殊字符导致400无法通过网关转发的问题” createTime: 2021-11-24T10:27:57+08:00 updateTime: 2021-11-24T10:27:57+08:00 draft: false author: “Atomicyo” tags: [“tomcat”] categories: [“java”] description: “SpringCloud + SpringGateway 解决Get请求传参为特殊字符导致

    2024年02月07日
    浏览(47)
  • JAVA - fastjson 中 JSONObject 的顺序问题

    目录 1. JSONObject  存在的默认排序问题一 1.1. 解决方案一 1.2. 解决方案二 2. JSONObject  存在的默认排序问题二 2.1. 解决方案一 2.2. 解决方案二 在使用 fastjson 中的 JSONObject 有时候会遇到数据顺序发生了变化,而实际需求中需要保持原有的顺序。 JSONObject 初始化时候顺序直接变

    2024年02月01日
    浏览(31)
  • FastJson序列化导致的 “$ref“

    前言: 刚转后端没多久,在通过 RPC 调用其他组的服务的时候,其他组对接的同学说,你的入参是有问题的,然后他把入参发我,类似于下面的 json : 这个对象包含一个 addressMO 和 brotherMO 以及 name 和 age , brotherMO 中也包含了 addressMO ,就会导致 出现上面的 \\\"$ref\\\": \\\"$.addressMO

    2024年02月02日
    浏览(38)
  • 【Java 笔记】使用Fastjson2时,对象转json首字母大小写问题

    开发环境: 一、JSON 转 Object 1.问题: 2.解决方案 二、Object转 JSON 三、SpringBoot设置fastjson2 为默认 pom.xml 2. 配置类 四、FastJson2 注解 默认 2. @JSONType 类注解 3. @JSONField(name = \\\"othername\\\") 属性注解 五、思考问题 Java 对象为什么需要序列化? 为什么对象没有实现Serializable接口,也可以

    2024年02月16日
    浏览(53)
  • 一次有关 DNS 解析导致 APP 慢的问题探究

    目录 一、业务背景 二、 问题 三、问题排查 3.1、问题一: 基于DNS 延迟的解析 3.2、问题二:HTTPDNS侧 HTTPDNS基础理论 相关问题 四、优化方向 4.1、域名解析配置 4.2、靠近 HTTPDNS 服务端层 4.3、靠近用户层 五、扩展 5.1、如何测试本地到权威DNS服务器 获取域名的时间 5.2、 同地区

    2024年02月08日
    浏览(49)
  • 【Java】“com.alibaba.fastjson.JSONObject cannot be cast to“报错问题

    报错如下: 通过 debug 断点可以看到,这里拿到虽然是 List,但是里面的对象还是一个 JSONObject,并不是需要的 DTO 类,所有导致了后面的报错。 查到问题根源,只要把这里的对象转化为 DTO 类就行了,就可以避免报错。 增加代码: 我的json \\\"[{},{}]\\\" 已经存为字符串所以改写这样

    2024年02月13日
    浏览(56)
  • Java后端返回的MySQL日期数据在前端格式错误的解决方法,区分jackson和fastjson

    在写web项目的时候经常会遇到后端返回的MySQL 日期数据(date) 类型在前端显示不正确的情况,有的时候会出现一串数字的时间戳,有的时候显示为日期晚了一天。 这是因Json给前端返回数据的时候格式问题造成的 其实总结起来就是一句话在Model部分对于JavaBean定义参数类型的时

    2024年02月03日
    浏览(44)
  • Quartz自定义的Job使用@Autowire提示空指针问题

    一. 问题描述 在我们的自定义的Job类中,想用@Autowire注入属性,但该属性为空 public class MyJob implements Job {     @Autowired     private RabbitTemplate rabbitTemplate;     @Override     public void execute(JobExecutionContext context) throws JobExecutionException {         // Job中需要执行的方法         Sy

    2024年02月13日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包