最強常用開發庫總結 - JSON庫詳解


最強常用開發庫總結 - JSON庫詳解

JSON應用非常廣泛,對於Java常用的JSON庫要完全掌握。@pdai

JSON簡介

JSON是什么

  • JSON 指的是 JavaScript 對象表示法(JavaScript Object Notation)
  • JSON 是輕量級的文本數據交換格式
  • JSON 獨立於語言:JSON 使用 Javascript語法來描述數據對象,但是 JSON 仍然獨立於語言和平台。JSON 解析器和 JSON 庫支持許多不同的編程語言。 目前非常多的動態(PHP,JSP,.NET)編程語言都支持JSON。
  • JSON 具有自我描述性,更易理解

結構與類型

  • 只有兩種結構:對象內的鍵值對集合結構和數組,對象用{}表示、內部是”key”:”value”,數組用[]表示,不同值用逗號分開
  • 基本數值有7個: false / null / true / object / array / number / string
  • 再加上結構可以嵌套,進而可以用來表達復雜的數據

一個簡單實例

{
   "Image": {
       "Width":  800,
       "Height": 600,
       "Title":  "View from 15th Floor",
       "Thumbnail": {
           "Url":    "http://www.example.com/image/481989943",
           "Height": 125,
           "Width":  "100"
       },
       "IDs": [116, 943, 234, 38793]
     }
}

JSON優秀資源

JSON在線解析工具

JSON類庫

Java中並沒有內置JSON的解析,因此使用JSON需要借助第三方類庫。

下面是幾個常用的 JSON 解析類庫:

  • FastJson: 阿里巴巴開發的 JSON 庫,性能十分優秀。
  • Jackson: 社區十分活躍且更新速度很快。
  • Gson: 谷歌開發的 JSON 庫,功能十分全面。

性能測試對比

從下面的測試結果可以看出,序列化次數比較小的時候,Gson性能最好,當不斷增加的時候到了100000,Gson明細弱於Jackson和FastJson, 這時候FastJson性能是真的牛,另外還可以看到不管數量少還是多,Jackson一直表現優異。而那個Json-lib可以直接忽略。

  • JSON序列化性能

  • JSON反序列化性能

更多請參考: Java幾種常用JSON庫性能比較

FastJson

Fastjson 簡介

Fastjson 是一個 Java 庫,可以將 Java 對象轉換為 JSON 格式,當然它也可以將 JSON 字符串轉換為 Java 對象。

Fastjson 可以操作任何 Java 對象,即使是一些預先存在的沒有源碼的對象。

Fastjson 特性

  • 提供服務器端、安卓客戶端兩種解析工具,性能表現較好。
  • 提供了 toJSONString() 和 parseObject() 方法來將 Java 對象與 JSON 相互轉換。調用toJSONString方 法即可將對象轉換成 JSON 字符串,parseObject 方法則反過來將 JSON 字符串轉換成對象。
  • 允許轉換預先存在的無法修改的對象(只有class、無源代碼)。
  • Java泛型的廣泛支持。
  • 允許對象的自定義表示、允許自定義序列化類。
  • 支持任意復雜對象(具有深厚的繼承層次和廣泛使用的泛型類型)。

下載和使用

你可以在 maven 中央倉庫中直接下載:http://repo1.maven.org/maven2/com/alibaba/fastjson/

配置 maven 依賴:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>x.x.x</version>
</dependency>

其中 x.x.x 是版本號,根據需要使用特定版本,建議使用最新版本。

序列化一個對象成JSON字符串

User user = new User();
user.setName("校長");
user.setAge(3);
user.setSalary(new BigDecimal("123456789.0123"));
String jsonString = JSON.toJSONString(user);
System.out.println(jsonString);
// 輸出 {"age":3,"name":"校長","old":false,"salary":123456789.0123}

反序列化一個JSON字符串成Java對象

String jsonString = "{\"age\":3,\"birthdate\":1496738822842,\"name\":\"校長\",\"old\":true,\"salary\":123456789.0123}";
 User u = JSON.parseObject(jsonString ,User.class);
 System.out.println(u.getName());
 // 輸出 校長

String jsonStringArray = "[{\"age\":3,\"birthdate\":1496738822842,\"name\":\"校長\",\"old\":true,\"salary\":123456789.0123}]";
List<User> userList = JSON.parseArray(jsonStringArray, User.class);
System.out.println(userList.size());
// 輸出 1

對於日期的處理

默認序列化Date輸出使用”yyyy-MM-dd HH:mm:ss”格式,可以用UseISO8601DateFormat特性換成”yyyy-MM-dd’T’HH:mm:ss”格式。

JSON.defaultTimeZone = TimeZone.getTimeZone("Asia/Shanghai");
JSON.defaultLocale = Locale.US;
        
public static class Model {
    @JSONField(format = "MMM dd, yyyy h:mm:ss aa")
    private java.util.Date date;

    public java.util.Date getDate() {
        return date;
    }

    public void setDate(java.util.Date date) {
        this.date = date;
    }

    @JSONField(format = "MMM-dd-yyyy h:mm:ss aa")
    public java.sql.Date date2;
}

Bean和數組轉換

設置字段名

public class A {
    @JSONField(name="ID")
    private int id;

    public int getId() {return id;}
    public void setId(int value) {this.id = id;}
}

設置是否不序列化某字段

public class A {
    @JSONField(serialize=false)
    public Date date;
}

public class A {
    @JSONField(deserialize=false)
    public Date date;
}

設置字段順序

public static class VO {
    @JSONField(ordinal = 3)
    private int f0;

    @JSONField(ordinal = 2)
    private int f1;

    @JSONField(ordinal = 1)
    private int f2;
}

自定義序列化和反序列化

FastJson漏洞問題

盡量使用最新版本。

JackSon

JackSon簡介

Jackson組件

3個核心模塊:

  • Streaming: jackson-core jar,定義了底層的streaming API和實現了Json特性。
  • Annotations: jackson-annotations jar,包含了標准的Jackson注解。本文暫不介紹。
  • Databind: jackson-databind jar,實現了數據綁定和對象序列化,它依賴於streaming和annotations的包。

第三方數據類型模塊

這些擴展是插件式的Jackson模塊,用ObjectMapper.registerModule()注冊,並且通過添加serializers和deserializers以便Databind包(ObjectMapper / ObjectReader / ObjectWriter)可以讀寫這些類型,來增加對各種常用的Java庫的數據類型的支持。

數據格式模塊

Jackson也有處理程序對JAX-RS標准實現者例如Jersey, RESTeasy, CXF等提供了數據格式支持。處理程序實現了MessageBodyReader和MessageBodyWriter,目前支持的數據格式包括JSON, Smile, XML, YAML和CBOR。

數據格式提供了除了Json之外的數據格式支持,它們絕大部分僅僅實現了streaming API abstractions,以便數據綁定組件可以按照原來的方式使用。另一些(幾乎不需要)提供了databind標准功能來處理例如schemas。

Jackson的使用

引用maven jar包:

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.10.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.10.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.10.1</version>
</dependency>

序列化一個對象成JSON字符串

public void toJson() throws JsonProcessingException {

    ObjectMapper mapper = new ObjectMapper();

    City case1 = new City();
    case1.setCity("SZ");
    case1.setAge(123);

    String jsonStr = mapper.writeValueAsString(case1);
    System.out.println("JSON:" + jsonStr);
}
// 輸出:JSON:{"city":"SZ","age":123}

反序列化一個JSON字符串成Java對象

public void toObj() throws JsonParseException, JsonMappingException, IOException {
    ObjectMapper mapper = new ObjectMapper();
    String inputjsonstr = "{\"city\":\"SZ\",\"age\":123}";
    
    City readcase = mapper.readValue(inputjsonstr, City.class);

    System.out.println("city info:" + readcase);
}

如果里面有未知屬性,比如json中有desc字段,但是City中沒有相應字段,會報錯, 需要設置如下:

mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

常用注解

  • @JsonProperty("xxx"): 將當前的屬性名在json字符串中重新命名為當前設置的這個值,比如在示例中,將age-->mAge
  • @JsonIgnore: 將被標注的屬性在生成json字符串的時候,直接忽略
  • @JsonInclude: 是一個類級別的設置,JsonInclude.Include.NON_EMPTY標識只有非NULL的值才會被納入json string之中,其余的都被忽略,比如這里的location屬性,並沒有出現在最終的結果字符串中。
  • @JsonSerialize: 使用自定義的類來實現自定義的字段轉換。寫入操作。
  • @JsonDeserialize: 解析的時候,自定義的轉換器;讀取操作。
  • @JsonAutoDetect: 設置類的訪問策略,是否所有的屬性都可以,還是按照一定的方式來提取。
  • @JsonRawValue: 無轉換的將屬性值寫入到json 字符串中。 寫入操作
  • @JsonValue: 標注方法,用以替代缺省的方法,由該方法來完成json的字符輸出。

GSON

Gson簡介

Gson是這樣一個Java類庫,它可以將Java對象轉換為相應的JSON形式,也可以將JSON字符串轉換為對應的Java對象。
Gson可以使用任意Java對象,包括哪些預先存在的、不在你的源代碼中的對象(因此,你並不知道對象的屬性)。

Gson的目標

  • 提供一種機制,使得將Java對象轉換為JSON或相反如使用toString()以及構造器(工廠方法)一樣簡單。
  • 允許預先存在的不可變的對象轉換為JSON或與之相反。
  • 允許自定義對象的表現形式
  • 支持任意復雜的對象
  • 輸出輕量易讀的JSON

Gson的使用

使用Gson的首要類是Gson類,你可以僅僅通過new Gson()的方式創建它。你也可以通過GsonBuilder類去創建Gson實例,這個類允許你進行一系列配置,例如版本控制等等。

Gson實例不會保存任何進行Json操作時的狀態。因此,你可以自由的服用相同的Gson對象進行諸多的Json序列化和反序列化操作。

引用maven jar包:

<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>28.2-jre</version>
</dependency>

序列化

// 基礎類型
Gson gson = new Gson();
gson.toJson(1);            ==> prints 1
gson.toJson("abcd");       ==> prints "abcd"
gson.toJson(new Long(10)); ==> prints 10
int[] values = { 1 };
gson.toJson(values);       ==> prints [1]

// 對象
BagOfPrimitives obj = new BagOfPrimitives();
Gson gson = new Gson();
String json = gson.toJson(obj);  
==> json is {"value1":1,"value2":"abc"}

// 數組
Gson gson = new Gson();
int[] ints = {1, 2, 3, 4, 5};
String[] strings = {"abc", "def", "ghi"};
gson.toJson(ints);     ==> prints [1,2,3,4,5]
gson.toJson(strings);  ==> prints ["abc", "def", "ghi"]

// 集合
Gson gson = new Gson();
Collection<Integer> ints = Lists.immutableList(1,2,3,4,5);
String json = gson.toJson(ints); ==> json is [1,2,3,4,5]

其中的對象代碼:

class BagOfPrimitives {
  private int value1 = 1;
  private String value2 = "abc";
  private transient int value3 = 3;
  BagOfPrimitives() {
    // no-args constructor
  }
}

反序列化

// 基礎類型
Gson gson = new Gson();
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);

// 對象
BagOfPrimitives obj2 = gson.fromJson(json, BagOfPrimitives.class);   
==> obj2 is just like obj

// 數組
Gson gson = new Gson();
int[] ints2 = gson.fromJson("[1,2,3,4,5]", int[].class); 
==> ints2 will be same as ints

// 集合
Gson gson = new Gson();
Type collectionType = new TypeToken<Collection<Integer>>(){}.getType();
Collection<Integer> ints2 = gson.fromJson(json, collectionType);
ints2 is same as ints

自定義序列化和反序列化機制

有時候,默認的實現並不是你想要的。這在處理類庫時常常發生(例如DateTime)。Gson允許你注冊自己自定義的序列化器和反序列化器。該過程分為兩部分:

  • Json序列化器:需要為一個對象自定義序列化機制。

  • Json反序列化器:需要為一個類型自定義反序列化機制。

實例構造者:並不需要,如果無參構造器是可用的或者注冊了一個反序列化器。

GsonBuilder gson = new GsonBuilder();
gson.registerTypeAdapter(MyType2.class, new MyTypeAdapter());
gson.registerTypeAdapter(MyType.class, new MySerializer());
gson.registerTypeAdapter(MyType.class, new MyDeserializer());
gson.registerTypeAdapter(MyType.class, new MyInstanceCreator());

registerTypeAdapter會檢查類型適配器是否實現了上面三個接口中的一個以上並且它們都注冊了類型適配器。

更多請參考:Gson用戶指南(中文翻譯)

參考文章

更多內容

最全的Java后端知識體系 https://www.pdai.tech, 每天更新中...


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM