环境:jdk1.8.0_291
项目引入了jaxen-1.1-beta-6.jar包
项目启动报了如下的错:
[2021-10-14 11:12:05.382] [ERROR] [main] [Configuration.java:2730]- [Failed to set setXIncludeAware(true) for parser org.apache.xerces.jaxp.DocumentBuilderFactoryImpl@4cbad1d4]
java.lang.UnsupportedOperationException: setXIncludeAware is not supported on this JAXP implementation or earlier: class org.apache.xerces.jaxp.DocumentBuilderFactoryImpl
at javax.xml.parsers.DocumentBuilderFactory.setXIncludeAware(DocumentBuilderFactory.java:584)
at org.apache.hadoop.conf.Configuration.loadResource(Configuration.java:2728)
at org.apache.hadoop.conf.Configuration.loadResources(Configuration.java:2696)
at org.apache.hadoop.conf.Configuration.getProps(Configuration.java:2579)
at org.apache.hadoop.conf.Configuration.set(Configuration.java:1257)
at org.apache.hadoop.conf.Configuration.set(Configuration.java:1229)
at com.code.common.hdfs.HDFSClient.init(HDFSClient.java:71)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:366)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:311)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:134)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:409)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1620)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107)
at com.dragonsoft.cicada.datacenter.DataCenterWebApplication.main(DataCenterWebApplication.java:21)
这个问题主要是:jaxen的包里面DocumentBuilderFactoryImpl没有实现DocumentBuilderFactory的setXIncludeAware这个方法。
细节分析:
org.apache.hadoop.conf.Configuration里面的loadResource方法中,构建DocumentBuilderFactory实例,一步一步跟进去看:
static <T> T find(Class<T> type, String fallbackClassName)
throws FactoryConfigurationError
{
final String factoryId = type.getName();
dPrint("find factoryId =" + factoryId);
// Use the system property first
try {
String systemProp = ss.getSystemProperty(factoryId);
if (systemProp != null) {
dPrint("found system property, value=" + systemProp);
return newInstance(type, systemProp, null, true);
}
}
catch (SecurityException se) {
if (debug) se.printStackTrace();
}
// try to read from $java.home/lib/jaxp.properties
try {
if (firstTime) {
synchronized (cacheProps) {
if (firstTime) {
String configFile = ss.getSystemProperty("java.home") + File.separator +
"lib" + File.separator + "jaxp.properties";
File f = new File(configFile);
firstTime = false;
if (ss.doesFileExist(f)) {
dPrint("Read properties file "+f);
cacheProps.load(ss.getFileInputStream(f));
}
}
}
}
final String factoryClassName = cacheProps.getProperty(factoryId);
if (factoryClassName != null) {
dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName);
return newInstance(type, factoryClassName, null, true);
}
}
catch (Exception ex) {
if (debug) ex.printStackTrace();
}
// Try Jar Service Provider Mechanism
T provider = findServiceProvider(type);
if (provider != null) {
return provider;
}
if (fallbackClassName == null) {
throw new FactoryConfigurationError(
"Provider for " + factoryId + " cannot be found");
}
dPrint("loaded from fallback value: " + fallbackClassName);
return newInstance(type, fallbackClassName, null, true);
}
这个方法,先会去从系统属性中获取资源名称,如果没有则尝试从$java.home/lib/jaxp.properties文件读取资源,如果还没有则通过应用类加载器找到类实例。因为我的系统属性没有这个资源名称,也没有jaxp.properties这个配置文件,所以会通过应用类加载器加载jaxen包下的类实例,DocumentBuilderFactory的setXIncludeAware这个方法,所以报了这个错。
解决方法:
方法一:(不建议)
在你使用的jdk安装路径下的/jre/lib下面
如果存在jaxp.properties则将其中内容改为下面的配置就可以了javax.xml.parsers.SAXParserFactory=com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl
javax.xml.parsers.DocumentBuilderFactory=com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
如果不存在javafx.properties,创建文件,把内容复制粘贴进去,添加到/jre/lib下面
方法二:
创建一个包名路径与xercesImpl-2.6.2.jar里面DocumentBuilderFactoryImpl相同的类,然后在这个类里面实现setXIncludeAware的方法,然后重编译之后,将这个新类的class文件替换到xercesImpl-2.6.2.jar 里面。