构建一个可以为子类

时间:2017-04-01 17:07:59

标签: android json inheritance serialization gson

我有一个对象列表,我需要将其反序列化到正确的子类中。我已经能够通过构建像下面的

这样的gson对象来实现这一点
    JsonDeserializer<Shape> jdTypes = (json, typeOfT, jsonContext) -> {
        JsonObject jsonObject = json.getAsJsonObject();
        int type = jsonObject.get("type").getAsInt();

        Gson gson = new Gson();

        switch (type){
            case Types.TYPE_CARD:
                return gson.fromJson(json, Card.class);

            case Types.TYPE_BLOCK:
                return gson.fromJson(json, Block.class);

            case Types.TYPE_STRIPE:
                return gson.fromJson(json, Stripe.class);

            //...

        }
    };

    GsonBuilder builder = new GsonBuilder();
    builder.registerTypeAdapter(Shape.class, jdTypes);
    builder.create();

虽然它有效但必须有更好的方法。目前我正在我的GsonBuilder中创建一个Gson实例。让人惊讶。有没有办法可以使用我要构建的Gson对象来反序列化不同的子类型?

2 个答案:

答案 0 :(得分:1)

如果我正确理解了这个问题,您可以直接使用JsonDeserializationContext

return jsonContext.deserialize(json, classOfType(type));

classOfType()应该返回与您的形状的type对应的类。

答案 1 :(得分:1)

无需重新发明轮子。你的问题在Gson的范围内是经典的,并且有一个特殊的RuntimeTypeAdapterFactory旨在解决这种类型的问题。例如,如果你有这样的东西:

final class Types {

    private Types() {
    }

    static final int TYPE_CARD = 1;
    static final int TYPE_BLOCK = 2;
    static final int TYPE_STRIPE = 3;

    abstract static class Abstract {

        private Abstract() { }

        static final class Card extends Abstract { }    
        static final class Block extends Abstract { }   
        static final class Stripe extends Abstract {}

    }

}

您可以配置和使用RuntimeTypeAdapterFactory

private static final Gson gson = new GsonBuilder()
        .registerTypeAdapterFactory(
                RuntimeTypeAdapterFactory.of(Types.Abstract.class, "type")
                        .registerSubtype(Types.Abstract.Card.class, String.valueOf(Types.TYPE_CARD))
                        .registerSubtype(Types.Abstract.Block.class, String.valueOf(Types.TYPE_BLOCK))
                        .registerSubtype(Types.Abstract.Stripe.class, String.valueOf(Types.TYPE_STRIPE))
        )
        .create();

然后你甚至不需要任何其他东西:

private static final Type abstractListType = new TypeToken<List<Types.Abstract>>() {
}.getType();

public static void main(final String... args) {
    gson.<List<Types.Abstract>>fromJson("[{\"type\":1},{\"type\":2},{\"type\":3}]", abstractListType)
            .stream()
            .map(Types.Abstract::getClass)
            .forEach(System.out::println);
}

输出:

  

class q43159721.Types $ Abstract $ Card
  class q43159721.Types $ Abstract $ Block
  class q43159721.Types $ Abstract $ Stripe