簡體   English   中英

GSON:自定義對象反序列化

[英]GSON : custom object deserialization

好的,所以我編輯了這個問題因為它不夠清楚。

編輯2 :更新了JSON文件。

我在Android應用程序中使用GSON,我需要解析來自服務器的JSON文件,並且有點過於復雜。 我不希望我的對象結構太重,所以我想簡化內容: 所以我的對象的結構將不是JSON文件的結構。

例如,如果在JSON中我有這個:

{
    "object1":{
        "attribute1" : "test1",
        "attribute40" : "test40",
        "user":{
            "id":1,
            "name":"foo"
        }
        ,"example":{
            "total":10,
            "list":[
            {
                "tag":"tag1",
                "name":"object name 1",
                "pos":1
            },
            {
                "tag":"tag10",
                "name":"object name 10",
                "pos":10
            }
        ]
        }
    }
    "object2":{
        "attribute1":"test..."
    }
}

我不想保留我當前的對象結構,一個對象Example ,它包含一個ArrayList和一個int “total”。 但我想只保留一個簡單的String,其值為"object name 1;object name 2;..."

此外,我想只存儲用戶ID,而不是完整的用戶,因為我已經將完整的用戶存儲在其他地方,並且還有其他服務器API調用。

所以我的班級類似於:

class Foo{
    int userId;
    String example; //"object name 1;object name 2;..."
    ...
}

所以我想我們可以使用自定義反序列化器實現這一點,但我找不到如何。 我想盡可能減少內存,所以我不認為有一個完整的對象示例,然后使用它來構建我的String example是一種正確的方法。

在最壞的情況下,如果它太復雜,我希望能夠在解析示例對象時至少只存儲Tag項列表:所以我需要一個自定義反序列化器來擺脫int total

所以我會:

class Foo{
    int userId;
    ArrayList<Tag> example;
    ...
}

我采用了答案來呈現聊天中設計的完整解決方案,以適應更改的JSON字符串。 該代碼假定字符串json完全包含問題中的(更新的)JSON。 要求是填寫以下類(setter和toString ommitted):

class Object1
{
    private String attribute1;
    private String attribute40;
    private int userId;
    private String  nameList;
}

GSON支持(作為大多數其他REST-libs)三種模式:

  • GSON_DOM
    通過JsonParser.parse()讀取整個JSON,並在內存中構建DOM樹(對象模型訪問)。 因此,此解決方案適用於小型JSON文件。
  • GSON_STREAM
    通過JsonReader只讀取JSON的塊。 代碼更復雜,但它適用於大型JSON文件。 從Android 3.0 Honeycomb開始,GSON的流解析器包含在android.util.JsonReader
  • GSON_BIND
    通過反射直接數據綁定到類,最大限度地減少了代碼。 GSON允許混合模式,這意味着將GSON_DOM和GSON_BIND或GSON_STREAM和GSON_BIND結合起來,這個答案應該顯示出來。

要通過GSON_DOM和GSON_BIND填充Object1類,實現如下:

private static void deserializeViaObjectAccess(final String json)
{
    Gson gson = new Gson();

    // Read the whole JSON into meomory via GSON_DOM
    JsonParser parser = new JsonParser();
    JsonObject object1 = parser.parse(json).getAsJsonObject().getAsJsonObject("object1");

    // map the Object1 class via GSON_BIND
    // (bind common attributes which exist in JSON and as properties in the class)
    // mapper acts as factory
    Object1 result = gson.fromJson(object1, Object1.class);

    // manually read the attribute from the user object
    int userId = object1.getAsJsonObject("user").getAsJsonPrimitive("id").getAsInt();
    result.setUserId(userId);

    // manually read the attributes from the example object
    String names = "";
    JsonArray list = object1.getAsJsonObject("example").getAsJsonArray("list");
    for (int i = 0; i < list.size(); ++i)
    {
        JsonObject entry = list.get(i).getAsJsonObject();
        String name = entry.getAsJsonPrimitive("name").getAsString();

        names = i == 0 ? name : names + "; " + name;
    }
    result.setNameList(names);

    // Output the result
    log.debug(result.toString());
}

要通過GSON_STREAM和GSON_BIND填充Object1類,實現如下:

目前,這只有在通過GSON_BIND或GSON_STREAM完全加載節點時才有可能。 此示例需要分割節點本身。 這僅適用於即將推出的2.2版本。 稍后我會在GSON 2.2可用時提交代碼。*

其中一個選項是解析使用內部GSON內置詳見解析器JSON字符串這里 你會做這樣的事情:

com.google.gson.JsonParser parser = new JsonParser();
JsonObject object = parser.parse(data).getAsJsonObject();
JsonObject example = object.getAsJsonObject("example");
JsonArray list = example.getAsJsonArray("list");

JsonObjectJsonArray是Gson本身的一部分。

使用這些之后,您可以使用getAsInt等函數來解析單個字段,並構建並返回您想要的任何對象。

編輯1

看起來你也可以在自定義類上使用gson.fromJson而不僅僅是本例中給出的通用Java類型。 因此,您必須使用parse解析JSON字符串,並在其中一個內部對象或數組上調用fromJson。

將示例JSON序列化為完整的Example對象,使用Example對象的name屬性構建所需事物的String,忘記Example對象。

我並不完全理解第二個問題,但如果你有一個完整的Test1對象將所有的字段/屬性,那么你可以創建一個Test2對象,它從Test1獲取它想要的字段。 例如,您的Test2對象可以在其構造函數中接受Test1作為參數,並僅采用它忽略其余部分所需的屬性。

當您通過http在Jsons中進行流式傳輸時,您可以簡單地丟棄文本並僅存儲自定義對象。 在這種情況下,您將不斷丟棄不需要的信息。

While stream not empty  

    Read the next block into a new string

    Deserialize the string to the your object

    Store the object in a myArrayList

注意:如果您希望應用程序具有可靠性,則讀取整個JSON並將其作為一個整體使用是非常必要的。 除非您想將JSON讀作原始字符流(我懷疑,除非您的JSON真的非常大,否則這個快捷方式是必要的)。

Neverthelss,讀取輸入流而不強加和JSON良好構造要求,可以在不必編寫和不必要的數據結構到內存的情況下完成。 如果您只想要一小部分數據,這可能會有效 - 即您只需要人們的名字或JSON中的網址。 但如果您想要更復雜的數據結構,它就會崩潰。 不過:

//示例解析來自JSON行的URL而不存儲整個數據結構

While input stream is not empty

     String x = nextLine

     If x contains "http"

         myArrayList.add(parseUrl(x)

最后的想法 :

Bur最終,Jsons REST請求不像SQL那樣 - 你不能在通用和任意地忽略某些領域。也許,如果你真的想要更輕量級的Jsons,更自然的方法是告訴或檢查你的RESt服務提供商是否可以簡單地擴大類型RESt請求參數以適應您的用例。

我建議使用傑克遜圖書館。 它提供Apache許可證,因此您可以免費使用它進行商業用途。 教程中查看大寫“Streaming API Example”。 它非常簡單,您可以完全控制流式傳輸過程。 所以,你可以拿走你想要的東西而忽略所有其他的東西。 傑克遜圖書館分為幾個罐子。 支持流API的jar是最小的,不使用任何其他jar。 我想是答案。

傑克遜可以提供更多。 本文中,您可以找到在更高級別上讀取JSON文件的方法,作為元素,但是在PREVIOUSLY中設置您需要的對象和不需要的對象。 因此,您可以立即解析所需的元素。

暫無
暫無

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

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