使用Chronicle Queue v4写入序列化对象时触发AssertionError(header嵌套错误)
这个异常我之前帮好几个开发者排查过,核心问题就是你在序列化对象的过程中,不小心嵌套了Chronicle Wire的header结构——简单说就是你的数据结构里可能包含了另一个带Wire header的对象,或者序列化逻辑重复写入了header。下面分场景给你具体的排查和解决办法:
1. 检查自定义序列化逻辑中的重复header调用
如果你是自己实现Marshallable接口或者自定义Wire编解码器,很容易犯的错误是嵌套对象也调用了writeHeader()。Chronicle Wire的规则是:只有顶级的队列文档需要一个header,嵌套的子对象只需要写字段内容,不能再加header。
错误示例:
// 嵌套对象错误地写入了header public class OrderItem implements Marshallable { private int quantity; @Override public void writeMarshallable(Wire wire) { wire.writeHeader(OrderItem.class); // 这里是问题所在! wire.write("quantity").int32(quantity); } } public class Order implements Marshallable { private List<OrderItem> items; @Override public void writeMarshallable(Wire wire) { wire.writeHeader(Order.class); wire.write("items").sequence(items, (w, item) -> w.marshallable(item)); } }
正确写法:
// 嵌套对象只写字段,不写header public class OrderItem implements Marshallable { private int quantity; @Override public void writeMarshallable(Wire wire) { wire.write("quantity").int32(quantity); } } public class Order implements Marshallable { private List<OrderItem> items; @Override public void writeMarshallable(Wire wire) { wire.writeHeader(Order.class); wire.write("items").sequence(items, (w, item) -> w.marshallable(item)); } }
2. 检查Queue写入API的误用
如果你使用Appender.writeDocument()方法,这个API内部已经会维护队列的文档结构,包括处理header相关的逻辑。如果你在回调里手动调用writeHeader(),就会导致重复写入,触发断言。
错误示例:
SingleChronicleQueue queue = SingleChronicleQueueBuilder.binary("/tmp/queue").build(); ExcerptAppender appender = queue.acquireAppender(); // 错误:writeDocument内部已处理header,无需手动调用 appender.writeDocument(wire -> { wire.writeHeader(User.class); wire.write("name").text("Alice"); });
正确写法:
SingleChronicleQueue queue = SingleChronicleQueueBuilder.binary("/tmp/queue").build(); ExcerptAppender appender = queue.acquireAppender(); // 直接写入字段即可,writeDocument会处理文档结构 appender.writeDocument(wire -> { wire.write("name").text("Alice"); wire.write("age").int32(30); }); // 或者如果你需要指定文档类型,用带类型的重载方法 appender.writeDocument(User.class, (wire, user) -> { wire.write("name").text(user.getName()); wire.write("age").int32(user.getAge()); });
3. 排查第三方序列化工具的配置问题
如果是用第三方序列化框架(比如Jackson结合Chronicle Wire模块),某些插件可能会默认给每个序列化的对象添加Wire header。当你序列化嵌套对象时,就会出现header嵌套的情况。
解决办法是:找到序列化配置,禁用嵌套对象的header自动生成,只让顶级对象保留header。比如调整Jackson的Chronicle Wire模块配置,关闭子对象的header生成开关。
核心原理回顾
Chronicle Queue v4的文档结构是严格的单层级header+内容模式:每个写入队列的条目是一个独立文档,只能有一个顶级header,所有嵌套的数据都是该文档的内容部分,不能再包含独立的header。这个断言就是为了防止破坏这种结构,导致后续读取时解析失败。
内容的提问来源于stack exchange,提问作者Abhijeet Desai

