如何处理XSD生成的两个不同Java类型中的重复数据?
解决方案建议
针对你遇到的多XSD生成重复Java类型的问题,结合使用的jaxb40-maven-plugin、Java 17和Spring Boot,推荐以下几个实用方案,按优先级排序:
1. 外部绑定文件统一生成重复类型(最优解)
无需修改原XSD文件,通过JAXB的外部绑定文件,强制将不同XSD中结构相同的类型映射为同一个Java类,从根源上避免重复类型。
操作步骤:
- 编写XML绑定文件(比如
src/main/resources/bindings/common-types-binding.xml),指定重复类型的统一包名和类名,对其他XSD中的同名同结构类型直接引用已定义的类:
<jaxb:bindings xmlns:jaxb="https://jakarta.ee/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" jaxb:version="4.0"> <!-- 为第一个XSD中的类型指定统一类 --> <jaxb:bindings schemaLocation="xsd/service-a.xsd"> <jaxb:bindings node="//xsd:complexType[@name='CustomerType']"> <jaxb:class name="CustomerType" packageName="com.yourproject.common.soap.types"/> </jaxb:bindings> </jaxb:bindings> <!-- 让第二个XSD中的同名类型直接复用已定义的类 --> <jaxb:bindings schemaLocation="xsd/service-b.xsd"> <jaxb:bindings node="//xsd:complexType[@name='CustomerType']"> <jaxb:class ref="com.yourproject.common.soap.types.CustomerType"/> </jaxb:bindings> </jaxb:bindings> </jaxb:bindings>
- 在
jaxb40-maven-plugin中配置绑定文件路径:
<plugin> <groupId>com.helger.maven</groupId> <artifactId>jaxb40-maven-plugin</artifactId> <version>4.0.1</version> <executions> <execution> <goals> <goal>generate</goal> </goals> <configuration> <schemaDirectory>${project.basedir}/src/main/resources/xsd</schemaDirectory> <bindingDirectory>${project.basedir}/src/main/resources/bindings</bindingDirectory> <bindingFiles> <bindingFile>common-types-binding.xml</bindingFile> </bindingFiles> <!-- 保留你的其他配置(比如生成策略、包名等) --> </configuration> </execution> </executions> </plugin>
这个方案直接在代码生成阶段统一类型,后续业务逻辑无需处理转换,完全复用同一类型的代码。
2. 优化MapStruct配置适配生成类
如果暂时无法修改生成逻辑,可通过调整MapStruct配置适配带Optional getter和构建器的生成类,实现自动映射。
关键配置:
- 定义MapStruct映射接口时,启用Spring组件模型和构建器支持:
@Mapper(componentModel = "spring", builder = @Builder(disableBuilder = false)) public interface CommonTypeMapper { CommonTypeMapper INSTANCE = Mappers.getMapper(CommonTypeMapper.class); // 将服务A的类型映射为通用类型 com.yourproject.common.soap.types.CustomerType mapFromServiceA(com.yourproject.servicea.soap.CustomerType source); // 将服务B的类型映射为通用类型 com.yourproject.common.soap.types.CustomerType mapFromServiceB(com.yourproject.serviceb.soap.CustomerType source); // 反向映射用于请求构建 com.yourproject.servicea.soap.CustomerType mapToServiceA(com.yourproject.common.soap.types.CustomerType source); }
MapStruct会自动识别Optional类型的getter和构建器模式,无需手动编写转换逻辑,在Spring环境中可直接注入使用。
3. 自定义JAXB插件自动合并重复类型
如果存在大量重复类型,手动编写绑定文件效率低,可自定义JAXB插件,自动检测结构完全一致的类型(通过元素名、字段类型、约束等匹配),强制生成同一Java类。
核心思路:
- 实现
com.sun.tools.xjc.Plugin接口(jaxb-tools提供的扩展点),在代码生成前遍历所有XSD的类型定义,对结构相同的类型标记为同一类。 - 在maven插件中配置启用自定义插件,无需修改原XSD即可自动合并。
4. JAXB XmlAdapter适配已生成的重复类型
如果已经生成了重复类且无法重新生成,可通过JAXB的XmlAdapter在序列化/反序列化阶段自动转换为通用类型。
示例适配器:
public class CustomerTypeAdapter extends XmlAdapter<Object, com.yourproject.common.soap.types.CustomerType> { @Override public com.yourproject.common.soap.types.CustomerType unmarshal(Object source) throws Exception { if (source instanceof com.yourproject.servicea.soap.CustomerType s1) { return com.yourproject.common.soap.types.CustomerType.builder() .id(s1.getId().orElse(null)) .name(s1.getName().orElse(null)) .build(); } else if (source instanceof com.yourproject.serviceb.soap.CustomerType s2) { return com.yourproject.common.soap.types.CustomerType.builder() .id(s2.getId().orElse(null)) .name(s2.getName().orElse(null)) .build(); } return null; } @Override public Object marshal(com.yourproject.common.soap.types.CustomerType target) throws Exception { // 根据当前调用的服务选择对应的类型,示例为服务A return com.yourproject.servicea.soap.CustomerType.builder() .id(Optional.ofNullable(target.getId())) .name(Optional.ofNullable(target.getName())) .build(); } }
- 在创建
JAXBContext时注册适配器,或通过绑定文件给生成的类添加@XmlJavaTypeAdapter(CustomerTypeAdapter.class)注解。
内容的提问来源于stack exchange,提问作者condiorno
相关产品推荐
相关产品推荐

