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

使用docx4j+MOXy处理含形状docx时出现跨模块ClassCastException

问题描述

使用docx4j读取docx文件,替换w:ins/w:del标记的修订作者名为固定字符串"External",pom.xml引入了docx4j-core、docx4j-JAXB-MOXy和org.eclipse.persistence.moxy依赖。处理包含形状的docx文档时,抛出如下ClassCastException:

org.docx4j.com.microsoft.schemas.office.word.x2010.wordprocessingShape.CTWordprocessingShape无法转换为org.eclipse.persistence.internal.oxm.Root
错误发生在AbstractMarshalRecordImpl.java第211行。已尝试改用ReferenceImpl规避问题,现寻求其他解决方案。


解决方案

方案1:切换JAXB实现为JAXB-RI(JDK默认实现)

MOXy在处理Office形状相关JAXB类时存在类型转换逻辑冲突,改用JDK自带的JAXB-RI可避免该问题。

  • 修改pom.xml,移除MOXy相关依赖,替换为docx4j的JAXB-Internal实现:
<dependencies>
    <dependency>
        <groupId>org.docx4j</groupId>
        <artifactId>docx4j-core</artifactId>
        <version>8.3.9</version> <!-- 替换为你当前使用的版本 -->
    </dependency>
    <dependency>
        <groupId>org.docx4j</groupId>
        <artifactId>docx4j-JAXB-Internal</artifactId>
        <version>8.3.9</version>
    </dependency>
</dependencies>
  • 代码无需额外修改,docx4j会自动切换到JAXB-RI,对复杂形状元素的兼容性更好。

方案2:升级docx4j至最新稳定版

新版本docx4j通常会修复MOXy与形状类的兼容性bug,这是最稳妥的修复方式之一。

  • 更新pom.xml中的依赖版本:
<dependency>
    <groupId>org.docx4j</groupId>
    <artifactId>docx4j-core</artifactId>
    <version>8.3.11</version> <!-- 替换为最新稳定版 -->
</dependency>
<dependency>
    <groupId>org.docx4j</groupId>
    <artifactId>docx4j-JAXB-MOXy</artifactId>
    <version>8.3.11</version>
</dependency>
<dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>org.eclipse.persistence.moxy</artifactId>
    <version>4.0.2</version> <!-- 匹配docx4j对应的MOXy版本 -->
</dependency>

方案3:排除形状相关类的JAXB上下文初始化

若必须使用MOXy,可在初始化JAXB上下文时排除CTWordprocessingShape类,避免触发类型转换逻辑。

  • 自定义JAXB上下文提供者:
import org.docx4j.jaxb.Context;
import org.eclipse.persistence.jaxb.JAXBContextFactory;

import javax.xml.bind.JAXBContext;
import java.util.HashMap;
import java.util.Map;
import java.util.Arrays;

public class CustomJAXBContextProvider {
    public static JAXBContext createContext() throws Exception {
        Map<String, Object> properties = new HashMap<>();
        properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, 
                       Context.getJAXBContext().getProperties().get(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY));
        
        // 排除形状相关类
        Class<?>[] excludedClasses = {org.docx4j.com.microsoft.schemas.office.word.x2010.wordprocessingShape.CTWordprocessingShape.class};
        
        return JAXBContext.newInstance(
            Arrays.stream(Context.getJAXBContext().getClasses())
                  .filter(clazz -> !Arrays.asList(excludedClasses).contains(clazz))
                  .toArray(Class<?>[]::new),
            properties
        );
    }
}
  • 在代码初始化阶段设置自定义上下文:
Context.setJAXBContext(CustomJAXBContextProvider.createContext());

注意:此方案会导致形状元素无法正常序列化,仅适用于不需要修改形状、仅处理修订作者的场景。

方案4:处理修订时跳过形状相关节点

遍历修订节点时,显式过滤掉父节点为形状的元素,避免触发MOXy的序列化逻辑。

  • 修订处理示例代码:
import org.docx4j.wml.*;
import java.util.List;
import java.util.stream.Collectors;

public class RevisionProcessor {
    public static void replaceAuthors(WordprocessingMLPackage pkg) {
        MainDocumentPart mainPart = pkg.getMainDocumentPart();
        List<Object> revisions = mainPart.getJAXBNodesViaXPath("//w:ins | //w:del", true);
        
        // 过滤掉形状内的修订节点
        List<Object> filteredRevisions = revisions.stream()
            .filter(node -> {
                if (node instanceof Ins) {
                    return !isParentShape((Ins) node);
                } else if (node instanceof Del) {
                    return !isParentShape((Del) node);
                }
                return true;
            })
            .collect(Collectors.toList());
        
        for (Object revision : filteredRevisions) {
            if (revision instanceof Ins) {
                ((Ins) revision).setAuthor("External");
            } else if (revision instanceof Del) {
                ((Del) revision).setAuthor("External");
            }
        }
    }
    
    private static boolean isParentShape(ContentAccessor node) {
        Object parent = node.getParent();
        if (parent instanceof org.docx4j.XmlUtils.Element) {
            org.docx4j.XmlUtils.Element elem = (org.docx4j.XmlUtils.Element) parent;
            return "http://schemas.microsoft.com/office/word/2010/wordprocessingShape".equals(elem.getNamespaceURI())
                    && "shape".equals(elem.getLocalName());
        }
        return false;
    }
}

此方案可绕过形状内的修订处理,但如果需要修改形状内的修订作者,则不适用。

内容的提问来源于stack exchange,提问作者user304611

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 02:32:04