【问题标题】:Serialized JSON String as Value in JSON序列化 JSON 字符串作为 JSON 中的值
【发布时间】:2019-11-21 02:21:34
【问题描述】:

我希望在使用 Jackson 读取序列化 JSON 字符串时,将其简单地视为我的 JSON 中的字符串。当我简单地转义序列化的 JSON 字符串并将其用作值时,序列化的字符串将被视为 JSON 的一部分并被解析。关于如何进行此操作的任何想法?

例如:

 "{\"payload\":\"{id:\"some-random-id\",version:554471325}\"}"

我希望在内存中读取如下内容:

{ payload: "{id:\"some-random-id\",version:554471325}" }

但是,解析器正在尝试将序列化的字符串读取为 JSON 并将其转换为以下内容:

{ payload: {id:"some-random-id", version:554471325} }

注意两个输出之间的区别。在一种情况下,与payload 关联的值是一个字符串,在另一种情况下它是一个 JSON 对象。我正在尝试获得前者,而我得到的是对后者的尝试。

【问题讨论】:

  • 你能举个例子来演示你想要实现的目标吗?
  • 也发布您的代码?
  • 我添加了一个例子。由于各种原因无法粘贴代码。
  • 仍然不知道你想做什么,我只看到一些反斜杠和双引号被删除。
  • 第一个是一个有效的 JSON 字符串,只是一个嵌入了引号的文本字符串。但是文本不是有效的 JSON,第三个 { payload: {id:"some-random-id", version:554471325} } 不是有效的 JSON,因为必须引用 JSON 键,即它应该是 { "payload": { "id": "some-random-id", "version": 554471325 } } (间距不重要)

标签: java json jackson jackson-databind


【解决方案1】:

有效的 JSON 是“一组名称/值对”,所以你缺少的是名称字段,这就是它被解析的原因。

例如,如果 JSON 是:

{"data": "{\"payload\":\"{id:\"some-random-id\",version:554471325}\"}"}

data 的值不会被解析。

顺便说一句。负载中的 JSON 包含不带引号的键名(应该是 {"id": 123, "version": 456}

【讨论】:

  • 本例中的字段名称预计为payload,我希望与该字段关联的值为字符串“{id:”some-random-id”,version :554471325}" 被 Jackson 反序列化后。
【解决方案2】:

更新:答案被替换,因为问题改变了。

问题中的示例不是有效的 JSON。为了看看它应该是什么,让我们将它生成为嵌套的 JSON 字符串:

ObjectMapper objectMapper = new ObjectMapper();

Map<String, Object> payloadObj = Map.of("id", "some-random-id", "version", 554471325);
String payloadJson = objectMapper.writeValueAsString(payloadObj);
System.out.println(payloadJson);

Map<String, Object> rootObj = Map.of("payload", payloadJson);
String rootJson = objectMapper.writeValueAsString(rootObj);
System.out.println(rootJson);

String rootString = objectMapper.writeValueAsString(rootJson);
System.out.println(rootString);

输出

{"id":"some-random-id","version":554471325}

{"payload":"{\"id\":\"some-random-id\",\"version\":554471325}"}

"{\"payload\":\"{\\\"id\\\":\\\"some-random-id\\\",\\\"version\\\":554471325}\"}"

输出的第三行应该是问题中第一个块的文本。

"{\"payload\":\"{id:\"some-random-id\",version:554471325}\"}"

但正如您所见,该文本缺少许多双引号和反斜杠,因此它不是有效的嵌套 JSON 字符串,因此您不能指望 JSON 解析器解析它。

JSON 解析器通常很宽松,无论如何都会尽力解析它,但如果解析器出错了,不要责怪它。责备原始文本并修复它,而不是尝试解析错误的 JSON。


原答案

键应该是名称或数字,而不是整个复杂对象,但如果您想要一个 JSON 作为另一个 JSON 中的键,只需调用 JSON 序列化程序两次。

例子

ObjectMapper objectMapper = new ObjectMapper();

Map<String, Object> data1 = Map.of("foo", 42, "bar", List.of(1, 1, 2, 3, 5, 8));
String json1 = objectMapper.writeValueAsString(data1);
System.out.println(json1);

Map<String, Object> data2 = Map.of("Test", "Hello World", json1, 3.14, "End", "Now!");
String json2 = objectMapper.writeValueAsString(data2);
System.out.println(json2);

注意:Map.of()List.of() 是 Java 9+

输出

{"foo":42,"bar":[1,1,2,3,5,8]}
{"{\"foo\":42,\"bar\":[1,1,2,3,5,8]}":3.14,"Test":"Hello World","End":"Now!"}

【讨论】:

  • 对不起!我打错了,我希望将序列化字符串作为 value 而不是 key。我知道如何将它记录为字符串,问题是,当我将它转换回内存中的 JSON 对象时,它被读取为 JSON,而我真正想要的是让它保留为字符串表示。这有意义吗?
  • @JacksonKelley 好吧,首先,如果能提前知道这一点,那就太好了。其次,"{\"payload\":\"{id:\"some-random-id\",version:554471325}\"}"不是一个有效的内嵌JSON,因为解析字符串的时候变成了{"payload":"{id:"some-random-id",version:554471325}"},而payload的值也不是一个有效的字符串,即是谁生成的原始字符串搞砸了。修复生成原始字符串的代码。
  • 我实际上并不关心字符串是否是有效的 JSON,因为它是 JSON 的变体,但不是真正的 JSON(同样,出于同样的原因,我无法分享更多细节)代码)。实际上,我知道它是无效的 JSON,我想保持这种状态。也就是说,即使您提出的解决方案也不适合我。
  • @JacksonKelley 如果不是 JSON,为什么要尝试使用 JSON 解析器?编写能够理解您正在阅读的文件格式的解析器。这当然假设了解格式,但我们肯定不了解。
  • 我知道您不理解格式,这就是为什么我在我提供的答案中道歉。但是,字符串是否是有效的 JSON 与我试图完成的事情无关,因为无论字符串中实际包含什么,都不应该解析字符串。
【解决方案3】:

我知道这是一个措辞糟糕的问题,对此我深表歉意。但是,我想不出更好的措辞方式,也无法提供代码。对于任何偶然发现这一点并理解我的要求的人,我找到了一种解决方法。

我将序列化的 JSON 字符串编码为 base64,因此 Jackson 将其检测为字符串而不是 JSON 对象。

上面问题中的例子变成:

 "{\"payload\":\"e2lkOiJhbnktZXhlY3V...\"}"

其中e2lkOiJhbnktZXhlY3V... 是字符串"{id:\"some-random-id\",version:554471325}" 的base64 编码表示

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-15
    • 1970-01-01
    相关资源
    最近更新 更多