Kryo序列化后访问XML Attribute节点getNodeValue()触发空指针异常
解决Kryo序列化DOM属性节点(AttrImpl)后反序列化调用getNodeValue()空指针问题
问题本质
你遇到的空指针异常,根源在于Xerces的DeferredAttrImpl是延迟加载的DOM节点,它的正常工作依赖所属DeferredDocumentImpl的内部状态(比如chunk索引、子节点同步标记等)。Kryo直接序列化单个Node对象时,只会序列化节点本身的表层属性,无法完整保留它与父文档的内部关联引用。反序列化后,文档对象的内部状态断裂,调用getNodeValue()触发节点同步操作时,就会抛出NPE。
可行解决方案
1. 提前提取属性值(最优方案)
既然最终只需要属性的字符串值,完全没必要序列化DOM节点。初始化AttributeItem时直接提取节点值并存储,彻底规避DOM序列化的坑:
public class AttributeItem implements Item { private static final long serialVersionUID = 1L; private String attributeValue; private Item parent; public AttributeItem(Node attributeNode) { // 序列化前提前提取属性值 this.attributeValue = attributeNode.getNodeValue(); } @Override public void write(Kryo kryo, Output output) { kryo.writeObject(output, this.parent); kryo.writeObject(output, this.attributeValue); } @Override public void read(Kryo kryo, Input input) { this.parent = kryo.readObject(input, Item.class); this.attributeValue = kryo.readObject(input, String.class); } @Override public String stringValue() { // 直接返回预存的值,无需操作DOM return this.attributeValue; } }
2. 序列化完整DOM文档而非单个节点
如果业务必须保留DOM结构,不要单独序列化属性节点,而是序列化整个Document对象。反序列化后,再从完整文档中重新定位需要的属性节点——这样能保证节点与文档的关联关系完整。
3. 自定义Kryo序列化器处理DOM节点
针对Xerces的DOM节点实现自定义序列化逻辑,手动保存和恢复必要的属性,反序列化时重新构建独立的节点对象:
public class AttrSerializer extends Serializer<Attr> { @Override public void write(Kryo kryo, Output output, Attr attr) { // 保存属性的核心信息:名称、值 kryo.writeObject(output, attr.getName()); kryo.writeObject(output, attr.getValue()); } @Override public Attr read(Kryo kryo, Input input, Class<? extends Attr> type) { String name = kryo.readObject(input, String.class); String value = kryo.readObject(input, String.class); // 重新构建一个独立的Attr节点 try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); Document doc = factory.newDocumentBuilder().newDocument(); Attr attr = doc.createAttribute(name); attr.setValue(value); return attr; } catch (ParserConfigurationException e) { throw new RuntimeException("Failed to create Attr node", e); } } }
注册这个序列化器到Kryo:
kryo.register(Attr.class, new AttrSerializer());
内容的提问来源于stack exchange,提问作者mschoeb
相关产品推荐
相关产品推荐

