如何让CBOR序列化输出与cbor.me在线工具结果一致?
解决CBOR序列化与cbor.me输出不一致的问题
你的问题主要出在两个核心点:Map的无序特性和CBOR结构编码格式,调整这两点就能得到和cbor.me完全一致的输出了。
问题分析
- HashMap的无序性:你用的
HashMap不会维护键的顺序(既不保留插入顺序,也不按自然顺序排序),而cbor.me是按照键的数值升序(123 < 456)来序列化Map的,所以你的输出里键的顺序和在线工具完全相反。 - 不定长度CBOR结构:你的输出以
bf开头,这是CBOR的不定长度Map编码;而cbor.me使用的是A2开头的固定长度Map(明确表示Map包含2个键值对),这是CBORMapper默认配置差异导致的。
解决方案
1. 使用有序Map保证键的顺序
替换HashMap为TreeMap,它会自动按照键的自然顺序(Int的数值大小)排序,确保123排在456前面:
val map = TreeMap<Int, Any>() map[123] = intArrayOf(22, 67, 2) map[456] = intArrayOf(34, 22, 1) // 注意这里把你代码里的12改成22,和问题描述的目标数组一致
2. 配置CBORMapper生成固定长度结构
默认情况下,CBORMapper可能会生成不定长度的CBOR结构,我们需要禁用这个特性,让它生成固定长度的Map和数组:
val mapper = CBORMapper().apply { configure(CBORGenerator.Feature.WRITE_OPEN_STRUCTURES, false) }
完整修改后的代码
import com.fasterxml.jackson.dataformat.cbor.CBORMapper import com.fasterxml.jackson.dataformat.cbor.CBORGenerator import java.util.TreeMap fun main() { val mapper = CBORMapper().apply { // 禁用不定长度结构,使用固定长度的Map/Array编码 configure(CBORGenerator.Feature.WRITE_OPEN_STRUCTURES, false) } // TreeMap自动按键的数值升序排列 val map = TreeMap<Int, Any>() map[123] = intArrayOf(22, 67, 2) map[456] = intArrayOf(34, 22, 1) val cborData = mapper.writeValueAsBytes(map) println(cborData.toHex()) val deserialized = mapper.readValue(cborData, TreeMap::class.java) } // 扩展函数:将ByteArray转为带连字符的十六进制字符串 fun ByteArray.toHex(): String = joinToString("-") { "%02X".format(it) }
验证结果
运行这段代码后,输出的十六进制字符串为:A2-18-7B-83-16-18-43-02-19-01C8-83-18-22-16-01
和cbor.me给出的输出完全对应(把在线工具里的空格换成连字符即可匹配)。
额外说明
如果你不想使用TreeMap,也可以用LinkedHashMap,但需要手动按照升序插入键(先put 123,再put 456),同样能保持顺序。不过TreeMap更省心,会自动处理排序逻辑。
内容的提问来源于stack exchange,提问作者Yasin Eraslan
相关产品推荐
相关产品推荐

