从 JSON 中确定对象类型并使用 GSON 创建对象
Determining type of Object from JSON and create object using GSON
我在我的应用程序中使用 Gson,其中有几个 Java 对象,我通过使用 GSON 将其转换为 JSON 来呈现给前端。我知道如何使用 gson 将 JSON 转换回 Java 对象。
我有这个用例:
当我向 GSON 提供一个特定的 JSON 字符串时,我希望它找到从中获取 JSON 字符串的对象的类型,并给我一个该类型的对象。
使用 GSON,只有在 fromJson
方法中传递对象 class 才能取回对象。但是无论如何我可以让 gson
自己确定它吗? 我无法控制另一边生成的对象。
示例:
Person person = new Person();
SomeRandomObject obj = new SomeRandomObject();
String personJson = gson.toJson(person);
String anotherJson = gson.toJson(obj);
现在如果我想将它转换回对象,我使用这个:
Person p = gson.fromJson(personJson,Person.class);
但是无论如何我可以得到这样的对象:
Object object = gson.fromJson(anotherJson,*TheCorrespondingObject.class*)
我知道我可以通过使用 Gson 抛出异常的不同对象尝试我的 JSON 字符串来实现这一点,但我认为这不是正确的方法。
一般答案:您必须在生成的 JSON 中添加一些内容以表明它是从什么生成的。
说,而不是
{
"name": "John"
}
你会生成类似这样的东西:
{
"type": "Customer"
"name": "John"
}
如何在 GSON 中执行此操作留给 reader 作为练习。 ;)
编辑:哦,你不能篡改 JSON。那没关系。
不过,如果没有某种标识符,很难以通用方式执行此操作,特别是考虑到某些 类 可能碰巧具有完全相同的字段。
最好、最简单的方法是将 JSON 本身包装在包含该类型的容器中。
例如:
{
"foo":"bar"
}
变成
{
"type":"FooContainer"
"value": {
"foo":"bar"
}
}
但是,你说你不能那样做,所以我不会详细介绍如何实际进行反序列化。如果你能做这个有限的改变,你可以写一个 TypeAdapterFactory
并让 Gson 做 all 剩下的工作,通过使用传递的 Gson
对象create()
方法,在read方法中调用gson.fromJson()
,代码会比下面的方法少很多
想想这里真正需要发生什么。不知何故,您需要检测 Websphere MQ 对象中的数据并使用它来计算。以这种方式检测它会获取代码,分析您收到的数据,并吐出正确的对象。
您要面对的第一个问题是您不想这样做:
Object myObj = gson.fromJson(jsonString, Object.class);
这意味着您正在覆盖默认的基本反序列化器,它可能会产生各种令人讨厌的副作用。对于某种自定义对象,最好将行为包装在 TypeAdapter
中:
public class Wrapper {
public Object data; // Encapsulate this if you want, this is just for brevity
}
我会把铸造/泛型留给你。有很多方法可以做到这一点,但我推荐 Visitor Pattern as a good choice, or perhaps creating an enum type object。如果您可以让所有接收到的对象类型都实现某种接口以简化此操作,那将是最好的,但是,同样,这不是您的主要问题。
您的主要问题实际上是在代码中检测这些 classes。现在我们有了包装器 class,我们可以使用它:
Wrapper myWrapper = gson.fromJson(jsonString, Wrapper.class);
现在,生成的每个 class 都是相同的 class,所以 Gson 很高兴。但是我们把规则放在哪里呢?他们按照您的习惯 TypeAdapter
:
public class WrapperTypeAdapter extends TypeAdapter<Wrapper> {
@Override
public final void write(JsonWriter out, Wrapper value) throws IOException {
if(value == null) {
out.nullValue();
return;
}
// Don't worry about Write for now, obviously
}
@Override
public final Wrapper read(JsonReader in) throws IOException {
if(in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
Wrapper wrapper = new Wrapper();
// HERE IS WHERE YOU GET TO WRITE CODE
return wrapper;
}
}
在 read 方法中,当您流式传输令牌时,您可以使用基于您对 JSON 令牌本身的预期的规则来决定 class 它将会是什么,然后构造新对象。我建议将其分解为许多方法,如 MyFoo readMyFoo(JsonReader)
、MyBar readMyBar(JsonReader)
等。如果不了解 JSON 本身,我很难深入了解更多细节,但这应该足够了让你开始。
通过分析原始字符串手动:
if (jsonString.indexOf(..) > 0) {
//reading Person
} else {
//reading SomeRandomObject
}
或者您可以使用 JSON 简单并阅读任何 JSON
我在我的应用程序中使用 Gson,其中有几个 Java 对象,我通过使用 GSON 将其转换为 JSON 来呈现给前端。我知道如何使用 gson 将 JSON 转换回 Java 对象。
我有这个用例: 当我向 GSON 提供一个特定的 JSON 字符串时,我希望它找到从中获取 JSON 字符串的对象的类型,并给我一个该类型的对象。
使用 GSON,只有在 fromJson
方法中传递对象 class 才能取回对象。但是无论如何我可以让 gson
自己确定它吗? 我无法控制另一边生成的对象。
示例:
Person person = new Person();
SomeRandomObject obj = new SomeRandomObject();
String personJson = gson.toJson(person);
String anotherJson = gson.toJson(obj);
现在如果我想将它转换回对象,我使用这个:
Person p = gson.fromJson(personJson,Person.class);
但是无论如何我可以得到这样的对象:
Object object = gson.fromJson(anotherJson,*TheCorrespondingObject.class*)
我知道我可以通过使用 Gson 抛出异常的不同对象尝试我的 JSON 字符串来实现这一点,但我认为这不是正确的方法。
一般答案:您必须在生成的 JSON 中添加一些内容以表明它是从什么生成的。
说,而不是
{
"name": "John"
}
你会生成类似这样的东西:
{
"type": "Customer"
"name": "John"
}
如何在 GSON 中执行此操作留给 reader 作为练习。 ;)
编辑:哦,你不能篡改 JSON。那没关系。
不过,如果没有某种标识符,很难以通用方式执行此操作,特别是考虑到某些 类 可能碰巧具有完全相同的字段。
最好、最简单的方法是将 JSON 本身包装在包含该类型的容器中。
例如:
{
"foo":"bar"
}
变成
{
"type":"FooContainer"
"value": {
"foo":"bar"
}
}
但是,你说你不能那样做,所以我不会详细介绍如何实际进行反序列化。如果你能做这个有限的改变,你可以写一个 TypeAdapterFactory
并让 Gson 做 all 剩下的工作,通过使用传递的 Gson
对象create()
方法,在read方法中调用gson.fromJson()
,代码会比下面的方法少很多
想想这里真正需要发生什么。不知何故,您需要检测 Websphere MQ 对象中的数据并使用它来计算。以这种方式检测它会获取代码,分析您收到的数据,并吐出正确的对象。
您要面对的第一个问题是您不想这样做:
Object myObj = gson.fromJson(jsonString, Object.class);
这意味着您正在覆盖默认的基本反序列化器,它可能会产生各种令人讨厌的副作用。对于某种自定义对象,最好将行为包装在 TypeAdapter
中:
public class Wrapper {
public Object data; // Encapsulate this if you want, this is just for brevity
}
我会把铸造/泛型留给你。有很多方法可以做到这一点,但我推荐 Visitor Pattern as a good choice, or perhaps creating an enum type object。如果您可以让所有接收到的对象类型都实现某种接口以简化此操作,那将是最好的,但是,同样,这不是您的主要问题。
您的主要问题实际上是在代码中检测这些 classes。现在我们有了包装器 class,我们可以使用它:
Wrapper myWrapper = gson.fromJson(jsonString, Wrapper.class);
现在,生成的每个 class 都是相同的 class,所以 Gson 很高兴。但是我们把规则放在哪里呢?他们按照您的习惯 TypeAdapter
:
public class WrapperTypeAdapter extends TypeAdapter<Wrapper> {
@Override
public final void write(JsonWriter out, Wrapper value) throws IOException {
if(value == null) {
out.nullValue();
return;
}
// Don't worry about Write for now, obviously
}
@Override
public final Wrapper read(JsonReader in) throws IOException {
if(in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
Wrapper wrapper = new Wrapper();
// HERE IS WHERE YOU GET TO WRITE CODE
return wrapper;
}
}
在 read 方法中,当您流式传输令牌时,您可以使用基于您对 JSON 令牌本身的预期的规则来决定 class 它将会是什么,然后构造新对象。我建议将其分解为许多方法,如 MyFoo readMyFoo(JsonReader)
、MyBar readMyBar(JsonReader)
等。如果不了解 JSON 本身,我很难深入了解更多细节,但这应该足够了让你开始。
通过分析原始字符串手动:
if (jsonString.indexOf(..) > 0) {
//reading Person
} else {
//reading SomeRandomObject
}
或者您可以使用 JSON 简单并阅读任何 JSON