For the records: https://issues.apache.org/jira/browse/CXF-5668
On 02/04/14 16:23, Alessio Soldano wrote:
Thanks,
will do soon.
On 02/04/14 16:17, Daniel Kulp wrote:
That seems reasonable to me. Feel free to apply it.
Dan
On Apr 2, 2014, at 8:00 AM, Alessio Soldano <[email protected]> wrote:
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
--
Alessio Soldano
Web Service Lead, JBoss