org.json源码分析及增强(二)——org.json.JSONException: Duplicate key问题处理

org.json.JSONException: Duplicate key问题的出现

当使用JSONObject处理如json{\"key\" : 1,\"key\" : 2}"这样的JSON数据格式的字符串时,或使用JSONArray处理json[{\"key\" : 1,\"key\" : 2}, {\"key\" : 3,\"key\" : 4}]的数组字符串时,org.json.JSONException: Duplicate key的问题就出现了,原因首先是JSON数据格式不规范,本就不应该包含相同的key名,另外,JSONObject内部使用的是一个map数据结构,是不允许有同样的key存在的,因此,通过抛出JSONException异常来警告使用者。主要的源码如下:

 public JSONObject putOnce(String key, Object value) throws JSONException {
        if (key != null && value != null) {
            if (this.opt(key) != null) {
                throw new JSONException("Duplicate key \"" + key + "\"");
            }
            this.put(key, value);
        }
        return this;
    }

通过this.opt(key) != null来进行重复key的判断,但原生JS对于重复key的JSON串的处理过程是什么样子的呢?

还原原生JS的处理

我们通过浏览器的控制台写一段JS进行测试:

var data = "[{\"key\" : 1,\"key\" : 2}, {\"key\" : 3,\"key\" : 4}]";
eval("("+data+")");

运行结果如下:这里写图片描述

可以看到JS的处理是会保留最后一对重复key的值作为key属性的值。

模仿原生JS的处理

首先说明你可以通过修改和继承已有的JSONArray、JSONObject和JSONTokener类来完成模仿JS的处理,但实际上你所处理的JSON串是极不规范的。 
主要的注意细节和方法如下: 
(1)为了继承JSONArray类,并获取到map对象,需要将JSONArray.java中的ArrayList myArrayList由private修改为protected; 
(2)通过继承重载JSONObject类的putOnce方法,将重复key的检查逻辑去掉,这样就完成了JSONObject对于重复key的支持; 
(3)对于JSONArray比较麻烦一些,需要一个继承重载JSONTokener类的nextValue方法的子类,并且还需要构建JSONObject和JSONArray子类的相关构造函数。 
参考代码如下: 
JSONArrayIgnoreDuplicates类:

public class JSONArrayIgnoreDuplicates extends JSONArray{

    public JSONArrayIgnoreDuplicates(){
        super();
    }

    public JSONArrayIgnoreDuplicates(String json){
        this(new JSONTokenerIgnoreDuplicates(json));
    }

     public JSONArrayIgnoreDuplicates(JSONTokenerIgnoreDuplicates x) throws JSONException {

         if (x.nextClean() != '[') {
             throw x.syntaxError("A JSONArray text must start with '['");
         }

         if (x.nextClean() != ']') {
                x.back();
                for (;;) {
                    if (x.nextClean() == ',') {
                        x.back();
                        this.myArrayList.add(JSONObjectIgnoreDuplicates.NULL);
                    } else {
                        x.back();
                        this.myArrayList.add(x.nextValue());
                    }
                    switch (x.nextClean()) {
                    case ',':
                        if (x.nextClean() == ']') {
                            return;
                        }
                        x.back();
                        break;
                    case ']':
                        return;
                    default:
                        throw x.syntaxError("Expected a ',' or ']'");
                    }
                }
            }
     }

}

JSONObjectIgnoreDuplicates类:

public class JSONObjectIgnoreDuplicates extends JSONObject {
    public JSONObjectIgnoreDuplicates(String json) {
        super(json);
    }

    public JSONObjectIgnoreDuplicates(JSONTokenerIgnoreDuplicates x) {
        super(x);
    }

    public JSONObject putOnce(String key, Object value) throws JSONException {
        if (key != null && value != null) {
            if (this.opt(key) != null ) {
                System.out.println("Duplicate key \"" + key + "\"");
            }
            this.put(key, value);
        }

        return this;
    }
}

JSONTokenerIgnoreDuplicates类:

public class JSONTokenerIgnoreDuplicates extends JSONTokener {

    public JSONTokenerIgnoreDuplicates(String s) {
        super(s);
    }

    @Override
     public Object nextValue() throws JSONException {
            char c = this.nextClean();
            String string;

            switch (c) {
                case '"':
                case '\'':
                    return this.nextString(c);
                case '{':
                    this.back();
                    return new JSONObjectIgnoreDuplicates(this);
                case '[':
                    this.back();
                    return new JSONObjectIgnoreDuplicates(this);
            }

            StringBuilder sb = new StringBuilder();
            while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
                sb.append(c);
                c = this.next();
            }
            this.back();

            string = sb.toString().trim();
            if ("".equals(string)) {
                throw this.syntaxError("Missing value");
            }
            return JSONObjectIgnoreDuplicates.stringToValue(string);
        }

}

测试代码如下:

JSONArrayIgnoreDuplicates array = new JSONArrayIgnoreDuplicates("[{\"key\" : 1,\"key\" : 2}, {\"key\" : 3,\"key\" : 4}]");
         System.out.println(array.toString());

运行结果: 
这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值