模块化JAXB/JAX-WS Maven模块间如何共享/复用类?
问题背景
有一个Maven多模块项目,结构如下:
my-project +- xsd +- src +- main +- resources +- xsd +- foo.xsd [定义foo:UUIDType等基础类型] +- bar.xsd [导入foo.xsd] +- baz.xsd [导入foo.xsd + bar.xsd] +- jaxb +- bindings.xml [定义<jaxb:globalBindings>,包含<xjc:javaType name="java.util.UUID" xmlType="foo:UUIDType" adapter="...UuidXmlAdapter"/>] +- wsdl +- src +- main +- resources +- wsdl +- qux.wsdl [导入qux.xsd] +- qux.xsd [导入foo.xsd + bar.xsd,定义qux.wsdl操作的请求响应类型] +- jaxws +- catalog.cat [定义foo.xsd和bar.xsd的解析规则] +- bindings.xml [定义<jaxb:globalBindings>,包含<xjc:javaType name="java.util.UUID" xmlType="foo:UUIDType" adapter="...UuidXmlAdapter"/>]
- xsd模块使用
org.jvnet.jaxb:jaxb-maven-plugin生成Java类,同时生成sun-jaxb.episode文件 - wsdl模块依赖xsd模块,使用
org.apache.cxf:cxf-codegen-plugin生成JAX-WS类,复用xsd模块的episode文件
遇到的矛盾:
- 若wsdl模块不添加
bindings.xml,qux.xsd里的foo:UUIDType无法映射为java.util.UUID,也不会使用对应的XmlAdapter - 若添加该bindings文件,会触发报错:
Exception in thread "main" org.apache.cxf.tools.common.ToolException: file:/.../myproject/wsdl/src/main/jaxws/bindings.xml [line,col]: compiler was unable to honor this conversion customization. It is attached to a wrong place, or its inconsistent with other bindings.
[WARNING] file:/.../myproject/xsd/src/main/resources/xsd/foo.xsd [line,col]: (the above customization is attached to the following location in the schema)
报错核心原因是全局绑定被重复应用到xsd模块已处理过的Schema上。
解决方案
方案1:限制绑定作用范围,避免全局重复
修改wsdl模块的bindings.xml,将类型绑定仅作用于qux.xsd本身,不影响已通过episode复用的xsd模块Schema:
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" version="2.1"> <!-- 仅对qux.xsd应用绑定规则 --> <jaxb:bindings schemaLocation="../resources/wsdl/qux.xsd"> <jaxb:globalBindings> <xjc:javaType name="java.util.UUID" xmlType="foo:UUIDType" adapter="...UuidXmlAdapter"/> </jaxb:globalBindings> </jaxb:bindings> </jaxb:bindings>
此方式确保绑定规则只作用于当前模块的qux.xsd,不会覆盖或重复作用于xsd模块已处理的Schema,从根源避免冲突。
方案2:提取共享绑定配置,避免重复编写
将通用绑定规则(如UUID类型映射)提取到xsd模块的共享配置文件中(比如xsd/src/main/resources/jaxb/shared-bindings.xml),然后在两个模块中分别引用:
- xsd模块的bindings.xml导入共享文件:
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" version="2.1"> <jaxb:bindings> <jaxb:import namespace="http://java.sun.com/xml/ns/jaxb/xjc" schemaLocation="http://java.sun.com/xml/ns/jaxb/xjc.xsd"/> </jaxb:bindings> <!-- 引入共享绑定规则 --> <jaxb:bindings> <jaxb:import location="classpath:/jaxb/shared-bindings.xml"/> </jaxb:bindings> </jaxb:bindings>
- wsdl模块的bindings.xml仅对qux.xsd引用共享文件:
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" version="2.1"> <jaxb:bindings schemaLocation="../resources/wsdl/qux.xsd"> <jaxb:bindings> <jaxb:import namespace="http://java.sun.com/xml/ns/jaxb/xjc" schemaLocation="http://java.sun.com/xml/ns/jaxb/xjc.xsd"/> </jaxb:bindings> <!-- 引入xsd模块的共享绑定规则 --> <jaxb:bindings> <jaxb:import location="classpath:/jaxb/shared-bindings.xml"/> </jaxb:bindings> </jaxb:bindings> </jaxb:bindings>
该方案既避免重复编写绑定规则,又保证作用范围精准。
方案3:优化CXF代码生成配置,确保episode生效
检查wsdl模块的cxf-codegen-plugin配置,确保正确引入xsd模块的sun-jaxb.episode文件,并启用xjc-episode参数:
<plugin> <groupId>org.apache.cxf</groupId> <artifactId>cxf-codegen-plugin</artifactId> <version>${cxf.version}</version> <executions> <execution> <id>generate-sources</id> <phase>generate-sources</phase> <goals> <goal>wsdl2java</goal> </goals> <configuration> <wsdlOptions> <wsdlOption> <wsdl>${project.basedir}/src/main/resources/wsdl/qux.wsdl</wsdl> <extraargs> <extraarg>-xjc-episode</extraarg> <extraarg>-b</extraarg> <extraarg>${project.basedir}/src/main/jaxws/bindings.xml</extraarg> <!-- 引入xsd模块生成的episode文件 --> <extraarg>-b</extraarg> <extraarg>${project.basedir}/../xsd/target/generated-sources/jaxb/sun-jaxb.episode</extraarg> </extraargs> </wsdlOption> </wsdlOptions> </configuration> </execution> </executions> <dependencies> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-xjc</artifactId> <version>${jaxb.version}</version> </dependency> </dependencies> </plugin>
episode文件会让CXF识别已生成的类,减少重复处理,但如果qux.xsd有新的类型使用场景,仍需针对性绑定。
总结
不需要为每个XSD单独重复绑定,最优方案是限制wsdl模块绑定的作用范围到qux.xsd,同时确保CXF正确复用xsd模块的episode文件,既解决类型映射问题,又避免重复绑定冲突。
内容的提问来源于stack exchange,提问作者Xavier Dury

