5

我有以下 JSON:

[
  {
    2: {
      "c": true
    }
  },
  {
    3: {
      "p": 10
    }
  }
]

我想转换为 CBOR 格式。根据 cbor.me 我有以下输出:

82A102A16163F5A103A161700A

但是,当使用 Jackson Binary CBOR Serializer 时,我有以下输出:

82BF02BF6163F5FFFFBF03BF61700AFFFF

这没有错,但没有优化......我有一个额外的 4 个不必要的字节添加到它实际上是什么。

然后我尝试手动序列化 JSON 但结果相同:

@Override
public void serialize(Request value, JsonGenerator jgen, SerializerProvider provider)
        throws IOException, JsonProcessingException {
    jgen.writeStartArray(value.getDataList().size());
    for (Data data : value.getDataList()) {
        jgen.writeStartObject(new Map[1]);
        jgen.writeFieldId(data.getItem());
        jgen.writeStartObject();
        if (data.getObject().getC() != null) {
            jgen.writeBooleanField("c", data.getObject().getC());
        }
        if (data.getObject().getP() != null) {
            jgen.writeNumberField("p", data.getObject().getP());
        }
        jgen.writeEndObject();
        jgen.writeEndObject();
    }
    jgen.writeEndArray();
}

这是杰克逊二进制格式库的错误还是我缺少 ObjectMapper 的一些配置属性?

编辑:这似乎是一个已知问题:https ://github.com/FasterXML/jackson-dataformats-binary/issues/3

4

2 回答 2

1

您已经收到了使用更新或更好编码器的答案。但是对于以后来这里的其他人...

问题是 OP 的编码器使用不定长度映射,然后使用“BREAK”原语突破并转到下一个项目。

将版本与中断原语进行比较:

82             # array(2)
   BF          # map(*)
      02       # unsigned(2)
      BF       # map(*)
         61    # text(1)
            63 # "c"
         F5    # primitive(21)
         FF    # primitive(*)
      FF       # primitive(*)
   BF          # map(*)
      03       # unsigned(3)
      BF       # map(*)
         61    # text(1)
            70 # "p"
         0A    # unsigned(10)
         FF    # primitive(*)
      FF       # primitive(*)

对于没有它们的版本:

82             # array(2)
   A1          # map(1)
      02       # unsigned(2)
      A1       # map(1)
         61    # text(1)
            63 # "c"
         F5    # primitive(21)
   A1          # map(1)
      03       # unsigned(3)
      A1       # map(1)
         61    # text(1)
            70 # "p"
         0A    # unsigned(10)

您看到地图(*)与地图(1)吗?

通过使用具有特定长度而不是无限长度的地图,生成的 CBOR 可以使用“一张地图来了,就在这里”而不是“IDK!地图来了!这是一张!现在停止!”

在第二个示例中,仍然有一个原语,但它不是 BREAK 命令。0xF5 实际上意味着“真实”。将前三位(CBOR 主要类型)从 0xF5(11110101)中取出,您将得到十进制 21,即已建立的 CBOR“真”(0x00010101)。

此外,将值 2 分配为其中包含 "c"="true" 的地图的名称是完全有效的。但是请注意,如果您担心的话,在使用值作为名称时转换为 JSON 会出现问题。

这是一个不应该使用无限长度映射/中断的不良编码器的问题。有时间使用这些,但仅限于“流式”模式,这对于给出的示例来说不太可能。如果您预先准备好所有项目并进行编码,则不需要使用不定式。如果您有一些映射但不确定有多少并且想要开始对您拥有的映射进行编码,那么您将需要无限长度的映射或字符串。

于 2019-10-28T19:50:32.237 回答
0

通过使用版本2.9.4,类中可以使用以下方法CBORGeneratorpublic final void writeStartObject(int elementsToWrite)

@Override
public void serialize(Request value, JsonGenerator jgen, SerializerProvider provider)
        throws IOException, JsonProcessingException {
    jgen.writeStartArray(value.getDataList().size());
    for (Data data : value.getDataList()) {
        ((CBORGenerator) jgen).writeStartObject(1);
        jgen.writeFieldId(data.getItem());
        ((CBORGenerator) jgen).writeStartObject(1);
        if (data.getObject().getC() != null) {
            jgen.writeBooleanField("c", data.getObject().getC());
        }
        if (data.getObject().getP() != null) {
            jgen.writeNumberField("p", data.getObject().getP());
        }
        jgen.writeEndObject();
        jgen.writeEndObject();
    }
    jgen.writeEndArray();
}

我有以下输出:

82A102A16163F5A103A161700A

于 2018-03-10T12:46:00.343 回答