【问题标题】:JsonMappingException - Unexpected Character in field nameJsonMappingException - 字段名称中的意外字符
【发布时间】:2020-10-01 14:18:48
【问题描述】:

我正在尝试反序列化 JSON 格式

"{mapping:{MyType(type=\"A\", value=\"B\"):\"C\"}}"

进入类类型

class MyMapping {
    Map<MyType, String> mapping;
}

class MyType {
    String type;
    String value; 
}

由于我有一个映射类型,我添加了一个 KeyDeserializer 来反序列化MyType(type=\"A\", value=\"B\")

但是当我尝试反序列化时,我得到一个异常

Caused by: com.fasterxml.jackson.core.JsonParseException: Unexpected character ('(' (code 40)): was expecting a colon to separate field name and value

这是因为它在MyType(type=\"A\", value=\"B\") 中遇到( 并在那里中断。如果我将整个密钥放在双引号 \"MyType(type=\"A\", value=\"B\")\" 内,它会将整个密钥传递给我的解串器。

有没有一种方法可以强制它转义 '(' 字符,而不必将整个键加上引号。

【问题讨论】:

  • 你有没有考虑过使用像 Gson 这样的库
  • 这不是一个有效的 JSON,所以很明显它不能被标准反序列化器反序列化...

标签: java json jackson


【解决方案1】:

示例中的字符串不是有效的 JSON。

"{mapping:{MyType(type=\"A\", value=\"B\"):\"C\"}}"

您指出 Jackson 解析器抱怨第一个 (

如果您想将此特定字符串用作键,则必须将其括在引号中并转义内部引号。让我们在浏览器中使用 Javascript 来做到这一点,因为它很容易。从 Chrome 控制台...

> var c = {};
< undefined
> c['MyType(type="A", value="B")']='C';
< "C"
> JSON.stringify(c)
< "{"MyType(type=\"A\", value=\"B\")":"C"}"`

这就是 Javascript 将您的密钥字符串转义为有效 JSON 的方式。

KeyDeserializer

基于 KeyDeserializer 的 Jackson 2.8 文档,我希望您的 KeyDeserializer 能够接收整个密钥字符串。这就是 JSON 的工作原理。

{"key-string":"value")

当然,“值”也可以是 false、true、null 或数字。

然后由您来解析密钥字符串并决定如何将其转换为您的 MyMapping 可以使用的密钥。

您的密钥字符串看起来很容易解析

您的 KeyDeserializer 可以使用已编译的正则表达式模式将两个键属性作为两个正则表达式“组”。

如果不想解析密钥字符串怎么办?

听起来您不想解析此密钥。有几种方法可以避免这种情况。这样做的一个关键是使用一种简单的 JSON 格式,例如 ...

{"key":{"keyType":"A","keyValue":"B"}, "value":"C"}

然后您可以使用注释来教 Jackson 使用您的 MyMapping 类。

如(未经测试,只是一个草图)

class MyMapping {
    Map<MyType, String> mapping;
    @JsonCreator
    public MyMapping(Map<String,Object> input) {
        Map<String,Object> key = (Map)input.get("key");
        String value = (String)input.get("value");
        MyType myKey = new MyType(key);
        mapping = new HashMap<>();
        mapping.put(myKey,value);
    }
}

class MyType {
    String type;
    String value; 
    MyType (Map<String,Object> input) {
        type = (String)input.getOrDefault("key","");
        value = (String)input.getOrDefault("value","");
    }
}

这个例子有很长的问题列表。例如,您将在地图中使用基于默认对象地址的比较。我忽略了可能的 ClassCastExceptions 和其他数据问题,从而缩短了这段代码。但这里的重点不是写好代码,也不是试图理解需求,而只是指出如何让 Jackson 为你解析 JSON。

有很多。实现这一目标的其他方法。我只是。选择了第一个想到的。

【讨论】:

    猜你喜欢
    • 2019-06-09
    • 1970-01-01
    • 2021-07-31
    • 2021-02-15
    • 2020-10-06
    • 1970-01-01
    • 2014-08-16
    • 2020-03-08
    • 1970-01-01
    相关资源
    最近更新 更多