Jackson vs Gson:Java JSON解析庫深度對比

2025-01-15 10:10 更新

大家好,我是 V 哥。Jackson和Gson是Java中最常用的兩個JSON_blnk解析庫,它們在解析速度、靈活性、序列化/反序列化能力上各有特點。下面V 哥從功能特性、性能、源碼實現(xiàn)等方面對比它們的優(yōu)缺點。

1. 功能特性對比

  • Jackson
    • 提供全面的JSON處理支持,包括對象-JSON轉換、樹模型處理、流式處理等。
    • 具有廣泛的注解支持,方便進行序列化/反序列化控制(如@JsonProperty@JsonIgnore等)。
    • 支持多種數據格式,包括XML、CSV、YAML等。
    • 具備較強的擴展能力,通過模塊化架構可以擴展額外功能。

  • Gson
    • Gson提供簡單、易用的API和注解(如@SerializedName)。
    • 在對象轉換中可以自動處理空值,且支持Java泛型的序列化與反序列化。
    • Gson原生支持Java對象的嵌套映射,且支持通過TypeToken來實現(xiàn)復雜類型的反序列化。
    • 庫文件輕量且易于集成。

2. 性能對比

一般來說,Jackson的性能優(yōu)于Gson,尤其是在處理大數據量和復雜對象時,Jackson表現(xiàn)更佳。這主要歸因于Jackson內部的高效流式解析器和緩存機制,它避免了內存中的大量臨時對象創(chuàng)建,提升了處理速度。

Jackson的流式API(如JsonParserJsonGenerator)提供了細粒度的數據處理,適合在性能要求較高的場景使用。Gson則使用內存樹模型處理JSON,這在內存開銷和解析速度上較劣勢。

3. 源碼實現(xiàn)分析

接下來,V 哥通過分析兩個組件的核心源碼實現(xiàn),來看一下兩者的不同之處。

Jackson 源碼實現(xiàn)

Jackson實現(xiàn)基于三個核心模塊:jackson-core、jackson-databindjackson-annotations。

  • 流式解析器:Jackson在jackson-core中實現(xiàn)了高效的流式解析器JsonParser和生成器JsonGenerator。這些解析器可以在讀取和寫入時逐行處理數據,避免不必要的對象創(chuàng)建,減少內存使用。
  • 數據綁定jackson-databind負責對象-JSON之間的轉換,通過反射和注解處理。
  • 擴展支持:通過模塊化架構,Jackson可以擴展其他格式(如XML和YAML)。其實現(xiàn)通過Module接口定義和動態(tài)注入,實現(xiàn)了靈活的格式支持。

下面V哥通過源碼分析來具體介紹:

Jackson 的源碼實現(xiàn)涉及多個模塊(如 jackson-corejackson-databind、jackson-annotations 等),我們可以從 Jackson 的數據解析與生成的基本流程、數據綁定模塊的實現(xiàn)、注解處理的方式、流式 API 等方面逐步分析其源碼。

1. 流式 API(Streaming API)分析

Jackson 使用了流式解析器 JsonParser 和生成器 JsonGenerator,這使得它在處理大數據量 JSON 時具有較好的性能。jackson-core模塊提供了這兩個主要類。Jackson 的流式 API 是逐字節(jié)處理 JSON 數據的,因此可以實現(xiàn)低內存消耗和高效的數據處理。

代碼解析示例

jackson-coreJsonParser 類中,實現(xiàn)了對 JSON 數據的逐步解析。它采用“令牌(Token)”的形式進行解析,常見的 Token 包括 START_OBJECT、FIELD_NAMEVALUE_STRING 等。

  • JsonParser類的核心方法 nextToken()
    • 讀取下一個 JSON Token,并將其存儲在當前上下文中。
    • 通過 switch-case 結構,處理 JSON 字符串中的各類數據。
    • 例如,遇到"{"會生成 START_OBJECT,而 "}" 會對應 END_OBJECT

public JsonToken nextToken() throws IOException {
    // 實現(xiàn)不同字符的判斷邏輯,根據 JSON 數據逐步解析
    int ch = nextByte();
    switch (ch) {
        case '{':
            _currToken = JsonToken.START_OBJECT;
            return _currToken;
        case '}':
            _currToken = JsonToken.END_OBJECT;
            return _currToken;
        // 省略其他分支
    }
}

  • JsonGenerator 類則用于寫入 JSON,它將數據以 Token 的形式逐步生成,適用于輸出大文件場景。

public void writeStartObject() throws IOException {
    _writeContext.writeStartObject();
    _generator.writeStartObject();
}

2. 數據綁定(Data Binding)分析

Jackson 的 jackson-databind 模塊負責對象和 JSON 之間的自動映射和綁定。核心實現(xiàn)類是 ObjectMapper,它通過反射技術將 JSON 字段自動映射到 Java 對象字段。

代碼解析示例

ObjectMapper 中主要通過 readValue()writeValue() 方法來實現(xiàn) JSON 與對象的互轉。

  • readValue()方法用于將 JSON 轉換為對象。通過 DeserializationContextJsonDeserializer 的配合,它能夠解析復雜的 JSON 數據到 Java 對象。

public <T> T readValue(JsonParser p, Class<T> valueType) throws IOException {
    JavaType javaType = _typeFactory.constructType(valueType);
    JsonDeserializer<Object> deser = _findRootDeserializer(_config, javaType);
    return (T) deser.deserialize(p, _deserializationContext);
}

  • writeValue() 方法用于將對象轉換為 JSON 字符串。它會先通過 SerializationContextJsonSerializer 獲取到需要的 JSON 結構,然后通過 JsonGenerator 寫入。

public void writeValue(JsonGenerator gen, Object value) throws IOException {
    JsonSerializer<Object> serializer = _serializerProvider().findTypedValueSerializer(value.getClass(), true, null);
    serializer.serialize(value, gen, _serializerProvider());
}

3. 注解處理

Jackson 支持豐富的注解,例如 @JsonProperty、@JsonIgnore 等,用于精細控制序列化和反序列化的過程。注解的處理主要依賴 AnnotationIntrospectorBeanSerializerFactory 等類。

代碼解析示例

在 Jackson 中,@JsonProperty 注解通過 AnnotationIntrospectorfindPropertyNameForParam() 方法來獲取指定的字段名,并對 Java 字段進行映射。

  • AnnotationIntrospector 類中會檢查字段上是否存在 Jackson 注解,如果存在則執(zhí)行注解對應的序列化規(guī)則。

public String findPropertyNameForParam(AnnotatedParameter param) {
    JsonProperty ann = param.getAnnotation(JsonProperty.class);
    return (ann == null) ? null : ann.value();
}

  • BeanSerializerFactory 類會解析所有字段和注解的關聯(lián)關系,并生成一個 BeanSerializer 對象,用于在序列化時將注解信息加入。

public JsonSerializer<Object> createBeanSerializer(SerializerProvider prov, JavaType type, BeanDescription beanDesc) {
    BeanSerializerBuilder builder = constructBeanSerializerBuilder(beanDesc);
    List<BeanPropertyWriter> props = findBeanProperties(prov, beanDesc, builder);
    builder.setProperties(props);
    return builder.build();
}

4. 樹模型(Tree Model)

Jackson 的樹模型允許用戶以樹形結構操作 JSON 數據,例如 JsonNodeObjectNode 類,支持更靈活的數據訪問與修改。樹模型操作適合需要動態(tài)或未知 JSON 結構的場景。

  • JsonNode 是 Jackson 樹模型的核心接口,ObjectNodeArrayNode 是其實現(xiàn)類,用于存儲 JSON 對象和數組。

ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(jsonString);  // 讀取 JSON 字符串
String name = rootNode.get("name").asText();       // 訪問字段

JsonNode 的實現(xiàn)中,Jackson 提供了不同的子類來處理 JSON 數據節(jié)點,比如 TextNode、BooleanNode、ArrayNode 等。這種設計使得 Jackson 能夠輕松地在樹節(jié)點中靈活讀取和寫入 JSON 數據。

5. 擴展與模塊支持

Jackson 的模塊化設計允許用戶加載第三方模塊來擴展其功能。jackson-module 系列包含了對 JDK8 類型、Java時間類、Kotlin 等支持。這些模塊通過 Module 類來注冊和管理,支持自定義序列化和反序列化器。

代碼解析示例

  • 通過 registerModule() 方法可以動態(tài)加載擴展模塊。

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule()); // 添加對 Java 時間類的支持

6. 小結一下

通過源碼分析,V 哥發(fā)現(xiàn),Jackson實在優(yōu)秀,體現(xiàn)了優(yōu)秀的設計架構,比如:流式解析提供了高性能支持,數據綁定實現(xiàn)了靈活的對象映射,注解處理讓開發(fā)者可以細粒度控制序列化過程,同時還支持擴展模塊。這種設計使得 Jackson 適用于多種復雜的 JSON 處理場景。

Gson 源碼實現(xiàn)

再來看 Gson,Gson 的源碼實現(xiàn)相對簡潔,主要專注于 JSON 與 Java 對象的序列化和反序列化。其實現(xiàn)涉及的核心類包括 Gson、TypeAdapter、JsonElement、JsonParser 等。下面我們分步驟分析 Gson 的主要源碼實現(xiàn)過程。

1. Gson 的整體架構

Gson 的核心類是 Gson,它負責 JSON 與 Java 對象之間的相互轉換。Gson 中的 toJson()fromJson() 方法是核心接口,它們分別用于將 Java 對象轉換為 JSON 字符串,以及將 JSON 字符串解析為 Java 對象。Gson 的設計依賴于反射和注解,TypeAdapter 類用于自定義對象的序列化和反序列化。

2. JSON 轉 Java 對象(反序列化)

Gson 中,fromJson() 方法用于 JSON 到 Java 對象的轉換。其主要步驟包括解析 JSON、匹配類型、反射創(chuàng)建對象等。

代碼解析示例

  • fromJson() 方法是 Gson 解析 JSON 字符串的入口。在調用時會根據給定的類型,將 JSON 轉換為對應的 Java 對象。

public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
    // 使用 JsonReader 逐字符讀取 JSON 數據
    JsonReader jsonReader = new JsonReader(new StringReader(json));
    return fromJson(jsonReader, classOfT);
}

  • fromJson(JsonReader reader, Type typeOfT) 方法通過調用 getAdapter(TypeToken.get(typeOfT)) 來獲取 TypeAdapter,然后調用 read() 方法讀取 JSON 數據并轉換為對象。

public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
    TypeAdapter<T> adapter = getAdapter(TypeToken.get(typeOfT));
    return adapter.read(reader);
}

TypeAdapter

TypeAdapter 是 Gson 中的核心接口,用于控制對象序列化和反序列化的過程。Gson 提供了多種類型的 TypeAdapter,并支持用戶自定義 TypeAdapter

  • read(JsonReader in) 方法會遍歷 JSON 數據并創(chuàng)建 Java 對象。例如,在 ReflectiveTypeAdapterFactory.Adapter 中會通過反射讀取 JSON 數據并賦值給 Java 對象的字段。

@Override
public T read(JsonReader in) throws IOException {
    T instance = constructor.construct();
    in.beginObject();
    while (in.hasNext()) {
        String name = in.nextName();
        // 找到字段對應的 TypeAdapter,賦值給 Java 對象
        Field field = fields.get(name);
        field.set(instance, fieldAdapter.read(in));
    }
    in.endObject();
    return instance;
}

3. Java 對象轉 JSON(序列化)

Gson 的 toJson() 方法用于將 Java 對象序列化為 JSON 字符串。實現(xiàn)思路類似,首先獲取對象的 TypeAdapter,然后通過 write() 方法將數據寫入 JSON。

代碼解析示例

  • toJson() 方法內部通過 getAdapter() 獲取 TypeAdapter,然后調用 write() 生成 JSON。

public void toJson(Object src, Appendable writer) throws JsonIOException {
    if (src != null) {
        toJson(src, src.getClass(), writer);
    } else {
        writer.append("null");
    }
}

  • write(JsonWriter out, T value) 方法用于將 Java 對象寫入 JSON。例如,在 ReflectiveTypeAdapterFactory.Adapter 中,它會逐字段將 Java 對象序列化為 JSON 字符串。

@Override
public void write(JsonWriter out, T value) throws IOException {
    out.beginObject();
    for (BoundField boundField : boundFields.values()) {
        out.name(boundField.name);
        boundField.write(out, value);
    }
    out.endObject();
}

JsonWriter

JsonWriter 是 Gson 中流式輸出 JSON 的工具,配合 TypeAdapter 使用,它可以逐步生成 JSON,適合大對象和復雜結構。

4. TypeToken 的使用

Gson 使用 TypeToken 處理泛型,以解決 Java 的類型擦除問題。TypeToken 是 Gson 用于保存泛型類型信息的工具類。

  • 例如 new TypeToken<List<String>>(){}.getType() 可以獲取 List<String>Type 對象。

Type listType = new TypeToken<List<String>>(){}.getType();
List<String> list = gson.fromJson(json, listType);

  • TypeToken 的源碼實現(xiàn)利用了匿名內部類來獲取泛型信息,TypeToken 的構造方法會調用 getSuperclassTypeParameter() 來捕獲泛型類型。

private static Type getSuperclassTypeParameter(Class<?> subclass) {
    Type superclass = subclass.getGenericSuperclass();
    if (superclass instanceof ParameterizedType) {
        return ((ParameterizedType) superclass).getActualTypeArguments()[0];
    }
    throw new RuntimeException("Missing type parameter.");
}

5. 注解處理

Gson 支持注解 @SerializedName 來指定 JSON 字段名,它通過反射獲取字段上的注解并設置到 Field 對象中,以在序列化和反序列化時使用。

  • ReflectiveTypeAdapterFactory 中,通過反射獲取字段的注解。如果字段帶有 @SerializedName 注解,則將注解指定的名稱作為 JSON 中的字段名。

Field field = ...;
SerializedName annotation = field.getAnnotation(SerializedName.class);
String name = (annotation == null) ? field.getName() : annotation.value();

6. JsonElement 和 JsonParser

Gson 提供了 JsonElement 類來表示 JSON 節(jié)點,它是一個抽象類,具有 JsonObject、JsonArray、JsonPrimitiveJsonNull 等子類。

  • JsonParser 類用于解析 JSON 字符串并返回一個 JsonElement,適用于不確定 JSON 結構的動態(tài)解析場景。

JsonElement jsonTree = JsonParser.parseString(jsonString);
if (jsonTree.isJsonObject()) {
    JsonObject jsonObject = jsonTree.getAsJsonObject();
    // 可以根據鍵值訪問
    String name = jsonObject.get("name").getAsString();
}

7. 自定義序列化與反序列化

Gson 允許用戶通過 TypeAdapterJsonSerializer/JsonDeserializer 來自定義序列化和反序列化過程,適用于處理特殊格式的數據。

  • JsonSerializerJsonDeserializer 是接口,用于自定義序列化和反序列化過程,用戶可以實現(xiàn)這兩個接口,并將其傳入 GsonBuilder 中進行注冊。

GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Date.class, new JsonSerializer<Date>() {
    @Override
    public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
        return new JsonPrimitive(src.getTime()); // 序列化為時間戳
    }
});
Gson gson = builder.create();

8. GsonBuilder

GsonBuilder 是 Gson 的構建類,用于配置 Gson 實例??梢栽?GsonBuilder 中添加自定義的 TypeAdapter、JsonSerializerJsonDeserializer,并設置序列化/反序列化的策略。

GsonBuilder builder = new GsonBuilder();
builder.setPrettyPrinting(); // 格式化 JSON 輸出
builder.registerTypeAdapter(CustomClass.class, new CustomTypeAdapter());
Gson gson = builder.create(); // 創(chuàng)建 Gson 實例

9. 小結一下

通過以上的源碼分析,咱們可以看到,Gson 的源碼設計相對簡潔,適合處理簡單的 JSON 數據結構。它的核心設計思想圍繞 TypeAdapter、TypeToken 和注解反射來實現(xiàn)靈活的序列化和反序列化。

4. 優(yōu)缺點分析

Jackson和Gson各有優(yōu)缺點,這也符合天下技術唯有最適合沒有最好的道理, V 哥建議,在選擇使用時,需要根據自己的項目情況來判斷,才是明智的。

Jackson 優(yōu)缺點

  • 優(yōu)點
    • 性能出色,尤其是流式API適合大數據量解析。
    • 注解功能豐富,支持更細粒度的數據控制。
    • 支持多種數據格式,具有較強的擴展性。
    • 模塊化架構,便于擴展和定制。

  • 缺點
    • API較復雜,學習成本較高。
    • 庫的大小比Gson略大。

Gson 優(yōu)缺點

  • 優(yōu)點
    • 輕量級、易用,便于快速集成。
    • 注解支持基礎操作,在簡單映射場景中靈活性較高。
    • 更易于調試,且使用內存樹模型方便解析和修改JSON。

  • 缺點
    • 性能相對較差,不適合大數據量和高并發(fā)處理場景。
    • 對復雜場景的支持較弱,尤其是序列化和反序列化定制能力欠缺。
    • 不支持流式API,內存開銷較大。

5. 適用場景

從性能的角度來分析,咱們可以得出以下結論:

  • Jackson:適用于高并發(fā)、大數據量、高性能要求的場景,或需要復雜數據格式支持的應用。
  • Gson:適用于小規(guī)模的JSON處理、項目簡單數據傳輸、快速開發(fā)等輕量級場景。

Jackson和Gson各有所長,選擇時應根據具體需求權衡性能、靈活性和開發(fā)便捷性。

以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號