背景
这边进行对接外部渠道时,需要对json串进行加签,但是验签一直出错。原因是渠道用了fastjson来处理,我们系统用gson来处理。
例如:
String raw = "[{\"z\":1,\"a\":2},{\"b\":1,\"c\":2}]";
// fastJson的toString
System.out.println(JSON.toJSONString(JSON.parse(raw)));
// gson的toString
com.google.gson.JsonParser JSON_PARSER = new com.google.gson.JsonParser();
String raw2 = JSON_PARSER.parse(raw).getAsJsonObject().toString();
fastjson
fastjson的maven依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
JSON.toJSONString(Object object);
里真正决定 key 打印顺序 的源码只有一处:
com.alibaba.fastjson.serializer.MapSerializer→
write(JSONSerializer serializer, Map map, Object fieldName, Type fieldType, int fieldFeatures)
MapSerializer 是 fastjson 里专门负责"把任何 Map/JSONObject 写成 JSON 字符串"的核心序列化器 。
一句话:它决定 Map 里的 key-value 最终怎么出现在 JSON 里(顺序、过滤、值序列化、空值处理等)。
Map<?, ?> map = (Map)object;
int mapSortFieldMask = SerializerFeature.MapSortField.mask;
if ((out.features & mapSortFieldMask) != 0 || (features & mapSortFieldMask) != 0) {
if (map instanceof JSONObject) {
map = ((JSONObject)map).getInnerMap();
}
if (!(map instanceof SortedMap) && !(map instanceof LinkedHashMap)) {
try {
map = new TreeMap((Map)map); // 关键:TreeMap 按 key 升序
} catch (Exception var25) {
}
}
}
-
如果传入的 map 是 fastjson 的 JSONObject,就取出它内部真正的 Map,避免重复排序或丢失特性。
JSONObject是 fastjson 提供的一个自定义Map实现,它内部包装了一个Map(通常是LinkedHashMap),但自身不是TreeMap或LinkedHashMap的子类。 -
只要全局或本次调用 带了
MapSortField,就把原 map 包成TreeMap,后面迭代顺序即字典序。已是SortedMap/LinkedHashMap就跳过, 想保留插入序。
gson
Gson#toJson(src) 的 key 顺序只由"原始来源"决定 ,Gson 本身不做任何排序,也不会打乱。
兼容一下:
/**
* 把 JsonElement 递归转成"按字段名hash"的 JsonElement
*/
private static JsonElement hashJson(JsonElement el) {
if (el.isJsonNull() || el.isJsonPrimitive()) {
return el; // 基本类型直接返回
}
if (el.isJsonArray()) {
JsonArray arr = new JsonArray();
for (JsonElement item : el.getAsJsonArray()) {
arr.add(hashJson(item)); // 递归处理数组元素
}
return arr;
}
// JsonObject -> hashMap
JsonObject obj = el.getAsJsonObject();
HashMap<String, JsonElement> hashMap = new HashMap<>();
obj.entrySet().forEach(e -> hashMap.put(e.getKey(), hashJson(e.getValue())));
JsonObject newObj = new JsonObject();
hashMap.forEach(newObj::add);
return newObj;
}