问题
当用Linkedhashmap去存储一个有序的map数据结构,然后用fastjson去转换为json字符串再转回来的时候发现顺序丢失。
代码示例:
无法保证插入顺序代码
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import java.util.LinkedHashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
LinkedHashMap<Integer, String> map = new LinkedHashMap<>();
map.put(1, "A");
map.put(3, "A");
map.put(8, "A");
map.put(5, "A");
//原始顺序
System.out.println("原始顺序:");
for (Object o : map.entrySet()) {
System.out.printf("%s ", o);
}
//fastjson
String fJson = JSON.toJSONString(map);
Map m = JSONObject.parseObject(fJson, Map.class);
System.out.println();
System.out.println("fastjson:");
for (Object o : m.entrySet()) {
System.out.printf("%s ", o);
}
}
}
输出:
原始顺序:
1=A 3=A 8=A 5=A
fastjson:
1=A 8=A 5=A 3=A
原因:
问题是出在fastjson的JSON.parseObject()方法上,debug代码到如下部分(版本1.1.23):
com.alibaba.fastjson.JSONObject#JSONObject()
public JSONObject() {
this(16, false);
}
com.alibaba.fastjson.JSONObject#JSONObject(int, boolean)
public JSONObject(int initialCapacity, boolean ordered) {
if (ordered) {
this.map = new LinkedHashMap(initialCapacity);
} else {
this.map = new AntiCollisionHashMap(initialCapacity);
}
}
由于会默认ordered = false 所以会返回一个AntiCollisionHashMap类型对象,然后用该对象去进行put赋值,返回的该map对象无法保证我们想要的顺序。
详见fastjson issue: github.com/alibaba/fas…
解决办法
方法1: 采用gson将json字符串转换为map
gson实现:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.LinkedHashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
LinkedHashMap<Integer, String> map = new LinkedHashMap<>();
map.put(1, "A");
map.put(3, "A");
map.put(8, "A");
map.put(5, "A");
//原始顺序
System.out.println("原始顺序:");
for (Object o : map.entrySet()) {
System.out.printf("%s ", o);
}
//gson
Gson gson = new GsonBuilder().enableComplexMapKeySerialization().create();
String gJson = gson.toJson(map);
Map m = gson.fromJson(gJson, Map.class);
System.out.println();
System.out.println("gson:");
for (Object o : m.entrySet()) {
System.out.printf("%s ", o);
}
}
}
输出
原始顺序:
1=A 3=A 8=A 5=A
gson:
1=A 3=A 8=A 5=A
方法2: fastjson版本升级到1.2.3以上, 指定Feature.OrderedField参数
代码示例:
//fastjson
String fJson = JSON.toJSONString(map);
Map m = JSON.parseObject(fJson, Feature.OrderedField);
System.out.println();
System.out.println("fastjson:");
for (Object o : m.entrySet()) {
System.out.printf("%s ", o);
}
输出
原始顺序:
1=A 3=A 8=A 5=A
fastjson:
1=A 3=A 8=A 5=A
原理: 根据JSON.parseObject(fJson, Feature.OrderedField),传入的Feature.OrderedField会使ordered=true,这样返回的map对象是LinkedHashMap类型,put的时候就会保证key的顺序。
com.alibaba.fastjson.JSONObject#JSONObject(int, boolean)
public JSONObject(int initialCapacity, boolean ordered) {
if (ordered) {
this.map = new LinkedHashMap(initialCapacity);
} else {
this.map = new HashMap(initialCapacity);
}
}
参考: