You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 15:17:39