簡體   English   中英

Gson - 基於字段值反序列化為特定對象類型

[英]Gson - deserialization to specific object type based on field value

我想根據type字段值將 json 對象反序列化為特定類型的對象(使用 Gson 庫),例如:

[
    {
          "type": "type1",
          "id": "131481204101",
          "url": "http://something.com",
          "name": "BLAH BLAH",
          "icon": "SOME_STRING",
          "price": "FREE",
          "backgroundUrl": "SOME_STRING"
    },
    {
        ....
    }
]

因此type字段將具有不同(但已知)的值。 基於該值,我需要將該 json 對象反序列化為適當的模型對象,例如:Type1Model、Type2Model 等。我知道我可以在反序列化之前通過將其轉換為JSONArray輕松做到這一點,遍歷它並解析它應該反序列化的類型到。 但我認為這是丑陋的方法,我正在尋找更好的方法。 有什么建議?

您可以實現JsonDeserializer並在將 Json 值解析為 Java 實例時使用它。 我將嘗試用一個代碼來展示它,它會給你一個想法:

1)定義您的自定義JsonDeserializer類,該類通過傳入的 json 值的 id 屬性創建不同的類實例:

class MyTypeModelDeserializer implements JsonDeserializer<MyBaseTypeModel> {

    @Override
    public MyBaseTypeModel deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context)
            throws JsonParseException {

        JsonObject jsonObject = json.getAsJsonObject();

        JsonElement jsonType = jsonObject.get("type");
        String type = jsonType.getAsString();

        MyBaseTypeModel typeModel = null;     

        if("type1".equals(type)) {
            typeModel = new Type1Model();
        } else if("type2".equals(type)) {
            typeModel = new Type2Model();
        }
        // TODO : set properties of type model

        return typeModel;
    }
}

2)為不同的java對象實例定義一個基類:

class  MyBaseTypeModel {
    private String type;
    // TODO : add other shared fields here
}

3)定義擴展基類的java對象類的不同實例:

class Type1Model extends MyBaseTypeModel {
    // TODO: add specific fields for this class
}

class Type2Model extends MyBaseTypeModel {
    // TODO: add specific fields for this class
}

4) 在將 json 值解析為 bean 時使用這些類:

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(MyBaseTypeModel.class, new MyTypeModelDeserializer());
Gson gson = gsonBuilder.create();

MyBaseTypeModel myTypeModel = gson.fromJson(myJsonString, MyBaseTypeModel.class);

我現在無法測試它,但我希望你能明白。 此外,此鏈接將非常有幫助。

@stephane-k 的回答有效,但有點令人困惑,可以改進(請參閱對他的回答的評論)

https://github.com/google/gson/blob/master/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java復制到您的項目中。 (沒關系;這些類旨在復制/粘貼https://github.com/google/gson/issues/845#issuecomment-217231315

設置模型繼承:

// abstract is optional
abstract class BaseClass {
}

class Type1Model extends BaseClass {
}

class Type2Model extends BaseClass {
}

設置 GSON 或更新現有 GSON:

RuntimeTypeAdapterFactory<BaseClass> typeAdapterFactory = RuntimeTypeAdapterFactory
        .of(BaseClass.class, "type")
        .registerSubtype(Type1Model.class, "type1")
        .registerSubtype(Type2Model.class, "type2");

Gson gson = new GsonBuilder().registerTypeAdapterFactory(typeAdapterFactory)
                .create();

將您的 JSON 反序列化為基類:

String jsonString = ...
BaseClass baseInstance = gson.fromJson(jsonString, BaseClass.class);

baseInstance將是Type1ModelType2Model

從這里您可以編碼到接口或檢查 instanceof 和強制轉換。

使用https://github.com/google/gson/blob/master/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java

然后配置它

public static final class JsonAdapterFactory extends 
    RuntimeTypeAdapterFactory<MediumSummaryInfo> {
        public JsonAdapterFactory() {
            super(MyBaseType.class, "type");
            registerSubtype(MySubtype1.class, "type1");
            registerSubtype(MySubtype2.class, "type2");
        }
}

並添加注釋:

@JsonAdapter(MyBaseType.JsonAdapterFactory.class)

到 MyBaseType

好多了。

如果您有很多子類型並且您不想或無法維護它們的列表,您也可以使用基於注釋的方法。

這是所需的代碼和一些使用示例: https : //gist.github.com/LostMekka/d90ade1fe051732d6b4ac60deea4f9c2 (它是 Kotlin,但可以輕松移植到 Java)

對我來說,這種方法特別有吸引力,因為我編寫了一個在編譯時不知道所有可能子類型的小型庫。

暫無
暫無

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

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