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\" : 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\" : 4}]");
System.out.println(array.toString());
运行结果: