cxf-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Alessio Soldano <asold...@redhat.com>
Subject JAXWS client proxy classloading with CXF 3.0
Date Wed, 02 Apr 2014 12:00:10 GMT
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


Mime
View raw message