将不带引号的 json 字符串转换为地图

2022-09-02 14:03:00

我有一个Json格式的字符串,只有没有一个键或值用引号括起来。例如,我有这个:

String json = "{name: Bob, state: Colorado, Friends: [{ name: Dan, age: 23 }, {name: Zane, age: 24 }]}"

我希望这成为一个看起来像这样的地图:

Map<String, Object> friend1Map = new HashMap<>();
friend1Map.put("name", "Dan");
friend1Map.put("age", 23);

Map<String, Object> friend2Map = new Hashmap<>();
friend2Map.put("name", "Zane");
friend2Map.put("age", 24);

Map<String, Object> newMap = new HashMap<>();
newMap.put("name", "Bob");
newMap.put("state", "Colorado");
newMap.put("Friends", Arrays.asList(friend1Map, friend2Map));

我尝试了以下两种方法:

ObjectMapper mapper = new ObjectMapper();
mapper.readValue(json, new TypeReference<Map<String, Object>>() {});

这将引发一个错误,说:

Unexpected character ('n'): was expecting double-quote to start field name

然后我尝试更改映射器的配置:

mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
mapper.readValue(json, new TypeReference<Map<String, Object>>() {});

但这抛出了一个错误,说:

com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'Bob': was expecting ('true', 'false' or 'null')
at [Source: {name: Bob, state: Colorado, Friends: [{ name: Dan, age: 23 }, {name: Zane, age: 24 }]}; line: 1, column: 11]

当json字符串中不包含引号时,有没有办法获得此地图?


答案 1

自 GSON v2.8.6 起

带有 jackson fasterxml 的 ObjectMapper 不支持不带引号的值,但 GSON 支持:

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.JsonParser;

.

  JsonNode json = json("{"
      + "  name: Bob,      "
      + "  state: Colorado,"
      + "  Friends: [      "
      + "    {"
      + "      name: Dan,  "
      + "      age: 23     "
      + "    },"
      + "    {"
      + "      name: Zane, "
      + "      age: 24     "
      + "     }"
      + "  ],"
      + "  extra: \"text with spaces or colon(:) must be quoted\""
      + "}");

  Map m = new ObjectMapper().convertValue(json, Map.class);

.

JsonNode json(String content) throws IOException {

  String canonicalFormat = JsonParser.parseString(content).toString();
  return json.readTree(canonicalFormat);
}

早期的格森

在 v2.8.6 之前,GSON 没有静态 parseString 方法。因此,您应该使用(在更高版本中已弃用)实例方法:

JsonNode json(String content) throws IOException {

  String canonicalFormat = new JsonParser().parse(content).toString();
  return json.readTree(canonicalFormat);
}

自 Java 15 起

注意:我们预计 Java 15 将支持未转义的双引号,如下所示:

var json = """
        {"name": "Bob", "state": "Colorado", "Friends": [{ "name": "Dan", "age": 23 }, {"name": "Zane", "age": 24 }]} """;

更多详情


答案 2

回答您的问题:没有安全的方法来获取您的JSON - 顺便说一句,这不是JSON,因为它是无效的 - 转换为.Map<String, Object>

让我详细阐述一下(为什么不能安全地解析它?):想象一下这样的“JSON”:

{
    this is my key: and here's my value and it even has a colon:
}

有效的 JSON 看起来像这样

{
    "this is my key": "and here's my value and it even has a colon:"
}

使用引号,解析器可以安全地确定键和值。没有它们,解析器就会丢失。