有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Gson:JsonArray无法转换为JsonPrimitive错误

我想使用Gson解析包含动态字段类型的json对象:

{
"rows":
   [
      {
         "id": "1",
         "interventions": [
            {
               "type": "type1",
               "label": "label 1"
            },
            {
               "type": "type2",
               "label": ["label 1","label 2"]
           },
           {
              "type": "type3",
              "label": "label 3",
           }
        ]
     }
  ]

}

正如您所看到的,“标签”字段可以是字符串或字符串列表

我编写了一个定制的反序列化程序来处理这个问题,如果“干预”字段只有一个元素(不管“标签”字段是字符串还是列表),它都可以工作:

{"rows":
  [
     {
        "id": "1",
        "interventions": [
           {
              "type": "type1",
              "label": "label 1"
           }
        ]
     }
  ]

}

但总是抛出com。谷歌。格森。无法将JsonArray强制转换为com。谷歌。格森。如果存在多个“干预”元素,则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

}

有人能帮忙吗


共 (1) 个答案

  1. # 1 楼答案

    不必为整个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之间也存在不匹配

    作为一个一般性建议,试着定制代码中最短/最小的部分,并尝试构建通用部分。随着时间的推移,定制需要进行大量的维护工作


    对于Gson2.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());
        }
    }