You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cxf.apache.org by Alessio Soldano <as...@redhat.com> on 2014/04/02 14:00:10 UTC

JAXWS client proxy classloading with CXF 3.0

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


Re: JAXWS client proxy classloading with CXF 3.0

Posted by Alessio Soldano <as...@redhat.com>.
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 <as...@redhat.com> 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


Re: JAXWS client proxy classloading with CXF 3.0

Posted by Alessio Soldano <as...@redhat.com>.
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 <as...@redhat.com> 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


Re: JAXWS client proxy classloading with CXF 3.0

Posted by Daniel Kulp <dk...@apache.org>.

That seems reasonable to me.   Feel free to apply it.


Dan


On Apr 2, 2014, at 8:00 AM, Alessio Soldano <as...@redhat.com> 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
> 

-- 
Daniel Kulp
dkulp@apache.org - http://dankulp.com/blog
Talend Community Coder - http://coders.talend.com