我有一个类层次结构,我想要转换为GSON和从GSON转换。我不确定如何使用GSON来处理这个问题(我目前有一个Factory
类来查看JSONObject,并根据它调用正确构造函数的键的存在与否,而后者又将其部分工作委托给超级)。当我将这些对象存储在本地SQLite DB中时,我使用一个整数来表示它们的类型,工厂类使用这种类型来调用正确的构造函数。我在JSON中没有 type (这不是我的)。
如何根据JSON对象的内容告诉GSON要为我实例化哪种对象?
在下面的示例中,将JSON括号内的...
视为可能有或没有更多元素
以下是类层次结构的细分:
有一个基本抽象类型:SuperType
,带有JSON表示{"ct":12345,"id":"abc123 ...}
有两个主要的抽象子类型:TypeA
(有json键“a”)和TypeB
(有json键“b”)
类型A
示例:{"ct":12345,"id":"abc123, "a":{...}}
TypeA
有15个孩子(我们将这些TypeA_A
称为TypeA_P
)。这些对象的JSON表示类似于{"ct":12345,"id":"abc123, "a":{"aa":1 ...} ...}
或{"ct":12345,"id":"abc123, "a":{"ag":"Yo dawg I head you like JSON" ...} ...}
的TypeB
示例:{"ct":12345,"id":"abc123, "b":{...} ...}
TypeB
有另一个抽象子类型(TypeB_A
)和几个孩子(让我们将这些TypeB_B
称为TypeB_I
)。这些对象的JSON表示形式为{"ct":12345,"id":"abc123, "b":{"ba":{...} ...} ...}
或{"ct":12345,"id":"abc123, "b":{"bg":"Stayin alive" ...} ...}
我可以将它全部抛弃在一个怪物类型中并将每个子类型视为内部对象,但我最终会得到很多内部成员为null(有点像一棵树,有很多树枝,无处可去)。结果,我最终会得到很多if (something==null)
,只是为了确定我正在处理的这些类型中的哪一种。
我查看了TypeAdapter
和TypeAdapterFactory
,但由于我必须查看传入JSON的内容,因此我仍然不确定如何处理此问题。
如何根据JSON对象的内容告诉GSON要为我实例化哪种对象?
感谢。
答案 0 :(得分:5)
因此,RTTAF方法是朝着正确的方向发展,但它希望我有一个字段来表示我正在使用哪个子类型。在我的具体情况下,我有这些亚型的子类型和子类型。这就是我最终做的事情:
注意:在我的测试项目(下面)中,我使用GSON和Lombok进行注释。
类型工厂
public class CustomTypeAdapterFactory implements TypeAdapterFactory {
@Override
public <T> TypeAdapter<T> create (final Gson gson, final TypeToken<T> type) {
if (type.getRawType () != SuperType.class)
return null;
final TypeAdapter<T> delegate = gson.getDelegateAdapter (this, type);
return new TypeAdapter<T> () {
@Override
public void write (final JsonWriter jsonWriter, final T t) throws IOException {
delegate.write (jsonWriter, t);
}
@Override
public T read (final JsonReader jsonReader) throws IOException, JsonParseException {
JsonElement tree = Streams.parse (jsonReader);
JsonObject object = tree.getAsJsonObject ();
if (object.has ("a"))
return (T) readTypeA (tree, object.getAsJsonObject ("a"));
if (object.has ("b"))
return (T) readTypeB (tree, object.getAsJsonObject ("b"));
throw new JsonParseException ("Cannot deserialize " + type + ". It is not a valid SuperType JSON.");
}
private TypeA readTypeA (final JsonElement tree, final JsonObject a) {
if (a.has ("aa"))
return gson.getDelegateAdapter (CustomTypeAdapterFactory.this, TypeToken.get (TypeA_A.class)).fromJsonTree (tree);
if (a.has ("ab"))
return gson.getDelegateAdapter (CustomTypeAdapterFactory.this, TypeToken.get (TypeA_B.class)).fromJsonTree (tree);
if (a.has ("ac"))
return gson.getDelegateAdapter (CustomTypeAdapterFactory.this, TypeToken.get (TypeA_C.class)).fromJsonTree (tree);
throw new JsonParseException ("Cannot deserialize " + type + ". It is not a valid TypeA JSON.");
}
private TypeB readTypeB (final JsonElement tree, final JsonObject b) {
if (b.has ("ba"))
return gson.getDelegateAdapter (CustomTypeAdapterFactory.this, TypeToken.get (TypeB_A.class)).fromJsonTree (tree);
if (b.has ("bb"))
return gson.getDelegateAdapter (CustomTypeAdapterFactory.this, TypeToken.get (TypeB_B.class)).fromJsonTree (tree);
if (b.has ("bc"))
return gson.getDelegateAdapter (CustomTypeAdapterFactory.this, TypeToken.get (TypeB_C.class)).fromJsonTree (tree);
throw new JsonParseException ("Cannot deserialize " + type + ". It is not a valid TypeB JSON.");
}
};
}
}
<强> SuperType.java 强>
@Getter
@Setter
@EqualsAndHashCode
@ToString
public class SuperType {
@SerializedName ("ct")
protected long creationTime;
@SerializedName ("id")
protected String id;
}
Type_A
在其级别中没有其他数据,但确实有一些常见的行为(为简单起见,这里省略了方法,因为它们与解析无关)。
<强> TypeA.java 强>
@Getter
@Setter
@EqualsAndHashCode (callSuper = true)
@ToString (callSuper = true)
public class TypeA extends SuperType {}
<强> TypeA_A.java 强>
@Getter
@Setter
@EqualsAndHashCode (callSuper = true)
@ToString(callSuper = true)
public class TypeA_A
extends TypeA {
@SerializedName ("a")
protected AA aValue;
@ToString
private static class AA {
@SerializedName ("aa")
private String aaValue;
}
}
其他Type_A儿童与TypeA_A非常相似。
Type_B
稍微复杂一些,因为它有自己的数据和行为(为简单起见,再次省略):
<强> TypeB.java 强>
@Getter
@Setter
@EqualsAndHashCode (callSuper = true)
@ToString (callSuper = true)
public class TypeB extends SuperType {
// no member declared here
protected static abstract class B {
@SerializedName ("b1")
protected String b1Value;
@SerializedName ("b2")
protected String b2Value;
}
}
<强> Type_BA.java 强>
@Getter
@Setter
@EqualsAndHashCode (callSuper = true)
@ToString (callSuper = true)
public class TypeB_A
extends TypeB {
@SerializedName ("b")
protected BA bValue;
@ToString
private static class BA extends B {
@SerializedName ("ba")
private String baValue;
}
}
<强> TypeB_B.java 强>
@Getter
@Setter
@EqualsAndHashCode (callSuper = true)
@ToString (callSuper = true)
public class TypeB_B
extends TypeB {
@SerializedName ("b")
protected BB bValue;
@ToString
private static class BB extends B {
@SerializedName ("bb")
private String bbValue;
@SerializedName ("bb1")
private String bb1Value;
}
}
这里可能存在一些拼写错误,因为我必须更改实际的类型名称和值,但我将创建一个基本的java代码示例并将发布到Github。
感谢@Jesse Wilson和@Argyle帮助我指明正确的方向。
答案 1 :(得分:4)
有一个名为RuntimeTypeAdapterFactory的标准扩展名TypeAdapter
,可以说明这一点。
test case提供了一些示例代码:
RuntimeTypeAdapterFactory<BillingInstrument> rta = RuntimeTypeAdapterFactory.of(
BillingInstrument.class)
.registerSubtype(CreditCard.class);
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(rta)
.create();
CreditCard original = new CreditCard("Jesse", 234);
assertEquals("{\"type\":\"CreditCard\",\"cvv\":234,\"ownerName\":\"Jesse\"}",
gson.toJson(original, BillingInstrument.class));
BillingInstrument deserialized = gson.fromJson(
"{type:'CreditCard',cvv:234,ownerName:'Jesse'}", BillingInstrument.class);
assertEquals("Jesse", deserialized.ownerName);
assertTrue(deserialized instanceof CreditCard);