diff --git a/api/src/main/java/jakarta/mail/Session.java b/api/src/main/java/jakarta/mail/Session.java index c1476a66..bdcddcc0 100644 --- a/api/src/main/java/jakarta/mail/Session.java +++ b/api/src/main/java/jakarta/mail/Session.java @@ -36,6 +36,7 @@ import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Hashtable; @@ -1384,30 +1385,47 @@ EventQueue getEventQueue() { return q; } - private static final String OSGI_SERVICE_LOADER_CLASS_NAME = "org.glassfish.hk2.osgiresourcelocator.ServiceLoader"; - - @SuppressWarnings({"unchecked"}) - private Iterator lookupUsingHk2ServiceLoader(Class factoryId, ClassLoader loader) { - Class target; - try { - target = Class.forName(OSGI_SERVICE_LOADER_CLASS_NAME, false, loader); - } catch (ClassNotFoundException ignored) { - return Collections.emptyIterator(); + private static Class[] getHk2ServiceLoaderTargets(Class factoryClass) { + ClassLoader[] loaders = new ClassLoader[]{ + Thread.currentThread().getContextClassLoader(), + factoryClass.getClassLoader(), + ClassLoader.getSystemClassLoader()}; + + Class[] classes = new Class[loaders.length]; + int w = 0; + for (ClassLoader loader : loaders) { + if (loader != null) { + try { + classes[w++] = Class.forName("org.glassfish.hk2.osgiresourcelocator.ServiceLoader", false, loader); + } catch (ClassNotFoundException | LinkageError ignored) { + } + } } - try { - // Use reflection to avoid having any dependency on HK2 ServiceLoader class - Class serviceClass = Class.forName(factoryId.getName(), false, loader); - Class[] args = new Class[]{serviceClass}; - Method m = target.getMethod("lookupProviderInstances", Class.class); - Iterable result = ((Iterable) m.invoke(null, (Object[]) args)); - return result != null ? result.iterator() : Collections.emptyIterator(); - } catch (Exception ignored) { - // log and continue - return Collections.emptyIterator(); + if (classes.length != w) { + classes = Arrays.copyOf(classes, w); } + return classes; } + @SuppressWarnings({"unchecked"}) + private Iterator lookupUsingHk2ServiceLoader(Class factoryId, ClassLoader loader) { + for (Class target : getHk2ServiceLoaderTargets(factoryId)) { + try { + // Use reflection to avoid having any dependency on HK2 ServiceLoader class + Class serviceClass = Class.forName(factoryId.getName(), false, loader); + Class[] args = new Class[]{serviceClass}; + Method m = target.getMethod("lookupProviderInstances", Class.class); + Iterable result = ((Iterable) m.invoke(null, (Object[]) args)); + if (result != null) { + return result.iterator(); + } + } catch (Exception ignored) { + // log and continue + } + } + return Collections.emptyIterator(); + } } /** diff --git a/api/src/main/java/jakarta/mail/util/FactoryFinder.java b/api/src/main/java/jakarta/mail/util/FactoryFinder.java index 838f503d..05658463 100644 --- a/api/src/main/java/jakarta/mail/util/FactoryFinder.java +++ b/api/src/main/java/jakarta/mail/util/FactoryFinder.java @@ -17,6 +17,7 @@ package jakarta.mail.util; import java.lang.reflect.Method; +import java.util.Arrays; import java.util.Iterator; import java.util.ServiceLoader; @@ -34,16 +35,24 @@ class FactoryFinder { */ static T find(Class factoryClass) throws RuntimeException { T result; - result = find(factoryClass, Thread.currentThread().getContextClassLoader()); - if (result != null) { - return result; + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + if (loader != null) { + result = find(factoryClass, loader); + if (result != null) { + return result; + } } - result = find(factoryClass, factoryClass.getClassLoader()); - if (result != null) { - return result; + //JakartaMail API ClassLoader / caller classloader + loader = factoryClass.getClassLoader(); + if (loader != null) { + result = find(factoryClass, loader); + if (result != null) { + return result; + } } + //Fallback to system class loader result = find(factoryClass, ClassLoader.getSystemClassLoader()); if (result != null) { return result; @@ -53,10 +62,8 @@ static T find(Class factoryClass) throws RuntimeException { } private static T find(Class factoryClass, ClassLoader loader) throws RuntimeException { - String factoryId = factoryClass.getName(); - // Use the system property first - String className = fromSystemProperty(factoryId); + String className = fromSystemProperty(factoryClass.getName()); if (className != null) { T result = newInstance(className, factoryClass, loader); if (result != null) { @@ -72,7 +79,7 @@ private static T find(Class factoryClass, ClassLoader loader) throws Runt // handling Glassfish/OSGi (platform specific default) - T result = lookupUsingHk2ServiceLoader(factoryId, factoryClass, loader); + T result = lookupUsingHk2ServiceLoader(factoryClass, loader); if (result != null) { return result; } @@ -80,16 +87,14 @@ private static T find(Class factoryClass, ClassLoader loader) throws Runt return null; } - @SuppressWarnings({"unchecked"}) private static T newInstance(String className, Class factoryClass, ClassLoader classLoader) throws RuntimeException { checkPackageAccess(className); try { - Class clazz; - if (classLoader == null) { - clazz = (Class) Class.forName(className); - } else { - clazz = (Class) Class.forName(className, false, classLoader); + Class clazz; + if (classLoader == null) { //Match behavior of ServiceLoader + classLoader = ClassLoader.getSystemClassLoader(); } + clazz = Class.forName(className, false, classLoader); return clazz.asSubclass(factoryClass).getConstructor().newInstance(); } catch (ClassCastException wrongLoader) { return null; @@ -102,41 +107,59 @@ private static String fromSystemProperty(String factoryId) { String systemProp = System.getProperty(factoryId); return systemProp; } - - private static final String OSGI_SERVICE_LOADER_CLASS_NAME = "org.glassfish.hk2.osgiresourcelocator.ServiceLoader"; - - @SuppressWarnings({"unchecked"}) - private static T lookupUsingHk2ServiceLoader(String factoryId, Class factoryClass, ClassLoader loader) { - Class target; - try { - target = Class.forName(OSGI_SERVICE_LOADER_CLASS_NAME, false, loader); - } catch (ClassNotFoundException ignored) { - return null; + + private static Class[] getHk2ServiceLoaderTargets(Class factoryClass) { + ClassLoader[] loaders = new ClassLoader[]{ + Thread.currentThread().getContextClassLoader(), + factoryClass.getClassLoader(), + ClassLoader.getSystemClassLoader()}; + + Class[] classes = new Class[loaders.length]; + int w = 0; + for (ClassLoader loader : loaders) { + if (loader != null) { + try { + classes[w++] = Class.forName("org.glassfish.hk2.osgiresourcelocator.ServiceLoader", false, loader); + } catch (ClassNotFoundException | LinkageError ignored) { + } + } + } + + if (classes.length != w) { + classes = Arrays.copyOf(classes, w); } + return classes; + } - try { - // Use reflection to avoid having any dependency on HK2 ServiceLoader class - Class serviceClass = Class.forName(factoryId, false, loader); - Class[] args = new Class[]{serviceClass}; - Method m = target.getMethod("lookupProviderInstances", Class.class); - Iterable iterable = ((Iterable) m.invoke(null, (Object[]) args)); - if (iterable == null) { - return null; + @SuppressWarnings({"unchecked"}) + private static T lookupUsingHk2ServiceLoader(Class factoryClass, ClassLoader loader) { + for (Class target : getHk2ServiceLoaderTargets(factoryClass)) { + try { + // Use reflection to avoid having any dependency on HK2 ServiceLoader class + Class serviceClass = Class.forName(factoryClass.getName(), false, loader); + Class[] args = new Class[]{serviceClass}; + Method m = target.getMethod("lookupProviderInstances", Class.class); + Iterable iterable = ((Iterable) m.invoke(null, (Object[]) args)); + if (iterable != null) { + Iterator iter = iterable.iterator(); + if (iter.hasNext()) { + return factoryClass.cast(iter.next()); //Verify classloader. + } + } + } catch (Exception ignored) { + // log and continue } - Iterator iter = iterable.iterator(); - return iter.hasNext() ? factoryClass.cast(iter.next()) : null; - } catch (Exception ignored) { - // log and continue - return null; } + return null; } private static T factoryFromServiceLoader(Class factory, ClassLoader loader) { + //ClassLoader of null is treated as system classloader try { ServiceLoader sl = ServiceLoader.load(factory, loader); Iterator iter = sl.iterator(); if (iter.hasNext()) { - return factory.cast(iter.next()); + return factory.cast(iter.next()); //Verify loader } else { return null; }