【问题标题】:ALLOW_UNQUOTED_FIELD_NAMES in jackon JSON library杰克逊 JSON 库中的 ALLOW_UNQUOTED_FIELD_NAMES
【发布时间】:2011-01-27 10:34:49
【问题描述】:

我正在使用 jackson 库对 JSON 进行序列化/反序列化。我需要这个 JSON 的大小尽可能小,所以我启用了 ALLOW_UNQUOTED_FIELD_NAMES 功能来消除所有引号。我知道去掉引号不是标准的 json,但是让 json 变小是项目的硬性要求。生成的 json 可以工作,但是当我尝试读取 json 值时出现异常:

org.codehaus.jackson.JsonParseException: 意外字符('9'(代码 57)): 期待任何一个有效的名字 字符(用于未引用的名称)或 双引号(用于引用)开始 [来源: java.io.StringReader@1347d75;线:1, 列:3]

当我读取这个json时抛出了上面的异常:

{90110a2e-febd-470f-afa4-cf7e890d31b9:0,eec652ad-a4d9-4eb1-8d24-7c1a0c29449f:1}

我的阅读方式是:

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

我用于读取和写入值的对象映射器是:

private static final ObjectMapper om = new ObjectMapper();
static {
    om.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, false);
    om.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
    om.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, true);
    om.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    om.getSerializationConfig().setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
}

我在发送方和接收方项目中都使用 Jackson 1.6.3 版。此功能所需的版本是 1.2+,所以我想也许我没有使用此版本,但我的接收器是一个 Spring 应用程序,我检查了安装在 libs 文件夹中的库是 1.6.3。

我可能做错了什么?也许这个功能不能与地图一起使用。

我还有一个问题,到目前为止,我只是发送了一个地图,其中键只是一个 uuid 值,值是一个数字。如果我发送带有 ALLOW_UNQUOTED_FIELD_NAMES 功能的特殊字符的值,我会遇到什么问题吗?杰克逊会逃脱这些角色吗?

谢谢。

【问题讨论】:

    标签: java json spring parsing jackson


    【解决方案1】:

    好的,我认为 Pingw33n 的回答非常正确。所以:是的,您可以使用该功能;但它是相当启发式的——因为没有关于不带引号的名称应该如何工作的规范(毕竟,JSON 允许名称中的任何和所有字符!);或者,如果要使用任何转义机制怎么办,任何人都可以猜测应该写入或接受什么。

    在这种特殊情况下,可能是“-”字符导致了问题。它不是 Javascript 名称的合法部分,这是 Jackson 使用的近似名称。

    一种可能的解决方案是让 Jackson 转义属性名称中的此类字符(我不记得目前是如何完成的;如果引用了任何名称字符)。如果您能找出一个简单的测试用例,您可以在Jackson Jira 提交 Jira 改进请求以添加转义(并确保解析器可以取消通常的反斜杠版本)。

    【讨论】:

    • 哦。实际上,它甚至比这更简单:由于 javascript 标识符不能以数字开头,这就是导致问题的原因。对于 ALLOW_UNQUOTED_FIELD_NAMES 模式,也可以放宽这一点;为此,Jira 功能请求会有所帮助。
    【解决方案2】:

    在某些情况下,QUOTE_FIELD_NAMES 的 Jackson 似乎会产生这样的输出,即使在 ALLOW_UNQUOTED_FIELD_NAMES 开启时它也无法读取自身。您可能需要为非标准输入解析实现自定义JsonParser

    问题在于您正在生成非标准 JSON,并且无法保证客户端会正确处理它。但是,如果您不将它暴露在您的应用程序之外并且非常关心大小,您可以解析/生成像杰克逊的Smile 这样的二进制格式。请参阅http://www.cowtowncoder.com/blog/archives/2010/09/entry_418.html (2.4)。

    【讨论】:

    • Smile 非常好——它可以很紧凑,尤其是。启用字符串值反向引用时(如果有许多重复的字符串值,如枚举值)
    【解决方案3】:

    我认为问题与 Javascript sintax 有关,与 Jackson 或 JSON 无关。

    在 Javascript 中,名称是一个字母,可选地后跟一个或多个字母、数字或下划线,因此 90110a2e-febd-470f-afa4-cf7e890d31b9 不是合法的 Javascript 名称。

    如果名称是合法的 JavaScript 名称而不是保留字,则属性名称周围的引号是可选的。因此,“first-name”周围需要引号,但 first_name 周围是可选的。

    顺便说一句,如果你这么关心 JSON 的大小,为什么不压缩它呢?

    【讨论】:

    • 谢谢 我已经考虑过了,但我不确定变量是否合法。尽管 json 没有在 javascript 中使用(它是从 Java 客户端发送到 JEE 应用程序),但您所说的可能是正确的。至于 gzip,我已经发送了压缩的 json,但无论如何感谢您的想法。
    【解决方案4】:

    这是一个老问题,但如果有人在这里绊倒并想知道一种让 ALLOW_UNQUOTED_FIELD_NAMES 在较新版本的 jackson 中工作的方法,请使用:

    new ObjectMapper().configure(com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
    

    【讨论】:

      【解决方案5】:

      如果您使用Spring Boot,您可以自动连接ObjectMapper

      @Configuration
      public class JacksonConfig {
      
          @Autowired
          private ObjectMapper objectMapper;
      
          @PostConstruct
          public void configureObjectMapper() {
              objectMapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-08-10
        • 2019-05-02
        • 2014-02-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-27
        • 1970-01-01
        相关资源
        最近更新 更多