SpringBoot 2+ bootJar jdk11 打包执行 java -jar 异常相关记录:
1. java.lang.ClassNotFoundException: com/sun/tools/internal/xjc/api/XJC
gradle 依赖添加
implementation 'com.sun.xml.bind:jaxb-xjc:2.3.6'
2. java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
gradle 依赖添加
implementation 'javax.xml.bind:jaxb-api:2.3.1'
3. java.lang.IllegalStateException: Unable to create JAXBContext for generated packages: "xxx" doesnt contain ObjectFactory.class or jaxb.index
从 jdk11 开始,jaxb 已从jdk中删除,DynamicClientFactory 需要使用 jaxb api,需要将 jaxb api 放在classpath中。当使用“java -jar”时,需要在 manifest 中添加必要的 classpath。
解决:参考 5. gradle 配置
4. 报错:编码GBK的不可映射字符
import org.apache.cxf.Bus;
import org.apache.cxf.bus.CXFBusFactory;
import org.apache.cxf.endpoint.EndpointImplFactory;
import org.apache.cxf.endpoint.dynamic.DynamicClientFactory;
import org.apache.cxf.helpers.JavaUtils;
import org.apache.cxf.jaxws.support.JaxWsEndpointImplFactory;
import java.io.File;
import java.util.List;
/**
* 解决jdk11 DynamicClientFactory classpath 读取异常
*/
public class JaxWsDynamicClientFactory extends DynamicClientFactory {
protected JaxWsDynamicClientFactory(Bus bus) {
super(bus);
}
@Override
protected EndpointImplFactory getEndpointImplFactory() {
return JaxWsEndpointImplFactory.getSingleton();
}
protected boolean allowWrapperOps() {
return true;
}
/**
* Create a new instance using a specific <tt>Bus</tt>.
*
* @param b the <tt>Bus</tt> to use in subsequent operations with the
* instance
* @return the new instance
*/
public static JaxWsDynamicClientFactory newInstance(Bus b) {
return new JaxWsDynamicClientFactory(b);
}
/**
* Create a new instance using a default <tt>Bus</tt>.
*
* @return the new instance
* @see CXFBusFactory#getDefaultBus()
*/
public static JaxWsDynamicClientFactory newInstance() {
Bus bus = CXFBusFactory.getThreadDefaultBus();
return new JaxWsDynamicClientFactory(bus);
}
/**
* 覆写父类的该方法<br/>
* 注:解决此(错误:编码GBK的不可映射字符)问题
*
* @return
*/
@Override
protected boolean compileJavaSrc(String classPath, List<File> srcList, String dest) {
org.apache.cxf.common.util.Compiler javaCompiler
= new org.apache.cxf.common.util.Compiler();
// 设置编译编码格式(此处为新增代码)
javaCompiler.setEncoding("UTF-8");
javaCompiler.setClassPath(classPath);
javaCompiler.setOutputDir(dest);
if (JavaUtils.isJava9Compatible()) {
javaCompiler.setTarget("9");
} else {
javaCompiler.setTarget("1.8");
}
return javaCompiler.compileFiles(srcList);
}
}
5. build.gradle bootJar 打包配置
原理都是把 jaxb-api.jar 解压到文件系统:
推荐:
bootJar {
requiresUnpack '**/jaxb-api-*.jar'
}
或:
task copyJaxbApi(type: Copy) {
from configurations.runtimeClasspath
into "$buildDir/libs"
include "jaxb-api*"
}
bootJar {
// 复制 jaxb-api 包至 classpath 路径
dependsOn copyJaxbApi
// 指定依赖包的路径 解决jdk11 DynamicClientFactory classpath 读取异常
manifest {
attributes(
'Class-Path': configurations.runtimeClasspath.files.collect { it.getName() }.join(' ')
)
}
}
附: gradle 6.8.3 相关依赖版本
implementation 'org.springframework.boot:spring-boot-starter-web:2.2.2.RELEASE'
implementation 'org.apache.cxf:cxf-rt-frontend-jaxws:3.5.1'
implementation 'org.apache.cxf:cxf-rt-transports-http:3.5.1'
implementation 'javax.xml.ws:jaxws-api:2.3.1'
implementation 'com.sun.xml.bind:jaxb-xjc:2.3.6'
// implementation 'javax.xml.bind:jaxb-api:2.3.1'
参考:
jaxb - How to resolve java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException - Stack Overflow
关于使用cxf调用webservice出现的问题 - 初学者的迷茫 - 博客园