You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Call to Provider.provider() from javax.xml.ws.Service constructors returns null in Java 11 if osgi-resource-locator is on the classpath. This jar can be on the classpath as a result of a transitive dependency. The cause of the NullPointerException is because the call to isOSGi() from javax.xml.ws.spi.FactoryFinder#find can return true in Java 11 even if the application is not OSGi; whereas in Java 1.8, the call would return false under the same circumstance.
The NullPointerException actually comes as a result of org.glassfish.hk2.osgiresourcelocator.ServiceLoader#lookupProviderInstance returning null to javax.xml.ws.spi.FactoryFinder#lookupUsingOSGiServiceLoader. The reason ServiceLoader#lookupProviderInstance returns null is because the ServiceLoader#initialize method has never been called. The reason the initialize method has never been called is because this is not an OSGi application which would normally load and initialize the bundle.
The lookupUsingOSGiServiceLoader method is invoked because the call to javax.xml.ws.spi.FactoryFinder#isOSGi() returns true. On JDK1.8, isOSGi() returns false. So why does isOSGi() return true? All the method does is check to see if Class.forName("org.glassfish.hk2.osgiresourcelocator.ServiceLoader") throws a ClassNotFoundException. On JDK 11, the exception is not thrown, but it is thrown on JDK 1.8. To understand why, we need to look at what happens in Class.forName.
The first thing Class.forName does is find the class for the caller using Reflection#getCallerClass(). Both 1.8 and 11 return the FactoryFinder class, as expected. Next, it finds the ClassLoader for the caller class using (package-private) ClassLoader#getClassLoader. And here lies the difference. On 1.8, this returns null, which is the bootstrap class loader. On 11, this returns the application class loader.
The reason we get the bootstrap class loader on 1.8 is that the javax.xml.ws package is part of the JDK in 1.8. In Java 9, it was removed (along with other Java EE classes - see JEP 320: Remove the Java EE and CORBA Modules). So, on 11, these classes have to be added to the classpath. This is why when Class.forName gets the class loader for javax.xml.ws.spi.FactoryFinder.class on Java 11, it gets the application class loader. And the lookup of the o.g.h.o.ServiceLoader class succeeds on 11 because osgi-resource-locator-1.0.1.jar is also on the classpath (in this case, due to a transitive dependency).
It is worth noting that the FactoryFinder#find method is coded differently in jaxws-api than it was in JDK 1.8. In Java 11, the method goes through a sequence of checks to find the service provider. First it looks to see if there is a jaxws.properties file in the JRE and uses the properties there. If jaxws.properties is not found, it looks for the system property javax.xml.ws.spi.Provider. Failing that, it checks isOSGi(). If the OSGi check fails it assumes the default of com.sun.xml.internal.ws.spi.ProviderImpl.
The workaround is to set the system property javax.xml.ws.spi.Provider=com.sun.xml.internal.ws.spi.ProviderImpl and add a dependency to jaxws-ri to the project.
Recommended diff is:
`
diff --git a/api/src/main/java/jakarta/xml/ws/spi/FactoryFinder.java b/api/src/main/java/jakarta/xml/ws/spi/FactoryFinder.java
index 4e259d5..7375203 100644
--- a/api/src/main/java/jakarta/xml/ws/spi/FactoryFinder.java
+++ b/api/src/main/java/jakarta/xml/ws/spi/FactoryFinder.java
@@ -71,7 +71,8 @@ class FactoryFinder {
// handling Glassfish (platform specific default)
if (isOsgi()) {
Call to
Provider.provider()
fromjavax.xml.ws.Service
constructors returnsnull
in Java 11 if osgi-resource-locator is on the classpath. This jar can be on the classpath as a result of a transitive dependency. The cause of the NullPointerException is because the call toisOSGi()
from javax.xml.ws.spi.FactoryFinder#find can return true in Java 11 even if the application is not OSGi; whereas in Java 1.8, the call would return false under the same circumstance.The NullPointerException actually comes as a result of org.glassfish.hk2.osgiresourcelocator.ServiceLoader#lookupProviderInstance returning null to javax.xml.ws.spi.FactoryFinder#lookupUsingOSGiServiceLoader. The reason ServiceLoader#lookupProviderInstance returns null is because the ServiceLoader#initialize method has never been called. The reason the initialize method has never been called is because this is not an OSGi application which would normally load and initialize the bundle.
The lookupUsingOSGiServiceLoader method is invoked because the call to javax.xml.ws.spi.FactoryFinder#isOSGi() returns true. On JDK1.8, isOSGi() returns false. So why does isOSGi() return true? All the method does is check to see if Class.forName("org.glassfish.hk2.osgiresourcelocator.ServiceLoader") throws a ClassNotFoundException. On JDK 11, the exception is not thrown, but it is thrown on JDK 1.8. To understand why, we need to look at what happens in Class.forName.
The first thing Class.forName does is find the class for the caller using Reflection#getCallerClass(). Both 1.8 and 11 return the FactoryFinder class, as expected. Next, it finds the ClassLoader for the caller class using (package-private) ClassLoader#getClassLoader. And here lies the difference. On 1.8, this returns null, which is the bootstrap class loader. On 11, this returns the application class loader.
The reason we get the bootstrap class loader on 1.8 is that the javax.xml.ws package is part of the JDK in 1.8. In Java 9, it was removed (along with other Java EE classes - see JEP 320: Remove the Java EE and CORBA Modules). So, on 11, these classes have to be added to the classpath. This is why when Class.forName gets the class loader for javax.xml.ws.spi.FactoryFinder.class on Java 11, it gets the application class loader. And the lookup of the o.g.h.o.ServiceLoader class succeeds on 11 because osgi-resource-locator-1.0.1.jar is also on the classpath (in this case, due to a transitive dependency).
It is worth noting that the FactoryFinder#find method is coded differently in jaxws-api than it was in JDK 1.8. In Java 11, the method goes through a sequence of checks to find the service provider. First it looks to see if there is a jaxws.properties file in the JRE and uses the properties there. If jaxws.properties is not found, it looks for the system property javax.xml.ws.spi.Provider. Failing that, it checks isOSGi(). If the OSGi check fails it assumes the default of com.sun.xml.internal.ws.spi.ProviderImpl.
The workaround is to set the system property javax.xml.ws.spi.Provider=com.sun.xml.internal.ws.spi.ProviderImpl and add a dependency to jaxws-ri to the project.
Recommended diff is:
`
diff --git a/api/src/main/java/jakarta/xml/ws/spi/FactoryFinder.java b/api/src/main/java/jakarta/xml/ws/spi/FactoryFinder.java
index 4e259d5..7375203 100644
--- a/api/src/main/java/jakarta/xml/ws/spi/FactoryFinder.java
+++ b/api/src/main/java/jakarta/xml/ws/spi/FactoryFinder.java
@@ -71,7 +71,8 @@ class FactoryFinder {
`
The text was updated successfully, but these errors were encountered: