Spring Boot 3.1+Java17搭建SOAP客户端遇JAXB异常求助
问题描述
基于Java 17和Spring 3.1.0搭建Spring Boot SOAP客户端时遇到JAXB异常,具体操作及报错如下:
操作步骤
从WSDL生成类
- 生成目录修改为
${project.basedir}/target/generate-sources,改回src/main/java问题依旧。 - pom.xml相关配置:
<plugin> <groupId>org.jvnet.jaxb2.maven2</groupId> <artifactId>maven-jaxb2-plugin</artifactId> <version>0.14.0</version> <executions> <execution> <goals> <goal>generate</goal> </goals> </execution> </executions> <configuration> <schemaLanguage>WSDL</schemaLanguage> <generateDirectory>${project.basedir}/target/generate-sources</generateDirectory> <generatePackage>de.mat.test.country</generatePackage> <schemaDirectory>${project.basedir}/src/main/resources/wsdl</schemaDirectory> <schemaIncludes> <include>countries.wsdl</include> </schemaIncludes> </configuration> </plugin>类生成正常,可在代码中正常导入使用。
- 生成目录修改为
创建Client和ClientConfig类
- CountryClient类:
public class CountryClient extends WebServiceGatewaySupport { public GetCountryResponse getCountry(String country) { GetCountryRequest request = new GetCountryRequest(); request.setName(country); var webServiceTemplate = getWebServiceTemplate(); var response = webServiceTemplate.marshalSendAndReceive(request); GetCountryResponse getCountryResponse = (GetCountryResponse) response; return getCountryResponse; } }- CountryClientConfig类:
@Configuration public class CountryClientConfig { @Bean public Jaxb2Marshaller marshaller() { Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); marshaller.setContextPath("de.mat.test.country"); // 仅此处修改 return marshaller; } @Bean public CountryClient countryClient(Jaxb2Marshaller marshaller) { CountryClient client = new CountryClient(); client.setDefaultUri("http://localhost:8080/ws"); client.setMarshaller(marshaller); client.setUnmarshaller(marshaller); return client; } }创建测试类(适配Spring新版本修改注解)
@SpringBootTest // 原教程为@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = CountryClientConfig.class, loader = AnnotationConfigContextLoader.class) public class ClientLiveTest { @Autowired CountryClient client; @Test public void givenCountryService_whenCountryGermany_thenCapitalIsBerlin() { GetCountryResponse response = client.getCountry("GER"); assertEquals("BLN", response.getCountry().getCapital()); } @Test public void givenCountryService_whenCountrySpain_thenCurrencyEUR() { GetCountryResponse response = client.getCountry("ESP"); assertEquals(Currency.EUR, response.getCountry().getCurrency()); } }
报错信息
运行测试时抛出JAXB异常:
org.springframework.oxm.UncategorizedMappingException: Unknown JAXB exception at org.springframework.oxm.jaxb.Jaxb2Marshaller.convertJaxbException(Jaxb2Marshaller.java:958) at org.springframework.oxm.jaxb.Jaxb2Marshaller.marshal(Jaxb2Marshaller.java:716) at org.springframework.ws.support.MarshallingUtils.marshal(MarshallingUtils.java:80) at org.springframework.ws.client.core.WebServiceTemplate$2.doWithMessage(WebServiceTemplate.java:399) at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:569) at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:539) at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:391) at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:385) at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:375) at de.mat.test.client.CountryClient2.getCountry(CountryClient2.java:15) at de.mat.test.ClientLiveTest.givenCountryService_whenCountrySpain_thenCurrencyEUR(ClientLiveTest.java:31) at java.base/java.util.ArrayList.forEach(Unknown Source) at java.base/java.util.ArrayList.forEach(Unknown Source) Caused by: jakarta.xml.bind.JAXBException: class de.mat.test.country.GetCountryRequest nor any of its super class is known to this context. at org.glassfish.jaxb.runtime.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.java:543) at org.glassfish.jaxb.runtime.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:444) at org.glassfish.jaxb.runtime.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:265) at org.glassfish.jaxb.runtime.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:197) at org.springframework.oxm.jaxb.Jaxb2Marshaller.marshal(Jaxb2Marshaller.java:712)
解决方案
该问题核心是JAXBContext无法识别生成的实体类,针对Java 17+Spring 3.x的环境,可通过以下方式解决:
1. 替换setContextPath为setClassesToBeBound
Spring 3.x搭配Java 17时,setContextPath方法在处理模块路径下的生成类时易失效,改用setClassesToBeBound直接指定需要绑定的类,确保JAXB能识别:
@Bean public Jaxb2Marshaller marshaller() { Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); // 替换原setContextPath,直接指定生成的请求、响应等类 marshaller.setClassesToBeBound(GetCountryRequest.class, GetCountryResponse.class, Country.class, Currency.class); return marshaller; }
2. 确保生成类被编译识别
- 检查
target/generate-sources目录是否被IDE标记为源码根目录,若未标记,手动设置该目录为Sources Root,确保编译时包含这些类。 - 执行
mvn clean compile命令,强制Maven编译生成类,避免类路径缺失问题。
3. 适配JPMS模块配置(若启用)
如果项目使用Java模块系统(存在module-info.java),需添加JAXB依赖并导出生成类的包:
module de.mat.test { requires jakarta.xml.bind; requires spring.ws; requires spring.context; // 导出生成类的包,允许JAXB访问 exports de.mat.test.country; }
4. 简化测试类注解
@SpringBootTest已包含上下文配置,可移除冗余的@ContextConfiguration:
@SpringBootTest(classes = CountryClientConfig.class) public class ClientLiveTest { // 测试代码保持不变 }
5. 验证JAXB依赖兼容性
确保项目中JAXB依赖(如org.glassfish.jaxb:jaxb-runtime)与Spring 3.1.0兼容,建议使用Spring Boot管理的依赖版本,避免版本冲突。
内容的提问来源于stack exchange,提问作者P D
相关产品推荐
相关产品推荐

