JBoss中第三方Drill JDBC驱动与__DocumentBuilderFactory冲突求助
I’ve dealt with this exact class loader conflict when setting up Drill JDBC in JBoss modules before—this is caused by JBoss’s redirected JAXP classes clashing with Hadoop’s Configuration class, which doesn’t explicitly specify a class loader when creating DocumentBuilderFactory instances. Here are the proven solutions to resolve this:
Solution 1: Update Your Module.xml to Properly Import JAXP Services
Your current module configuration is missing explicit dependencies on JBoss’s JAXP modules, which are critical to ensuring the correct factory implementations load within your driver’s module context. Modify your module.xml as follows:
<module xmlns="urn:jboss:module:1.3" name="vermilion.jdbc.others" slot="main"> <resources> <resource-root path="drill-jdbc-all-1.13.0.jar"/> </resources> <dependencies> <module name="javax.api"/> <module name="javax.transaction.api"/> <module name="sun.jdk"/> <module name="org.apache.commons.collections"/> <!-- Add explicit JAXP dependencies with service imports --> <module name="javax.xml.parsers.api"/> <module name="javax.xml.bind.api"/> <!-- Import JAXP service providers to avoid redirected class leaks --> <module name="com.sun.xml.bind" services="import"/> <module name="com.sun.xml.stream" services="import"/> </dependencies> </module>
The services="import" attribute tells JBoss to load the official JAXP service providers (like the Sun/Oracle implementations) into your driver’s class loader, preventing the redirected __DocumentBuilderFactory from being used.
Solution 2: Force Hadoop Configuration to Use the Module’s Class Loader
If updating the module.xml doesn’t fix the issue, explicitly set the class loader for Hadoop’s Configuration before initializing your Drill connection. Add this code right before calling DriverManager.getConnection():
// Load your Drill JDBC module's class loader ModuleIdentifier moduleId = ModuleIdentifier.fromString("vermilion.jdbc.others:main"); ModuleClassLoader moduleClassLoader = Module.getModuleFromCallerModuleLoader() .loadModule(moduleId) .getClassLoader(); // Set the thread's context class loader to your module's loader Thread.currentThread().setContextClassLoader(moduleClassLoader); // Initialize Hadoop Configuration with the module's class loader Configuration hadoopConf = new Configuration(); hadoopConf.setClassLoader(moduleClassLoader); // Now create your Drill connection as usual Connection conn = DriverManager.getConnection(jdbcUrl, username, password);
This ensures that when Hadoop’s Configuration.loadResource() calls DocumentBuilderFactory.newInstance(), it uses your driver’s module class loader instead of JBoss’s default application class loader, eliminating the class cast mismatch.
Solution 3: Disable JBoss’s JAXP Redirection (Last Resort)
If the above solutions don’t work, you can disable JBoss’s redirected JAXP classes for your deployment. Create or update a jboss-deployment-structure.xml in your deployment’s META-INF or WEB-INF directory:
<jboss-deployment-structure> <deployment> <exclude-subsystems> <subsystem name="jaxp-processing"/> </exclude-subsystems> <exclusions> <module name="org.jboss.as.jaxp"/> </exclusions> </deployment> </jboss-deployment-structure>
⚠️ Note: This disables JBoss’s JAXP security and class loading controls, so only use this as a last resort if the other fixes fail.
Why This Happens
JBoss EAP/WildFly uses __redirected classes to wrap standard JAXP APIs for security and class loading isolation. When Hadoop’s Configuration class calls DocumentBuilderFactory.newInstance() without specifying a class loader, it falls back to the thread’s context class loader (which is typically JBoss’s application class loader). This creates an instance of __redirected.__DocumentBuilderFactory, which can’t be cast to the standard javax.xml.parsers.DocumentBuilderFactory loaded from your driver’s module class path—hence the ClassCastException.
内容的提问来源于stack exchange,提问作者Joash

