反序列化 JSON 具有随机名称的数组 - GSON
Deserialize JSON Array with random name - GSON
我正在尝试使用 GSON 反序列化一个复杂的 JSON 结构。 API 提供程序通过在结果中提供一个随机名称的数组来使事情复杂化。
这是 (simplified/generified) JSON:
{
"field_1": "value",
"field_2": "value",
"field_3": {
"RANDOM_NAME": [
{
"array_field_1": "value",
"array_field_2": "value",
"array_field_3": "value"
},
{
"array_field_1": "value",
"array_field_2": "value",
"array_field_3": "value"
}
]
},
"field_4": "value"
}
这是对应的(高度简化的)POJO:
public class responseObject {
String field_1;
String field_2;
Field3 field_3;
String field_4;
class Field3{
ArrayObject[] arrayObjects;
}
class ArrayObject{
String array_field_1;
String array_field_2;
String array_field_3;
}
}
然而,当我 运行 responseObject response = new Gson().fromJson(getJSON(),responseObject.class);
我得到以下调用堆栈:
表明 field_3
没有被正确反序列化并且不包含 ArrayObject
.
的数组
this post 中的答案参考了如何将数据转换为地图,但在我的例子中,数组中每个项目的数据结构实际上比这个简化的例子大得多,如果我必须从复杂的嵌套地图列表中手动选择我需要的数据,那么它就违背了使用 GSON 的目的。在随机对象是数组而不是普通 json 对象的情况下,也无法让这些答案起作用。
如何获取 JSON 中随机命名的数组以正确反序列化为变量 responseObject.Field3.arrayObjects
?
这可以通过编写自定义 TypeAdapter
for Field3
which ignores the name of the property and only reads the value. The TypeAdapter
has to be created by a TypeAdapterFactory
以允许获取 ArrayObject[]
:
的委托适配器来解决
class Field3TypeAdapterFactory implements TypeAdapterFactory {
public Field3TypeAdapterFactory() {
}
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
// Only support Field3 class
if (type.getRawType() != Field3.class) {
return null;
}
TypeAdapter<ArrayObject[]> fieldValueAdapter = gson.getAdapter(ArrayObject[].class);
// Cast is safe, check at beginning made sure type is Field3
@SuppressWarnings("unchecked")
TypeAdapter<T> adapter = (TypeAdapter<T>) new TypeAdapter<Field3>() {
@Override
public void write(JsonWriter out, Field3 value) throws IOException {
throw new UnsupportedOperationException("Serialization is not supported");
}
@Override
public Field3 read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
in.beginObject();
// Skip the random property name
in.skipValue();
ArrayObject[] fieldValue = fieldValueAdapter.read(in);
in.endObject();
Field3 object = new Field3();
object.arrayObjects = fieldValue;
return object;
}
};
return adapter;
}
}
然后您可以 register the factory with a GsonBuilder
, or you can annotate your Field3
class with @JsonAdapter
。使用 @JsonAdapter
时,工厂 class 应该有一个 no-args 构造函数。
您可以通过将类型设为 field_3 Map<String, List<ArrayObject>>
来避免使用 TypeAdapeter 的复杂性
public class responseObject {
String field_1;
String field_2;
Map<String, List<ArrayObject>> field_3;
String field_4;
class ArrayObject{
String array_field_1;
String array_field_2;
String array_field_3;
}
}
然后在不知道其键值的情况下从地图中取出第一项,您可以使用:
public List<ResponseObject.ArrayObject> getFirstValue(Map<String, List<ResponseObject.ArrayObject>> field_3) {
return field_3.values().iterator().next();
}
我正在尝试使用 GSON 反序列化一个复杂的 JSON 结构。 API 提供程序通过在结果中提供一个随机名称的数组来使事情复杂化。
这是 (simplified/generified) JSON:
{
"field_1": "value",
"field_2": "value",
"field_3": {
"RANDOM_NAME": [
{
"array_field_1": "value",
"array_field_2": "value",
"array_field_3": "value"
},
{
"array_field_1": "value",
"array_field_2": "value",
"array_field_3": "value"
}
]
},
"field_4": "value"
}
这是对应的(高度简化的)POJO:
public class responseObject {
String field_1;
String field_2;
Field3 field_3;
String field_4;
class Field3{
ArrayObject[] arrayObjects;
}
class ArrayObject{
String array_field_1;
String array_field_2;
String array_field_3;
}
}
然而,当我 运行 responseObject response = new Gson().fromJson(getJSON(),responseObject.class);
我得到以下调用堆栈:
表明 field_3
没有被正确反序列化并且不包含 ArrayObject
.
this post 中的答案参考了如何将数据转换为地图,但在我的例子中,数组中每个项目的数据结构实际上比这个简化的例子大得多,如果我必须从复杂的嵌套地图列表中手动选择我需要的数据,那么它就违背了使用 GSON 的目的。在随机对象是数组而不是普通 json 对象的情况下,也无法让这些答案起作用。
如何获取 JSON 中随机命名的数组以正确反序列化为变量 responseObject.Field3.arrayObjects
?
这可以通过编写自定义 TypeAdapter
for Field3
which ignores the name of the property and only reads the value. The TypeAdapter
has to be created by a TypeAdapterFactory
以允许获取 ArrayObject[]
:
class Field3TypeAdapterFactory implements TypeAdapterFactory {
public Field3TypeAdapterFactory() {
}
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
// Only support Field3 class
if (type.getRawType() != Field3.class) {
return null;
}
TypeAdapter<ArrayObject[]> fieldValueAdapter = gson.getAdapter(ArrayObject[].class);
// Cast is safe, check at beginning made sure type is Field3
@SuppressWarnings("unchecked")
TypeAdapter<T> adapter = (TypeAdapter<T>) new TypeAdapter<Field3>() {
@Override
public void write(JsonWriter out, Field3 value) throws IOException {
throw new UnsupportedOperationException("Serialization is not supported");
}
@Override
public Field3 read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
in.beginObject();
// Skip the random property name
in.skipValue();
ArrayObject[] fieldValue = fieldValueAdapter.read(in);
in.endObject();
Field3 object = new Field3();
object.arrayObjects = fieldValue;
return object;
}
};
return adapter;
}
}
然后您可以 register the factory with a GsonBuilder
, or you can annotate your Field3
class with @JsonAdapter
。使用 @JsonAdapter
时,工厂 class 应该有一个 no-args 构造函数。
您可以通过将类型设为 field_3 Map<String, List<ArrayObject>>
public class responseObject {
String field_1;
String field_2;
Map<String, List<ArrayObject>> field_3;
String field_4;
class ArrayObject{
String array_field_1;
String array_field_2;
String array_field_3;
}
}
然后在不知道其键值的情况下从地图中取出第一项,您可以使用:
public List<ResponseObject.ArrayObject> getFirstValue(Map<String, List<ResponseObject.ArrayObject>> field_3) {
return field_3.values().iterator().next();
}