簡體   English   中英

將對象序列化為Json

[英]Serializing Object to Json

我正在嘗試使用Gson來獲取一些Java Object並將其序列化為json並獲取表示該Json的字節數組。 我需要一個字節數組,因為我將輸出傳遞給需要它為字節數組的外部依賴項。

public byte[] serialize(Object object){
  return gson.toJson(object).getBytes();
}

我有兩個問題:

  1. 如果輸入是String,則gson似乎會按原樣返回String。 它不對輸入進行任何驗證。 這是預期的嗎? 我想以一種可以驗證輸入對象實際上是Json的方式使用Gson。 我該怎么辦?
  2. 我要在短時間內調用該序列化函數數千次。 轉換為String然后轉換為byte[]可能會帶來一些不必要的開銷。 是否有更優化的方法來獲取byte[]

編輯:我對第1點的回答是錯誤的。

2)如果您僅使用普通gson轉換器,則會有很多不必要的反射開銷。 在您的情況下,編寫自定義適配器將極大地提高性能。 這是一篇關於該內容的更多信息的文章https://open.blogs.nytimes.com/2016/02/11/improving-startup-time-in-the-nytimes-android-app/?_r=0

如果輸入是String,則gson似乎會按原樣返回String。 它不對輸入進行任何驗證。 這是預期的嗎?

是的,這很好。 它只是返回給定字符串的JSON字符串表示形式。

我想以一種可以驗證輸入對象實際上是Json的方式使用Gson。 我該怎么辦?

本身就不需要。 Gson.toJson()方法接受要序列化的對象,並始終生成有效的JSON。 如果您要進行反序列化,則Gson會在讀取/解析/反序列化過程中對無效的JSON文檔進行快速失敗(實際上是讀取,這是Gson的最底層)。

我要在短時間內調用該序列化函數數千次。 轉換為String然后轉換為byte []可能會帶來一些不必要的開銷。 是否有更優化的方法來獲取byte []?

是的,僅為了公開其內部char[]克隆而累積JSON字符串會浪費內存。 Gson基本上是一種面向流的工具,請注意,有一些Gson.toJson方法重載接受了Appendable ,而這些重載基本上是Gson核心(只是快速了解Gson.fromJson(Object)工作方式-它只是創建一個StringWriter實例由於Appendable接口而累積了一個字符串)。 如果Gson可以通過Reader而不是寫入Appendable發出JSON令牌,那將非常酷,但是很遺憾,這個想法被拒絕了,很可能永遠不會在Gson中實現。 由於Gson在反序列化期間不會以讀取語義的方式(從您的代碼角度)發出JSON令牌,因此您必須緩沖整個結果:

private static byte[] serializeToBytes(final Object object)
        throws IOException {
    final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    final OutputStreamWriter writer = new OutputStreamWriter(outputStream);
    gson.toJson(object, writer);
    writer.flush();
    return outputStream.toByteArray();
}

這個不使用StringWriter因此不會累積帶有克隆數組ping-pong的中間字符串。 我不知道是否有可以利用/重用現有字節數組的編寫器/輸出流,但是我相信應該有一些,因為它為您在問題中提到的性能目的提供了很好的理由。

如果可能的話,您還可以檢查庫接口/ API是否以某種方式公開/接受OutputStream那么您可以輕松地將此類輸出流傳遞給serializeToBytes方法,甚至刪除該方法。 如果它可以使用輸入流,而不僅僅是字節數組,那么您還可以看一下將輸出流轉換為輸入流,以便serializeToBytes方法可以返回InputStreamReader (需要一些開銷,但可以處理無限數據-找到余額):

private static InputStream serializeToByteStream(final Object object)
        throws IOException {
    final PipedInputStream inputStream = new PipedInputStream();
    final OutputStream outputStream = new PipedOutputStream(inputStream);
    new Thread(() -> {
        try {
            final OutputStreamWriter writer = new OutputStreamWriter(outputStream);
            gson.toJson(object, writer);
            writer.flush();
        } catch ( final IOException ex ) {
            throw new RuntimeException(ex);
        } finally {
            try {
                outputStream.close();
            } catch ( final IOException ex ) {
                throw new RuntimeException(ex);
            }
        }
    }).start();
    return inputStream;
}

使用示例:

final String value = "foo";
System.out.println(Arrays.toString(serializeToBytes(value)));
try ( final InputStream inputStream = serializeToByteStream(value) ) {
    int b;
    while ( (b = inputStream.read()) != -1 ) {
        System.out.print(b);
        System.out.print(' ');
    }
    System.out.println();
}

輸出:

[34,102,111,111,34]
34102111111 34

兩者都代表一個ASCII碼數組,從字面上表示一個字符串"foo"

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM