我想使用Gson解析包含动态字段类型的json对象:
{
"rows":
[
{
"id": "1",
"interventions": [
{
"type": "type1",
"label": "label 1"
},
{
"type": "type2",
"label": ["label 1","label 2"]
},
{
"type": "type3",
"label": "label 3",
}
]
}
]
}
您会看到“标签”字段可以是String或字符串列表。
我写了一个定制的反序列化程序来处理此问题,如果“干预”字段只有一个元素(不管“标签”字段是字符串还是列表),它都可以工作:
{"rows":
[
{
"id": "1",
"interventions": [
{
"type": "type1",
"label": "label 1"
}
]
}
]
}
但总是抛出com.google.gson.JsonArray,如果有多个“干预”元素,则不能将其强制转换为com.google.gson.JsonPrimitive异常。
这是自定义的反序列化器:
public class CustomDeserializer implements JsonDeserializer<InterventionsModel> {
@Override
public InterventionsModel deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) throws JsonParseException {
if(je != null && je.getAsJsonObject()!=null) {
JsonPrimitive jp = je.getAsJsonObject().getAsJsonPrimitive("label");
if (jp != null && jp.isString()) {
String label = jp.getAsString();
List<String> list = new ArrayList<String>(1);
list.add(label);
InterventionsModel interventionsModel = new InterventionsModel();
interventionsModel.setLabel(list);
return interventionsModel;
}
}
return new Gson().fromJson(je, InterventionsModel.class);
}
}
在调用方法中:
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(InterventionsModel.class, new CustomDeserializer());
builder.setPrettyPrinting();
Gson gson = builder.create();
对象的类为:
public class ResultsModel {
private List<RowModel> rows;
//getter and setter ..
}
public class RowModel {
private String id;
private List<InterventionsModel> interventions;
//getter and setter
}
public class InterventionsModel {
private String type;
private List<String> label;
//setter and getter
}
有人可以帮忙吗?
答案 0 :(得分:3)
您不必为整个InterventionsModel
创建自定义反序列化器。
相反,只需将@JsonAdapter
注释应用于List<String> label
字段
public class InterventionsModel {
private String type;
@JsonAdapter(LabelsDeserializer.class)
private List<String> label;
// Setters and getters
}
并为List<String>
类型创建反序列化器
public class LabelsDeserializer implements JsonDeserializer<List<String>> {
@Override
public List<String> deserialize(
final JsonElement json,
final Type typeOfT,
final JsonDeserializationContext context) {
// Check if the JSON object is an array or a primitive value
if (json.isJsonArray()) {
// Multiple Strings elements
final JsonArray jsonArray = json.getAsJsonArray();
final List<String> labels = new ArrayList<>(jsonArray.size());
for (final JsonElement jsonElement : jsonArray) {
labels.add(jsonElement.getAsString());
}
return labels;
}
// Single String element
return Collections.singletonList(json.getAsString());
}
}
Java模型的字段type
与JSON文档字段intervention_type
之间也存在不匹配。
作为一般建议,请尝试始终自定义代码的最短/最小部分,并尝试构建通用代码。自定义会带来很多工作,随着时间的流逝需要维护。
对于Gson 2.6.*
,使用
public class LabelsDeserializer extends TypeAdapter<List<String>> {
@Override
public void write(
final JsonWriter out,
final List<String> labels) throws IOException {
if (labels.size() == 1) {
out.value(labels.get(0));
return;
}
out.beginArray();
for (final String l : labels) {
out.value(l);
}
out.endArray();
}
@Override
public List<String> read(final JsonReader in) throws IOException {
final JsonToken peek = in.peek();
if (peek.equals(JsonToken.BEGIN_ARRAY)) {
final List<String> labels = new ArrayList<>();
in.beginArray();
while (in.hasNext()) {
labels.add(in.nextString());
}
in.endArray();
return labels;
}
return Collections.singletonList(in.nextString());
}
}