将固定大小的Map序列化为CBOR

时间:2018-02-26 15:19:51

标签: java json serialization jackson cbor

我有以下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();
}

这是Jackson二进制格式库的错误还是我错过了ObjectMapper的一些配置属性?

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

2 个答案:

答案 0 :(得分: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有效表示“ true”。取0xF5(11110101)的前三位(CBOR主要类型),然后将十进制21设置为已建立的CBOR“ true”(0x00010101)。

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

这是编码器质量较差的问题,不应该使用不确定的长度映射/中断。有时间使用它们,但是只能在“流”模式下使用,对于给定的示例来说是不可能的。如果您将所有项目放在前面并进行编码,则不需要使用不定式。如果您有一定数量的地图,但不确定要映射多少,并希望开始对自己所拥有的内容进行编码,那就是需要无限长的地图或字符串的方法。

答案 1 :(得分:0)

通过使用版本2.9.4CBORGenerator课程中提供了以下方法:public 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