Map 轉 JSON 是 REST API、日誌記錄、配置序列化、緩存存儲等場景的高頻操作。本文對比 Jackson、Gson、JSON-lib 三大庫,提供生產就緒配置模板與避坑指南。
| 維度 | Jackson | Gson | JSON-lib (停維護) |
|---|---|---|---|
| Maven 坐標 | com.fasterxml.jackson.core:jackson-databind | com.google.code.gson:gson | net.sf.json-lib:json-lib |
| 依賴 | core, annotations, databind | 無額外依賴 | ezmorph, commons-lang, commons-beanutils, commons-collections, commons-logging |
| 性能 | ⭐⭐⭐⭐⭐ (流式 + 後端優化) | ⭐⭐⭐⭐ | ⭐⭐ |
| 功能豐富度 | ⭐⭐⭐⭐⭐ (模塊化擴展) | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| Spring Boot 默認 | ✅ | 可切換 | ❌ |
| 維護狀態 | 活躍 (2.15+) | 活躍 (2.10+) | 停止維護 (2012 年最後版本) |
| 學習曲線 | 中等 (功能多) | 低 (API 簡潔) | 低 |
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.core.json.JsonWriteFeature;
public class JacksonMapper {
private static final ObjectMapper MAPPER = createMapper();
private static ObjectMapper createMapper() {
ObjectMapper mapper = new ObjectMapper();
// 1. 註冊 Java 8 時間模塊 (必須!)
mapper.registerModule(new JavaTimeModule());
// 2. 禁用時間戳輸出日期 (輸出 ISO-8601 字符串)
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// 3. 空值處理策略
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 忽略 null
// 或 NON_EMPTY (忽略空集合/數組/字符串)
// 或 NON_DEFAULT (忽略默認值)
// 或 CUSTOM (自定義)
// 4. 未知屬性不報錯 (兼容性)
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 5. 單引號/註釋支援 (可選)
mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
// 6. 大數字處理
mapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);
mapper.configure(DeserializationFeature.USE_BIG_INTEGER_FOR_INTS, true);
// 7. 安全:禁用默認類型 (防反序列化漏洞)
mapper.activateDefaultTyping(
LaissezFaireSubTypeValidator.instance,
ObjectMapper.DefaultTyping.NON_FINAL);
return mapper;
}
public static String toJson(Object obj) {
try {
return MAPPER.writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new RuntimeException("JSON 序列化失敗", e);
}
}
public static T fromJson(String json, Class clazz) {
try {
return MAPPER.readValue(json, clazz);
} catch (JsonProcessingException e) {
throw new RuntimeException("JSON 反序列化失敗", e);
}
}
}
// 使用
Map map = Map.of(
"time", LocalDateTime.now(),
"carNum", "京A2212",
"mark", "前保險杠損壞",
"billNum", "100232113213R"
);
String json = JacksonMapper.toJson(map);
// {"time":"2024-01-15T14:30:00","carNum":"京A2212","mark":"前保險杠損壞","billNum":"100232113213R"}
import com.google.gson.*;
public class GsonMapper {
private static final Gson GSON = new GsonBuilder()
.setDateFormat("yyyy-MM-dd HH:mm:ss") // 日期格式
.serializeNulls() // 包含 null (默認不含)
.disableHtmlEscaping() // 不義 HTML 字符
.setPrettyPrinting() // 格式化輸出 (調試用)
.create();
public static String toJson(Object obj) { return GSON.toJson(obj); }
public static T fromJson(String json, Class clazz) { return GSON.fromJson(json, clazz); }
}
// Map 轉 JSON 一樣簡單
String json = GsonMapper.toJson(map);
若維護舊系統使用 JSON-lib,建議漸進式遷移:
JsonLibUtils 中<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier> <!-- 指定 JDK 版本分類器 -->
</dependency>
<dependency>
<groupId>net.sf.ezmorph</groupId>
<artifactId>ezmorph</artifactId>
<version>1.0.6</version>
</dependency>
| 庫 | 平均耗時 (ms) | 吞吐 (ops/s) | 堆分配 (MB) |
|---|---|---|---|
| Jackson (afterburner 模塊) | 85 | 11,764 | 42 |
| Jackson (默認) | 112 | 8,928 | 58 |
| Gson | 145 | 6,896 | 72 |
| JSON-lib | 420 | 2,380 | 185 |
結論:Jackson 綜合性能最優,Gson 代碼最簡潔,JSON-lib 已淘汰。
// Jackson 默認調用 toString()
// 自定義 Key 序列化
mapper.enable(SerializationFeature.WRITE_MAP_NULL_VALUES); // 含 null 鍵
// 或實現 JsonSerializer
// Jackson
mapper.configure(SerializationFeature.FAIL_ON_SELF_REFERENCES, false);
// 或使用 @JsonIdentityInfo
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Node { ... }
// Jackson: 類型信息嵌入
mapper.activateDefaultTyping(validator, DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
// JSON: {"@class":"com.example.User", "name":"Tom"}
// Gson: RuntimeTypeAdapterFactory
RuntimeTypeAdapterFactory factory = RuntimeTypeAdapterFactory.of(Animal.class, "type")
.registerSubtype(Dog.class, "dog")
.registerSubtype(Cat.class, "cat");
Gson gson = new GsonBuilder().registerTypeAdapterFactory(factory).create();
// Jackson 生成器流式寫入
try (JsonGenerator gen = mapper.getFactory().createGenerator(outputStream)) {
gen.writeStartObject();
gen.writeStringField("hugeField", hugeString); // 不將整個對象載入內存
gen.writeEndObject();
}
// Gson 流式讀取
try (JsonReader reader = new JsonReader(new InputStreamReader(inputStream))) {
reader.beginObject();
while (reader.hasNext()) { ... }
}
新項目/ Spring Boot
│
├─ 需要最高性能、豐富特性、生態整合 → Jackson (默認最佳)
├─ 追求極簡 API、輕量依賴、Android 兼容 → Gson
└─ 純 Kotlin 項目 → kotlinx.serialization / Jackson Kotlin 模塊
維護舊系統
├─ 已用 JSON-lib → 制定遷移計劃,新代碼禁用
├─ 已用 Gson → 繼續使用,無需強行遷移
└─ 已用 Jackson → 升級至最新版,啟用 afterburner 模塊