已解决:java.lang.RuntimeException: net.sf.json.JSONNull cannot be cast to java.lang

本文分析了json-lib在处理json字符串时,遇到null值转换为JSONObject对象时的问题,指出其使用JSONNull对象导致的问题。通过源码解析,解释了当值为null时,对象类型会变成JSONNull,从而在判断null时引发错误。解决方法包括将null替换为或更换其他json转换库。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.问题场景

在项目中json字符串转换时,一些属性为null的属性转换时报错。

2.问题原因

json字符串转换时,对值是否为null进行判断时,用的是JsonNULL对象的equals方法
在这里插入图片描述
json-lib的最新版本2.4都存在该问题。

3.代码分析

3.1JSONObject对象

net.sf.json.JSONObject实际上实现了Map接口:
在这里插入图片描述
map实际上为hashmap
在这里插入图片描述
在这里插入图片描述
首先json字符串会被解析转换。
在这里插入图片描述
传参json字符串和对应的解析规则给本身的_fromJSONTokener方法
在这里插入图片描述

3.2_fromJSONTokener方法源码
private static JSONObject _fromJSONTokener(JSONTokener tokener, JsonConfig jsonConfig) {
        try {
            if (tokener.matches("null.*")) {
                fireObjectStartEvent(jsonConfig);
                fireObjectEndEvent(jsonConfig);
                return new JSONObject(true);
            } else if (tokener.nextClean() != '{') {
                throw tokener.syntaxError("A JSONObject text must begin with '{'");
            } else {
                fireObjectStartEvent(jsonConfig);
                Collection exclusions = jsonConfig.getMergedExcludes();
                PropertyFilter jsonPropertyFilter = jsonConfig.getJsonPropertyFilter();
                JSONObject jsonObject = new JSONObject();

                while(true) {
                    while(true) {
                        char c = tokener.nextClean();
                        switch(c) {
                        case '\u0000':
                            throw tokener.syntaxError("A JSONObject text must end with '}'");
                        case '}':
                            fireObjectEndEvent(jsonConfig);
                            return jsonObject;
                        default:
                            tokener.back();
                            String key = tokener.nextValue(jsonConfig).toString();
                            c = tokener.nextClean();
                            if (c == '=') {
                                if (tokener.next() != '>') {
                                    tokener.back();
                                }
                            } else if (c != ':') {
                                throw tokener.syntaxError("Expected a ':' after a key");
                            }

                            char peek = tokener.peek();
                            boolean quoted = peek == '"' || peek == '\'';
                            Object v = tokener.nextValue(jsonConfig);
                            if (!quoted && JSONUtils.isFunctionHeader(v)) {
                                String params = JSONUtils.getFunctionParams((String)v);
                                int i = 0;
                                StringBuffer sb = new StringBuffer();

                                do {
                                    char ch = tokener.next();
                                    if (ch == 0) {
                                        break;
                                    }

                                    if (ch == '{') {
                                        ++i;
                                    }

                                    if (ch == '}') {
                                        --i;
                                    }

                                    sb.append(ch);
                                } while(i != 0);

                                if (i != 0) {
                                    throw tokener.syntaxError("Unbalanced '{' or '}' on prop: " + v);
                                }

                                String text = sb.toString();
                                text = text.substring(1, text.length() - 1).trim();
                                Object value = new JSONFunction(params != null ? StringUtils.split(params, ",") : null, text);
                                if (jsonPropertyFilter == null || !jsonPropertyFilter.apply(tokener, key, value)) {
                                    if (jsonObject.properties.containsKey(key)) {
                                        jsonObject.accumulate(key, value, jsonConfig);
                                        firePropertySetEvent(key, value, true, jsonConfig);
                                    } else {
                                        jsonObject.element(key, (Object)value, jsonConfig);
                                        firePropertySetEvent(key, value, false, jsonConfig);
                                    }
                                }
                            } else {
                                if (exclusions.contains(key)) {
                                    switch(tokener.nextClean()) {
                                    case ',':
                                    case ';':
                                        if (tokener.nextClean() == '}') {
                                            fireObjectEndEvent(jsonConfig);
                                            return jsonObject;
                                        }

                                        tokener.back();
                                        continue;
                                    case '}':
                                        fireObjectEndEvent(jsonConfig);
                                        return jsonObject;
                                    default:
                                        throw tokener.syntaxError("Expected a ',' or '}'");
                                    }
                                }

                                if (jsonPropertyFilter == null || !jsonPropertyFilter.apply(tokener, key, v)) {
                                    if (quoted && v instanceof String && (JSONUtils.mayBeJSON((String)v) || JSONUtils.isFunction(v))) {
                                        v = "\"" + v + "\"";
                                    }

                                    if (jsonObject.properties.containsKey(key)) {
                                        jsonObject.accumulate(key, v, jsonConfig);
                                        firePropertySetEvent(key, v, true, jsonConfig);
                                    } else {
                                        jsonObject.element(key, v, jsonConfig);
                                        firePropertySetEvent(key, v, false, jsonConfig);
                                    }
                                }
                            }

                            switch(tokener.nextClean()) {
                            case ',':
                            case ';':
                                if (tokener.nextClean() == '}') {
                                    fireObjectEndEvent(jsonConfig);
                                    return jsonObject;
                                }

                                tokener.back();
                                break;
                            case '}':
                                fireObjectEndEvent(jsonConfig);
                                return jsonObject;
                            default:
                                throw tokener.syntaxError("Expected a ',' or '}'");
                            }
                        }
                    }
                }
            }
        } catch (JSONException var15) {
            fireErrorEvent(var15, jsonConfig);
            throw var15;
        }
    }
3.3_fromJSONTokener方法源码解读

大致为,先判断是否为空或者没有{}大括号等等。然后使用wihle(true){}开始遍历json字符串,JSONTokener的nextClean()方法为取json字符串中的每个字符,其中逻辑大概为遇到/就跳过再执行,遇到非法字符或不符合规范就抛出错误,直到返回一个合法字符。后续就是一些把json字符串根据key-value存进map中,也就是对象本身的properties。
关键是这条语句:Object v = tokener.nextValue(jsonConfig);
进入JSONTokener的newValue方法可以看到,当值为null时,取出来的对象类型就为JSONNull了
在这里插入图片描述
JSONNull.getInstance()返回的就是一个JSONNull对象
在这里插入图片描述

4.结论

非”null”字符串放到JSONObject类中时,取出来使用时是java.lang.String类型
“null”字符串放到JSONObject类中时,取出来的使用会转换成net.sf.json.JSONNull类型:

5.举个例子

import net.sf.json.JSONObject;

public class JsonTest {

    public static void main(String[] args) {
        String jsonStr = "{\"test\":\"\",\"test1\":null,\"test2\":1}";
        JSONObject jsonObject = JSONObject.fromObject(jsonStr);
        String test1 = jsonObject.get("test1") == null ? "" : (String) jsonObject.get("test1");
        System.out.println(test1);
    }
}

按照现在常用的json转换工具,都会自动帮忙转成""空字符串

模拟该过程,断点到jsonObject.get(“test1”) == null这行时,就会报错。因为取出来的数值类型为net.sf.json.JSONNull并不等于null,但是转成string时就不支持。

原因很简单,因为test1的对象类型为JSONNull,那么在 == null ? 这步时调用的是JSONNull的equals方法。那我们看看JSONNull的equals方法。

    public boolean equals(Object object) {
        return object == null || object == this || object == instance || object instanceof JSONObject && ((JSONObject)object).isNullObject() || "null".equals(object);
    }

很明显,JSONNull对象不等于null,所以返回值为false,所以就在后面强转String的代码会抛出错误。

6.解决方法

1.将json字符串中的null改成传""即可。
2.使用别的json转换包

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值