将公共类移至父包后JAXB解包映射失败问题求助
我有多个对应不同版本(通过不同命名空间标识)的XSD文件,其中包含大量跨版本通用的复杂类型,使用XJC生成Java类时会产生大量重复类。为避免重复,我将公共类移至com.acme.common父包,并修改了ObjectFactory.java中的导入配置,但在解包XML时,仅根层级基本类型字段能映射成功,其他引用公共包类的字段为null或空值。若将所有类放在同一包下则映射正常。
生成JAXB类的命令如下:
xjc rixml-2_5.xsd -p com.acme.A -verbose -XautoNameResolution xjc rixml-2_4.xsd -p com.acme.B -verbose -XautoNameResolution
获取JAXB上下文的代码如下:
private static final Class<?>[] classesToBeBound = new Class<?>[] { com.acme.A.ObjectFactory.class, com.acme.B.ObjectFactory.class }; private static JAXBContext context; static { try { context = JAXBContext.newInstance(classesToBeBound); } catch (JAXBException e) { throw new RuntimeException(e); } }
请问是否可通过JAXB或其他Java库解决该问题?
当然可以解决,核心是让JAXB正确识别跨包的公共类,以下是几种可行方案:
1. 修正JAXB上下文初始化,包含公共包类
你当前的classesToBeBound只包含了A、B包的ObjectFactory,但JAXB无法自动发现com.acme.common下的公共类,导致解包时无法映射这些类型的字段。需要把公共类也加入上下文初始化参数:
private static final Class<?>[] classesToBeBound = new Class<?>[] { com.acme.A.ObjectFactory.class, com.acme.B.ObjectFactory.class, // 添加公共包下的核心类,或直接加公共包的ObjectFactory(如果存在) com.acme.common.CommonType1.class, com.acme.common.CommonType2.class // 其他公共类依次添加 };
如果公共类较多,也可以直接指定包名初始化上下文(需确保包下有jaxb.index文件或ObjectFactory):
context = JAXBContext.newInstance("com.acme.A:com.acme.B:com.acme.common");
2. 生成类时直接指定公共类型的绑定(推荐,避免手动移类)
不要手动移动类,而是通过XJC的外部绑定文件(binding.xjb)提前指定公共类型的包路径,让XJC直接把跨版本通用的复杂类型生成到com.acme.common包,避免后续手动修改的问题。
示例binding.xjb内容:
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" jaxb:version="2.1"> <!-- 绑定2_5版本XSD中的通用类型到公共包 --> <jaxb:bindings schemaLocation="rixml-2_5.xsd" node="/xsd:schema"> <jaxb:bindings node="//xsd:complexType[@name='CommonType1']"> <jaxb:class name="CommonType1" package="com.acme.common"/> </jaxb:bindings> <jaxb:bindings node="//xsd:complexType[@name='CommonType2']"> <jaxb:class name="CommonType2" package="com.acme.common"/> </jaxb:bindings> </jaxb:bindings> <!-- 对2_4版本XSD做同样的绑定 --> <jaxb:bindings schemaLocation="rixml-2_4.xsd" node="/xsd:schema"> <jaxb:bindings node="//xsd:complexType[@name='CommonType1']"> <jaxb:class name="CommonType1" package="com.acme.common"/> </jaxb:bindings> <jaxb:bindings node="//xsd:complexType[@name='CommonType2']"> <jaxb:class name="CommonType2" package="com.acme.common"/> </jaxb:bindings> </jaxb:bindings> </jaxb:bindings>
生成类时指定绑定文件:
xjc rixml-2_5.xsd -p com.acme.A -verbose -XautoNameResolution -b binding.xjb xjc rixml-2_4.xsd -p com.acme.B -verbose -XautoNameResolution -b binding.xjb
这样XJC会自动把指定的通用类型生成到公共包,且自动处理ObjectFactory的依赖,无需手动修改,解包时只要上下文包含三个包的类即可正常映射。
3. 使用MOXy替代原生JAXB(可选)
如果你愿意更换JAXB实现,Eclipse MOXy对跨包类型的识别更灵活,它支持通过jaxb.properties指定实现,且初始化上下文时能自动扫描关联的类,减少手动配置的麻烦。只需添加MOXy依赖,然后在每个包下添加jaxb.properties文件,内容为:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
之后初始化上下文的代码可以保持不变,MOXy会自动发现公共包的类。
内容的提问来源于stack exchange,提问作者Paras

