Skip to content

Commit 8017fc3

Browse files
authored
Fix ExtensionException in OSGi environment for global extension (#2079)
Implement the same resource logic with ContextClassLoader as JUnit platform. Fixes #2076
1 parent 9d1e819 commit 8017fc3

File tree

4 files changed

+36
-26
lines changed

4 files changed

+36
-26
lines changed

docs/release_notes.adoc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33

44
include::include.adoc[]
55

6-
== 2.4 (tbd)
6+
== 2.4-M6 (tbd)
7+
8+
=== Misc
9+
10+
* Fix ExtensionException in OSGi environment for global extension spockIssue:2076[]
11+
** This issue was introduced with spockPull:1995[]
712

813
== 2.4-M5 (2025-01-07)
914

spock-core/src/main/java/org/spockframework/runtime/ExtensionClassesLoader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public <T> List<Class<? extends T>> loadClasses(String descriptorPath, Class<T>
5656

5757
private Collection<URL> locateDescriptors(String descriptorPath) {
5858
try {
59-
return ReflectionUtil.getResourcesFromClassLoaders(descriptorPath);
59+
return ReflectionUtil.getResourcesFromClassLoader(descriptorPath);
6060
} catch (Exception e) {
6161
throw new ExtensionException("Failed to locate extension descriptors", e);
6262
}

spock-core/src/main/java/org/spockframework/util/ReflectionUtil.java

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -86,30 +86,24 @@ public static Class<?> loadClass(String className) throws ClassNotFoundException
8686
}
8787

8888
/**
89-
* Returns the resources from the following classloaders:
90-
* <ul>
91-
* <li>Spock {@link ClassLoader}</li>
92-
* <li>{@code Thread.currentThread().getContextClassLoader()}</li>
93-
* </ul>
89+
* Returns the resources from the {@code Thread.currentThread().getContextClassLoader()}.
9490
*
9591
* @param resourcePath the path of the resource
9692
* @return the list of resources
9793
* @throws IOException if the resources can't be loaded
9894
*/
99-
public static Collection<URL> getResourcesFromClassLoaders(String resourcePath) throws IOException {
100-
ClassLoader spockClassLoader = ReflectionUtil.class.getClassLoader();
101-
// We need to use a sorted Set here, to filter out duplicates, if the ContextClassLoader can also reach the Spock classloader
102-
TreeSet<URL> set = new TreeSet<>(Comparator.comparing(URL::toString));
103-
set.addAll(Collections.list(spockClassLoader.getResources(resourcePath)));
95+
public static Collection<URL> getResourcesFromClassLoader(String resourcePath) throws IOException {
10496
try {
105-
//Also resolve resources via ContextClassLoader to better support for runtimes like OSGi
97+
//Resolve resources via ContextClassLoader to better support for runtimes like OSGi
98+
//Issue #2076: But du not use ContextClassLoader and the Spock ClassLoader and merge the results, because this fails for bundle resources
10699
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
107-
if (contextClassLoader != null && spockClassLoader != contextClassLoader) {
108-
set.addAll(Collections.list(contextClassLoader.getResources(resourcePath)));
100+
if (contextClassLoader != null) {
101+
return Collections.list(contextClassLoader.getResources(resourcePath));
109102
}
110103
} catch (SecurityException ignored) {
111104
}
112-
return set;
105+
ClassLoader spockClassLoader = ReflectionUtil.class.getClassLoader();
106+
return Collections.list(spockClassLoader.getResources(resourcePath));
113107
}
114108

115109
public static boolean isClassAvailable(String className) {

spock-specs/src/test/groovy/org/spockframework/util/ReflectionUtilSpec.groovy

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,14 @@ class ReflectionUtilSpec extends Specification {
5858
Thread.currentThread().setContextClassLoader(oldLoader)
5959
}
6060

61-
def "getResourcesFromClassLoaders"() {
61+
def getResourcesFromClassLoader() {
6262
when:
63-
def res = ReflectionUtil.getResourcesFromClassLoaders(JarFile.MANIFEST_NAME)
63+
def res = ReflectionUtil.getResourcesFromClassLoader(JarFile.MANIFEST_NAME)
6464
then:
6565
res.size() >= 1
6666
}
6767

68+
@Issue("https://github.com/spockframework/spock/issues/2076")
6869
def "getResourcesFromClassLoaders - ContextClassLoader"() {
6970
given:
7071
def oldLoader = Thread.currentThread().getContextClassLoader()
@@ -74,23 +75,18 @@ class ReflectionUtilSpec extends Specification {
7475
@Override
7576
Enumeration<URL> getResources(String name) throws IOException {
7677
if (name == resPath) {
77-
def url = new URL("file:/" + resPath)
78-
return new Vector([
79-
//Check that we filter out duplicates
80-
url,
81-
url
82-
]).elements()
78+
return new Vector([new URL("file:/" + resPath)]).elements()
8379
}
8480
return super.getResources(name)
8581
}
8682
}
8783

8884
expect:
89-
ReflectionUtil.getResourcesFromClassLoaders(resPath).isEmpty()
85+
ReflectionUtil.getResourcesFromClassLoader(resPath).isEmpty()
9086

9187
when:
9288
Thread.currentThread().setContextClassLoader(resCl)
93-
def res = ReflectionUtil.getResourcesFromClassLoaders(resPath)
89+
def res = ReflectionUtil.getResourcesFromClassLoader(resPath)
9490
then:
9591
res.size() == 1
9692
res[0].toString().contains(resPath)
@@ -99,6 +95,21 @@ class ReflectionUtilSpec extends Specification {
9995
Thread.currentThread().setContextClassLoader(oldLoader)
10096
}
10197

98+
@Issue("https://github.com/spockframework/spock/issues/2076")
99+
def "getResourcesFromClassLoaders - ContextClassLoader == null"() {
100+
given:
101+
def oldLoader = Thread.currentThread().getContextClassLoader()
102+
103+
when:
104+
Thread.currentThread().setContextClassLoader(null)
105+
def res = ReflectionUtil.getResourcesFromClassLoader(JarFile.MANIFEST_NAME)
106+
then:
107+
res.size() >= 1
108+
109+
cleanup:
110+
Thread.currentThread().setContextClassLoader(oldLoader)
111+
}
112+
102113
def "check if class exists"() {
103114
expect:
104115
ReflectionUtil.isClassAvailable("java.util.List")

0 commit comments

Comments
 (0)