fastjson与gson的toString差异

背景

这边进行对接外部渠道时,需要对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;
    }
相关推荐
老板一杯拿铁6 小时前
Java 八股文面试详解:从基础到进阶的全面梳理
java·面试
const_qiu6 小时前
第 2.5 章 2.5.4-2.5.5:JWT 双 Token 与声明式权限守卫
java·人工智能
bug菌6 小时前
一个周末就想把短链服务推到 10 万 QPS,真能靠加 Redis 做到吗?
java·redis·go
撸串-研究生6 小时前
springboot福利院管理系统73979
java·spring boot·后端·福利院管理系统
不得了zz7 小时前
04-Spring AI Alibaba ReactAgent 生产级实践:工具调用、结构化输出、HITL 与上下文管理
java·ai编程·springaialibaba
猿究院_夏燊7 小时前
SpringMVC 到底是怎么干活的?
java·网络·职场和发展
鶴哥只手遮天7 小时前
Spring Framework 7.0.9 深度剖析-05-配置元数据解析:XML、注解与 JavaConfig
java·后端·开源
NGINX开源社区8 小时前
与我们交流:NGINX Gateway Fabric 与 NGINX Ingress Controller 社区会议
java·服务器·前端
鶴哥只手遮天8 小时前
Spring Framework 7.0.9 深度剖析-16-异步与调度
java·后端·开源
十年Java程序媛8 小时前
Java 多线程基础与锁机制|进程线程、synchronized、volatile、Lock 面试全梳理
java·spring boot·面试