Gson 簡單使用姿勢小結

Gson 簡單使用姿勢小結

關於 Json 序列化的框架可以說比較多了,比如 Spring 默認的 Jackson,國內互聯網用的比較多的 FastJson,本文則主要介紹一下 Gson 的簡單使用姿勢,並不會涉及到不同的 json 框架的性能對比

本文主要內容來源於官方教程: https://github.com/google/gson/blob/master/UserGuide.md

1. 依賴導入

首先我們藉助 maven 來引入依賴包,按照自己的實際情況選擇一個版本(簡單的使用姿勢與具體的版本並沒有太大的關聯性)

<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>

2. 基本的序列化與反序列化

一般來講,我們通過 Gson 對象來實現 Json 的序列化與反序列化,如下是幾個簡單的序列化與反序列化的 case

// Serialization
Gson gson = new Gson();
gson.toJson(1);            // ==> 1
gson.toJson("abcd");       // ==> "abcd"
gson.toJson(new Long(10)); // ==> 10
int[] values = { 1 };
gson.toJson(values);       // ==> [1]

// Deserialization
int one = gson.fromJson("1", int.class);
Integer one = gson.fromJson("1", Integer.class);
Long one = gson.fromJson("1", Long.class);
Boolean false = gson.fromJson("false", Boolean.class);
String str = gson.fromJson("\"abc\"", String.class);
String[] anotherStr = gson.fromJson("[\"abc\"]", String[].class);

上面的 case 中,主要就是藉助gson.toJson來輸出 Json 字符串,藉助gson.fromJson返序列化得到對象

3. 對象序列化

對象的序列化與反序列化可以說是最常見的,在 Gson 的使用過程中,推薦的對象寫法

  • filed:private 修飾
  • 不希望序列化的成員,添加transient修飾符
  • 默認無參構造方法(可選,這裏跟人推薦保留,不同於 FastJson 的必須存在)
public static class BaseBean {
    private int age;

    private String name;

    private transient int code;

    private String email;

    public BaseBean() {
    }

    @Override
    public String toString() {
        return "BaseBean{" + "age=" + age + ", name='" + name + '\'' + ", code=" + code + ", email='" + email +
                '\'' + '}';
    }
}
@Test
public void testObjGson() {
    BaseBean bean = new BaseBean();
    bean.age = 10;
    bean.code = 20;
    bean.name = "一灰灰blog";

    Gson gson = new Gson();
    String str = gson.toJson(bean);
    System.out.println("json str: " + str);

    BaseBean out = gson.fromJson(str, BaseBean.class);
    System.out.println("after deserialization: " + out);
}

上面的使用姿勢和前面並沒有什麼本質的區別,接下來看一下輸出結果

json str: {"age":10,"name":"一灰灰blog"}
after deserialization: BaseBean{age=10, name='一灰灰blog', code=0, email='null'}

請注意:

  • 輸出 json 串時,null 和transient修飾的成員不會輸出到 json 串中
  • 對象沒有 Get/Set 方法,也依然可以反序列化(對象也沒有繼承自 Serialize 接口,當然我個人的觀點是請繼承 Serialize 接口)

如果我希望將 null 的成員,也可以輸出到 json 串,可以如下操作

// 並不直接創建Gson對象,改用GsonBuilder
Gson gsonWithNUll = new GsonBuilder().serializeNulls().create();
System.out.println("serialize with null: " + gsonWithNUll.toJson(bean));

輸出結果如下

serialize with null: {"age":10,"name":"一灰灰blog","email":null}

說明:如果希望擴展序列化方式,通過 GsonBuilder 來構建 Gson 對象是一個不錯的選擇

4. JsonObject 與 JsonArray

某些場景下我們可能並沒有定義反序列化的數據對象,比如 FastJson 中的直接反序列化爲JSONObject/JSONArray,然後手動獲取數據進行業務處理,這種場景下,gson 可以如何支持呢?

Map map = new HashMap();
map.put("a", "hello world");
map.put(12, true);
map.put("array", Arrays.asList("a", "c", "f", 12));
map.put("obj", Maps.newHashMap("k", "v"));

Gson gson = new Gson();
String str = gson.toJson(map);

// 直接藉助 JsonParser#parseString 來實現反序列化
JsonObject obj = JsonParser.parseString(str).getAsJsonObject();
String a = obj.get("a").getAsString();
boolean b = obj.get("12").getAsBoolean();
JsonArray ary = obj.get("array").getAsJsonArray();
JsonObject o = obj.get("obj").getAsJsonObject();

System.out.println("a:" + a + " b:" + b + " ary:" + ary + " o:" + o);

請注意,我們這裏主要藉助的是JsonParser.parseString方法,輸入參數可以是 String 也可以是流,返回的是JsonElement對象,這個對象比較有意思,提供了一些基礎的類型輸出方法如

  • getAsString: 返回 String
  • getAsInt: 返回 int
  • getAsJsonArray: 返回 JsonArray(json 數組)
  • getAsJsonObject: 返回 JsonObject (Json 對象)
  • ...

5. 泛型序列化

以上屬於常規的基本使用姿勢,實際的工作中,關於泛型的序列化和反序列化可以說非常常見了,那麼應該如何處理呢

public static class ResWrapper<T> {
    private T data;
    private int code;
    private String msg;
}

public static class User {
    private int age;
    private String name;
}

@Test
public void testGenri() {
    ResWrapper<User> wrapper = new ResWrapper<>();
    wrapper.code = 0;
    wrapper.msg = "name";

    User user = new User();
    user.age = 18;
    user.name = "一灰灰";

    wrapper.data = user;

    Gson gson = new Gson();
    String str = gson.toJson(wrapper);

    Type type = new TypeToken<ResWrapper<User>>() {}.getType();
    ResWrapper<User> out = gson.fromJson(str, type);
    System.out.println(out);
}

上面的核心在於 Type 的生成: new TypeToken<ResWrapper<User>>() {}.getType();

6. 進階

以上內容基本上可以覆蓋日常業務開發中 90%的場景,當然 gson 也支持一些更高級的功能

如 filed name 映射

  • @SerializedName("custom_naming")
private class SomeObject {
  @SerializedName("custom_naming")
  private final String someField;
  private final String someOtherField;

  public SomeObject(String a, String b) {
    this.someField = a;
    this.someOtherField = b;
  }
}

如版本支持

  • @Since(1.1)
public class VersionedClass {
  @Since(1.1) private final String newerField;
  @Since(1.0) private final String newField;
  private final String field;

  public VersionedClass() {
    this.newerField = "newer";
    this.newField = "new";
    this.field = "old";
  }
}

VersionedClass versionedObject = new VersionedClass();
Gson gson = new GsonBuilder().setVersion(1.0).create();
String jsonOutput = gson.toJson(versionedObject);
System.out.println(jsonOutput);
System.out.println(); // 輸出: {"newField":"new","field":"old"}

gson = new Gson();
jsonOutput = gson.toJson(versionedObject);
System.out.println(jsonOutput); // 輸出: {"newerField":"newer","newField":"new","field":"old"}

自定義的類型轉換

GsonBuilder gson = new GsonBuilder();
gson.registerTypeAdapter(MyType.class, new DateTimeSerializer());
gson.registerTypeAdapter(MyType.class, new DateTimeDeserializer());

private class DateTimeSerializer implements JsonSerializer<DateTime> {
  public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) {
    return new JsonPrimitive(src.toString());
  }
}

private class DateTimeDeserializer implements JsonDeserializer<DateTime> {
  public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
      throws JsonParseException {
    return new DateTime(json.getAsJsonPrimitive().getAsString());
  }
}

可視化的 json 輸出

Gson gson = new GsonBuilder().setPrettyPrinting().create();
String jsonOutput = gson.toJson(someObject);

II. 其他

1. 一灰灰 Bloghttps://liuyueyi.github.io/hexblog

一灰灰的個人博客,記錄所有學習和工作中的博文,歡迎大家前去逛逛

2. 聲明

盡信書則不如,以上內容,純屬一家之言,因個人能力有限,難免有疏漏和錯誤之處,如發現 bug 或者有更好的建議,歡迎批評指正,不吝感激

3. 掃描關注

一灰灰 blog

QrCode

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章