Hi,
I've started testing the JBossWS integration with Apache CXF 3 and I'm
currently dealing with a classloading issue on client side.
A relevant difference between 2.7.x and 3 when it comes to JAXWS client proxies
is that on 3 they implement the org.apache.cxf.endpoint.Client interface [1],
while on 2.7.x they don't.
When building up a JAXWS client, the org.apache.cxf.common.util.ProxyHelper is
used to decide which classloader will later be passed to the JDK Proxy for
building the proxy instance. If the classloader that loaded the user service
class has visibility over all the interfaces the proxy has to implement, that
classloader is used, otherwise a ProxyClassloader is built. The
ProxyClassloader is basically a combination of the classloaders that loaded
each specific interface class.
Now, with Apache CXF 2.7.x, the user application needs to have visibility over the JAX-WS api only,
while with 3.0 it also needs to "see" the Apache CXF classes, because of the check for
org.apache.cxf.endpoint.Client interface. When running JAX-WS applications on WildFly using the
JBossWS integration, the user is not *required* to set a dependency to Apache CXF modules, even if
they're internally used to serve JAX-WS functionalities. For this reason, the service class
classloader, which is a JBoss Module classloader, won't usually allow loading the
org.apache.cxf.endpoint.Client *directly* (that is is by doing
Class.forName("org.apache.cxf.endpoint.Client", true, loader)). For this reason, the
ProxyHelper will go the combined classloader approach.
The problem with such an approach on WildFly / JBoss AS is that later the JDK
Proxy will try to load the interfaces using the ProxyClassloader, whose parent
is the boot classloader. On recent JDK version, the boot classloader is able to
load the JAX-WS api classes (because they're included in the JDK); however, the
javax.xml.ws.BindinProvider interface class that was retrieved from the service
class is a different class, having been loaded by a specific module part of the
service class classloader. This makes a check fail in the JDK Proxy,
effectively preventing creating the jaxws client proxy.
To me, the CXF ProxyClassloader should have an explicit parent classloader set
to the same classloader instance that was provided (the application
classloader, that is the service class classloader). That in turn *might* have
the boot classloader as parent (not in the case of JBoss / WildFly, due to the
modular approach).
If you have nothing against this, I'll create a JIRA and commit the following
patch:
diff --git
a/core/src/main/java/org/apache/cxf/common/util/ProxyClassLoader.java
b/core/src/main/java/org/apache/cxf/common/util/ProxyClassLoader.java
index f7de519..c4baa17 100644
--- a/core/src/main/java/org/apache/cxf/common/util/ProxyClassLoader.java
+++ b/core/src/main/java/org/apache/cxf/common/util/ProxyClassLoader.java
@@ -32,10 +32,12 @@ public class ProxyClassLoader extends ClassLoader {
private final Set<ClassLoader> loaders = new HashSet<ClassLoader>();
private boolean checkSystem;
- public ProxyClassLoader() {
+ public ProxyClassLoader(ClassLoader parent) {
+ super(parent);
classes = null;
}
- public ProxyClassLoader(Class<?>[] cls) {
+ public ProxyClassLoader(ClassLoader parent, Class<?>[] cls) {
+ super(parent);
classes = cls;
}
diff --git a/core/src/main/java/org/apache/cxf/common/util/ProxyHelper.java
b/core/src/main/java/org/apache/cxf/common/util/ProxyHelper.java
index c252574..27f2c56 100644
--- a/core/src/main/java/org/apache/cxf/common/util/ProxyHelper.java
+++ b/core/src/main/java/org/apache/cxf/common/util/ProxyHelper.java
@@ -58,7 +58,7 @@ public class ProxyHelper {
if (canSeeAllInterfaces(loader, interfaces)) {
return loader;
}
- ProxyClassLoader combined = new ProxyClassLoader(interfaces);
+ ProxyClassLoader combined = new ProxyClassLoader(loader, interfaces);
for (Class<?> currentInterface : interfaces) {
combined.addLoader(currentInterface.getClassLoader());
}
Thanks
Alessio
[1]
https://fisheye6.atlassian.com/changelog/cxf?cs=3898dbb3e29202c0d2942fb903fa29a7c16418a7
--
Alessio Soldano
Web Service Lead, JBoss