-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
Overview
Although current use of ClassLoaderUtils.getDefaultClassLoader() works for the most common class loading scenarios, it is not always appropriate to default to using the thread context ClassLoader (TCCL) when loading user types via reflection.
This issue is inspired by the issues discussed in #805 and serves as an umbrella issue for potential class loading issues across the platform.
Related Issues
- Introduce extension API for providing a custom ClassLoader (e.g., for Powermock) #201
- TestEngines not found by ServiceLoader on Java 9 #805
Comparison to class loading in Spring
If we take inspiration from the Spring Framework, we can see that org.springframework.util.ClassUtils.forName(String, ClassLoader) accepts a user-supplied ClassLoader and falls back to the "default ClassLoader" only if the supplied ClassLoader is null. For loading services, Spring does not use Java's ServiceLoader mechanism but rather its own SpringFactoriesLoader which performs the same task as Java's ServiceLoader but with explicit control over which ClassLoader is used. Note that SpringFactoriesLoader delegates to org.springframework.util.ClassUtils.forName(String, ClassLoader) to actually load the service class.
Initial Analysis
JUnit does not necessarily need the flexibility of SpringFactoriesLoader, but for certain scenarios we will likely have to supply a custom ClassLoader instead of relying on the "default ClassLoader" which currently is typically the thread context ClassLoader (TCCL).
Supplying getClass().getClassLoader() is likely a viable option. However, we should not change the implementation of ClassLoaderUtils.getDefaultClassLoader(). Rather, we should simply use it less often and then only as a fallback.
FWIW, we actually did have the foresight to create org.junit.platform.commons.util.ReflectionUtils.loadClass(String, ClassLoader), but... we never supply it anything other than the default ClassLoader. 😉
Use Cases to Investigate
The following use cases should be investigated to determine how best to look up the ClassLoader to use.
TestEngineloading inServiceLoaderTestEngineRegistryTestExecutionListenerloading inServiceLoaderTestExecutionListenerRegistry- Jupiter
Extensionloading inExtensionRegistry#registerAutoDetectedExtensions - Additional classpath entries in
ConsoleTestExecutor#createCustomClassLoader ClasspathScannerconfiguration/instantiation inReflectionUtilsReflectionUtils#loadClass(String)
Deliverables
- For each of the aforementioned Use Cases to Investigate, determine how best to look up the
ClassLoader. - Use the
ClassLoaderfor the current framework class (e.g., viagetClass().getClassLoader()) instead ofClassLoaderUtils.getDefaultClassLoader()where appropriate. - Ensure that tools have the ability to set the thread context
ClassLoader(TCCL) where necessary.