【问题标题】:Json Mapping With Numbers as Property Names以数字作为属性名称的 Json 映射
【发布时间】:2021-10-06 04:49:16
【问题描述】:

我以下面的json为例:

{
    "success": true,
    "data": {
        "1": {
            "amount": "1"
        },
        "2": {
            "amount": "98"
        }
    }
}

不幸的是,我无法控制传入的 JSON 结构。我一直在尝试找到一种使用 JSONProperties 将这些映射到 DTO 的方法,但是我无法使用数字声明属性。

我也尝试过使用 JSONObject 迭代 JSON,但我似乎无法让它通过所有子节点,只是顶层。

JSONObject payload = new JSONObject(jsonString);
JSONObject newPayload = payload;

Iterator<String> keys = payload.keys();

while (keys.hasNext()) {
                String key = keys.next();

                if (StringUtils.isNumber(key)) {
                    newPayload.put("element" + key, payload.get(key));
                    newPayload.remove(key);
                }
}

有没有人遇到过类似的情况并找到了解决办法。

所有这些最终都将 JSON 转换为 XML... 继承了这个平台,没时间重构lol,不是我的选择。

【问题讨论】:

  • 技术上说,这些不是数字;它们是一串数字。您是否可以或应该将它们视为数字取决于您对服务合同的了解。
  • 我应该说这个的最后部分,这个的最终结果需要转换成 XML,因此需要去掉键名的数字。我将编辑问题
  • 数字是否应该是顺序索引,从 1 开始?
  • @chrylis-cautiouslyoptimistic- 是的,被告知它应该始终是 2 个索引,但我正在处理一个非常不可靠的响应,因此试图涵盖可能性。我有一个解决方案,.replace(),但这很糟糕,我现在很好奇。

标签: java json jackson mapping transformation


【解决方案1】:

您可以使用@JsonProperty注解并指定名称。

@JsonProperty("1")
private String one;

【讨论】:

  • 这对于呈现的特定 JSON 是正确的,但 OP 给人的印象是结果集是任意的。
  • 这是一个选项,但我希望能够处理任意结果集,因为我不相信 JSON 没有动态构建的模式,我已经讲过如何使用数组
【解决方案2】:

有许多解决方案,但假设您只需要反序列化这个病态结构,我会这样处理它(Groovy 风格的紧凑性):

class ResponseData {
  Map<String, Long> amounts = new HashMap<>()  // or different key type


  static class WrappedAmount {
    String amount

    Long getAmountAsLong() {
      return Long.valueOf(amount)
    }
  }


  @JsonAnySetter  // this is the magic step
  void appendAmount(String key, WrappedAmount amount) {
    amounts.put(key, amount.getAmountAsLong())
  }
}


class Response {
  boolean success  // REST endpoints should use status codes, not properties
  ResponseData data
}

这会将您的响应反序列化到一个可管理的数据结构中。如果按照您的建议,这些键是索引并且将被删除并替换为类似 XML 标记的排序,您可能希望将 HashMap 替换为 TreeMap 以便您可以迭代它以生成输出。

【讨论】:

    【解决方案3】:

    如果传入的JSON结构未知,我们可以使用递归来解析整个JSON(包括子节点)。

    下面的代码将遍历整个JSON并将其存储在Map&lt;String, Object&gt;中。我们可以在递归过程中随心所欲(比如将值映射到 DTO),或者我们可以再次递归遍历 Map&lt;String, Object&gt;

    import org.json.simple.JSONArray;
    import org.json.simple.JSONObject;
    
    private static Map<String, Object> parseMap(JSONObject jsonObject) {
        Map<String, Object> map = new HashMap<>();
        Set<String> keySet = jsonObject.keySet();
        for (String key : keySet) {
            Object value = jsonObject.get(key);
    
            if (value instanceof JSONArray) {
                value = parseList((JSONArray) value);
            } else if (value instanceof JSONObject) {
                value = parseMap((JSONObject) value);
            }
            // We can do whatever we want with a value of a key here.
            map.put(key, value);
        }
        return map;
    }
    
    private static List<Object> parseList(JSONArray array) {
        List<Object> list = new ArrayList<>();
        for (Object value : array) {
            if (value instanceof JSONArray) {
                value = parseList((JSONArray) value);
            } else if (value instanceof JSONObject) {
                value = parseMap((JSONObject) value);
            }
            // We can do whatever we want with an element of a JSON list here.
            list.add(value);
        }
        return list;
    }
    

    驱动代码:-

    JSONParser jsonParser = new JSONParser();
    JSONObject jsonObject = (JSONObject) jsonParser.parse(jsonString);
    
    Map<String, Object> map = parseMap(jsonObject);
    System.out.println("Resulting Map = " + map);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-04
      • 1970-01-01
      相关资源
      最近更新 更多