【问题标题】:Spring Boot: Convert complex json string response to objectSpring Boot:将复杂的 json 字符串响应转换为对象
【发布时间】:2018-06-28 20:00:28
【问题描述】:

我想将一个复杂的 json 字符串(我从 GET 请求中获得)转换为我们的数据库。我需要遍历所有对象并找到一些特定的对象。问题是所有对象在某种程度上都是不同的。它们可能看起来像这三个示例,但还有更多示例:

{
  "created": 1493209170473990,
  "id": "fu:9843464EDF4D053072ACEAC2362EE0D8",
  "type": "user-created"
},
{
  "created": 1493209170883075,
  "data": {
    "process_type": "wallet-tx"
  },
  "id": "fu:6BE085BF29D7C8AF4C238615CA85F31A",
  "process": "0CEB2F401E0FB9D9A44A124D0710B521",
  "type": "process-created"
},
{
  "created": 1495535185484487,
  "data": {
    "message": "electronic delivery"
  },
  "document": "25FBED0A80FEEBD6FF154D21D8E35D7E",
  "id": "fu:3C17584381C0AFB4836F73057DB7DEAB",
  "type": "info"
}

我需要找到一些具有特定类型的对象,但我无法将它们从字符串中取出。我通过这个调用获得了请求数据:

@RequestMapping(value="/events", method=RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@CrossOrigin(origins = "http://localhost:4200", maxAge = 3600)
public String getEvents() {

    int created_after = 0;

    final String url = server + "/rest/client/events/" + created_after;

    RestTemplate restTemplate = new RestTemplate();
    restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Type", "application/json; charset=utf-8");
    headers.set("Auth-Token", token); // user_token

    HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);

    ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);

    return response.getBody();
}

我在前端使用 Angular,它可以轻松地将字符串转换为对象,但随后我必须再次将其传递给后端以处理数据。我想把所有东西都放在后端。你知道如何解决吗?

如果您需要更多信息,请询问。谢谢

编辑: 我的 JSON 输出如下所示:

[
  {
    "created": 1493209170473990,
    "id": "fu:9843464EDF4D053072ACEAC2362EE0D8",
    "type": "user-created"
  },
  {
    "created": 1493209170653925,
    "data": {
      "verify_id": "12581C42DD2DF7D80F802C50ABD144F8"
    },
    "id": "fu:06111B0A9C5B760B9269044DA97D3D6F",
    "type": "post-address-verification-confirmed"
  },
  {
    "created": 1493209171320041,
    "data": {
      "after": {
        "attempt": 1
      }
    },
    "id": "fu:7B5B2AD57C1CE97BB642931C2C3C819D",
    "process": "0CEB2F401E0FB9D9A44A124D0710B521",
    "type": "process-updated"
  },
...
]

【问题讨论】:

    标签: json spring-boot


    【解决方案1】:

    如果您不知道 JSON 的结构是什么,那么您可以将您的 JSON 字符串序列化为一个 Map,该 Map 将 json 中的字段名称映射到它们的值。

    这可以使用 Jackson ObjectMapper 来完成:

    String jsonObject = <the string JSON response you obtained>;
    
    ObjectMapper objectMapper = new ObjectMapper();
    Map<String, Object> jsonMap = objectMapper.readValue(jsonString,
        new TypeReference<Map<String, Object>>(){});
    

    如果它是您期望的 JSON 对象列表,那么您可以首先将其映射到 JSON 字符串数组,然后将每个字符串转换为映射:

    ObjectMapper objectMapper = new ObjectMapper();
    String[] jsonStrings = objectMapper.readValue(jsonString, String[]);
    List<Map<String, Object>> jsonMaps = new ArrayList<>();
    for (String json : jsonStrings) {
        jsonMaps.add(objectMapper.readValue(json, 
                new TypeReference<Map<String, Object>>(){});
    }
    

    【讨论】:

    • 感谢您的回复。如果我使用它,我会得到以下异常:无法从 START_ARRAY 令牌中反序列化 java.util.LinkedHashMap 的实例。找不到任何解决方案
    • 导致此异常的确切 JSON 字符串是什么?
    • 我会在我上面的原始文章中发布 json 输出
    • 好吧,问题是您的 JSON 作为对象列表返回。我的印象是它只是一个结构未知的 JSON 对象。我会更新我的答案。
    【解决方案2】:

    按照我的理解,您的对象有一些共同的属性,以及一些可选的属性。您可以使用@JsonAnyGetter@JsonAnySetter 对可选属性进行建模:

    class Data {
        @JsonProperty
        private Long created;
        @JsonProperty
        private String id;
        @JsonProperty
        private String type;
        private Map<String, Object> optional = new HashMap<>();
        public Data() { // empty public constructor is required
        }
        // getters/setters for all properties omitted for brevity
        @JsonAnySetter
        public void addOptional(String name, Object value) {
            optional.put(name, value);
        }
        @JsonAnyGetter
        public Object getOptional(String name) {
            return optional.get(name);
        }
    }
    

    然后你可以使用反序列化你的对象

    ObjectMapper objectMapper = new ObjectMapper();
    Data data = objectMapper.readValue(j, Data.class);
    

    或者,如果您有一个 Data 对象数组作为输入,

    Data[] data = objectMapper.readValue(j, Data[].class);
    

    createdidtype 之外的所有属性都将放置在optional 映射中。

    【讨论】:

    • 我也试过你的答案,但是我也得到了一个错误:Can not deserialize instance of abc.model.Event out of START_ARRAY token 也许我实现错了?不幸的是,我是 Java 新手
    • 我试过升技,现在错误消失了,但我没有得到可选数据作为输出。只有 ID、创建和类型。我使用了您提供的数据类。我改了Data[] data = objectMapper.readValue(j, Data[].class);
    • 关于 START_ARRAY token 的错误是因为我认为您会单独反序列化对象,而不是作为数组。如果它是您拥有的对象数组,那么是的,您可以使用Data[] data = objectMapper.readValue(json, Data[].class); 反序列化它们。额外的属性应该反序列化为optional 属性的Map 值。顺便说一句,你是如何检查你没有 optional 数据元素的?对于第一个数组元素,它将为空,但对于其他两个,里面应该有东西
    • 还要确保所有导入都来自同一个包根目录。我知道 Jackson 已经在 org.codehouse.jacksoncon.fasterxml.jackson 包之间移动,所以如果你的项目以某种方式引用了这两个包(例如,作为 Maven 依赖项),请确保不要混淆它们。
    • @Peter 不,每个类只能有一个 @JsonAnyGetter/Setter,它充当您尚未定义的任何属性的包罗万象的接收器。所以processdocument 也会出现在optional 属性中,如果存在的话。再说一次,没有什么能阻止你将它们声明为 @JsonProperty,然后它们最终会反序列化为常规属性。默认情况下,Jackson 将所有 @JsonProperty 视为可选,因此它们在不存在时将为空。 @JsonAnySetter 只是一种确保您已捕获所有内容的安全方法,即使分析中遗漏了某些属性
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-03
    • 1970-01-01
    • 2017-01-17
    • 2022-11-19
    • 2016-02-25
    • 2022-01-13
    • 1970-01-01
    相关资源
    最近更新 更多