【问题标题】:Gson: How do I parse polymorphic values that can be either lists or strings?Gson:如何解析可以是列表或字符串的多态值?
【发布时间】:2017-05-02 01:15:59
【问题描述】:

我需要解析一个包含一长串客户的 JSON 文件。在 JSON 文件中,每个客户可能有一个 id 作为字符串:

{
  "cust_id": "87655",
  ...
},

或者几个id作为一个数组:

   {
      "cust_id": [
        "12345",
        "45678"
      ],
      ...
    },

Customer 类如下:

public class Customer {

    @SerializedName("cust_id")
    @Expose
    private String custId;
    public String getCustId() {
        return custId;
    }

    public void setCustId(String custId) {
        this.custId = custId;
    }
}

我使用 Gson 解析 JSON:

Gson gson = new Gson()
Customers customers1 = gson.fromJson(json, Customers.class)

当它试图解析数组时,它会以com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_ARRAY 失败。

失败的原因很清楚。

我的问题:鉴于 我无法更改 json 文件结构,处理这两种情况的最佳方法是什么(当 id 是一个字符串和一个字符串数组时)?? p>

【问题讨论】:

  • 请注意,您的问题针对的是在 S.O. 非常琐碎的主题。要求以最有效的方式将单个和多个案例“对齐”到列表中,但是接受的答案以一种非常幼稚的方式做到这一点:需要构造函数,需要“级联异常展开”,忽略特定的 Gson 实例配置等。

标签: java json gson


【解决方案1】:

如果您想同时处理这两种情况,您可以使用自定义反序列化程序。当然,您必须将“cust_id”变量更改为列表或数组。

主要:

String json1 = "{\"cust_id\": \"87655\"}";
String json2 = "{\"cust_id\": [\"12345\", \"45678\"]}";

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Customer.class, new CustomerDeserializer());
Gson gson = gsonBuilder.create();

Customer customer1 = gson.fromJson(json1, Customer.class);
System.out.println(customer1);

Customer customer2 = gson.fromJson(json2, Customer.class);
System.out.println(customer2);

客户

public class Customer {

    @SerializedName("cust_id")
    private List<String> custId;

    public List<String> getCustId() {
        return custId;
    }

    public void setCustId(List<String> custId) {
        this.custId = custId;
    }
}

客户解串器

public class CustomerDeserializer implements JsonDeserializer<Customer> {

@Override
public Customer deserialize(JsonElement jsonElement, Type typeOf, JsonDeserializationContext context) throws JsonParseException {
    Customer result = null;
    Gson gson = new Gson();

    try {
        // try to deserialize by assuming JSON has a list
        result = gson.fromJson(jsonElement, Customer.class);
    } catch (JsonSyntaxException jse) {
        // error here means JSON has a single string instead of a list

        try {
            // get the single ID
            String custId = jsonElement.getAsJsonObject().get("cust_id").getAsString();

            result = new Customer();
            result.setCustId(Arrays.asList(new String[] {custId}));
        } catch (Exception e) {
            // more error handling here
            e.printStackTrace();
        }
    }

    return result;
}

}

输出

Customer [custId=[87655]]
Customer [custId=[12345, 45678]]

【讨论】:

    【解决方案2】:

    试试method overriding:

    public class Customer {
    
        @SerializedName("cust_id")
        @Expose
        private String custId;
    
        public void setCustId(String custId) {
            this.custId = {custId};
        }
    
        public String[] getCustId() {
            return custId;
        }
    
        @override
        public void setCustId(String[] custId) {
            this.custId = custId;
        }
    }
    

    现在在代码中CUSTID 的所有值都将是数组而不是字符串

    【讨论】:

      【解决方案3】:

      您可以简单地将所有值指定为数组,即使只是一个值。

      {
        "cust_id": ["87655"],
        ...
      },
      

      更新:如果无法更改 json,您可以绑定 Customer 类中除 custId 之外的所有字段并手动设置。

      public class Customer {
          private String[] custId;
      
          public String getCustId() {
              return custId;
          }
      
          public void setCustId(String custId) {
              custId = new String[] {custId};
          }
      
          public void setCustId(String[] custId) {
              this.custId = custId;
          }
      }
      

      然后手动解析:

      Gson gson = new Gson();
      Customers customers = gson.fromJson(json, Customers.class);
      Object custId = new JSONObject(json).get("cust_id");
      if (custId instanceof String) {
        customers.setCustId((String) custId);
      else if (custId instanceof JSONArray) {
        customers.setCustId(convertToStringArray(new JSONArray(custId)));
      }
      

      【讨论】:

      • 我无法更改 json。它是提供给我的。
      【解决方案4】:

      请参考this

      现在的问题是您必须在返回的地图上编写自己的代码才能获得所需的结果。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-08
        • 1970-01-01
        • 1970-01-01
        • 2020-04-11
        相关资源
        最近更新 更多