Skip to content

Commit 6b89248

Browse files
vaadin-botArtur-
andauthored
fix: Use context class loader for class finder (#16063) (#16066)
* fix: Use context class loader for class finder Fixes vaadin/hilla#791 * test Co-authored-by: Artur <artur@vaadin.com>
1 parent 070278c commit 6b89248

2 files changed

Lines changed: 56 additions & 3 deletions

File tree

flow-server/src/main/java/com/vaadin/flow/server/frontend/scanner/ClassFinder.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,15 @@ public DefaultClassFinder(Set<Class<?>> classes) {
6262
classList.sort(
6363
(cls1, cls2) -> cls1.getName().compareTo(cls2.getName()));
6464
this.classes = new LinkedHashSet<>(classList);
65-
// take classLoader from the first class in the set, unless empty
66-
classLoader = classes.isEmpty() ? getClass().getClassLoader()
67-
: classes.iterator().next().getClassLoader();
65+
66+
// The classes might be loaded with different class loaders, e.g app
67+
// class
68+
// loader and restart class loader in Spring Boot applications. If
69+
// we pick one
70+
// of them and pick the parent, then it won't find classes and
71+
// resources loaded
72+
// by the child loader.
73+
classLoader = Thread.currentThread().getContextClassLoader();
6874
}
6975

7076
/**

flow-server/src/test/java/com/vaadin/flow/server/frontend/scanner/ClassFinderTest.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.vaadin.flow.server.frontend.scanner;
22

3+
import java.io.IOException;
34
import java.util.ArrayList;
45
import java.util.Arrays;
56
import java.util.Collections;
@@ -8,6 +9,7 @@
89
import java.util.List;
910
import java.util.Set;
1011

12+
import org.apache.commons.io.IOUtils;
1113
import org.junit.Assert;
1214
import org.junit.Rule;
1315
import org.junit.Test;
@@ -22,6 +24,27 @@ public class ClassFinderTest {
2224
@Rule
2325
public ExpectedException exception = ExpectedException.none();
2426

27+
private final class FakeClassLoader extends ClassLoader {
28+
private final ClassLoader realClassLoader;
29+
30+
private FakeClassLoader(ClassLoader realClassLoader) {
31+
super(null);
32+
this.realClassLoader = realClassLoader;
33+
}
34+
35+
protected Class<?> findClass(String name)
36+
throws ClassNotFoundException {
37+
try {
38+
byte[] bytes = IOUtils
39+
.toByteArray(realClassLoader.getResourceAsStream(
40+
name.replace(".", "/") + ".class"));
41+
return defineClass(name, bytes, 0, bytes.length);
42+
} catch (IOException e) {
43+
throw new ClassNotFoundException("Failed", e);
44+
}
45+
}
46+
}
47+
2548
private static class TestList extends ArrayList<String> {
2649

2750
}
@@ -91,4 +114,28 @@ public void orderIsDeterministic() {
91114
expected.add(NodeTestComponents.VaadinBowerComponent.class);
92115
Assert.assertEquals(expected, allClasses);
93116
}
117+
118+
public static class TestClass1 {
119+
120+
}
121+
122+
@Test
123+
public void defaultsToContextClassLoader() throws Exception {
124+
ClassLoader contextClassLoader = Thread.currentThread()
125+
.getContextClassLoader();
126+
127+
ClassLoader loader1 = new FakeClassLoader(contextClassLoader);
128+
ClassLoader loader2 = new FakeClassLoader(contextClassLoader);
129+
Class<?> cls1 = loader1.loadClass(
130+
"com.vaadin.flow.server.frontend.scanner.ClassFinderTest$TestClass1");
131+
Class<?> cls2 = loader2.loadClass(
132+
"com.vaadin.flow.server.frontend.scanner.ClassFinderTest$TestClass1");
133+
134+
Assert.assertEquals(loader1, cls1.getClassLoader());
135+
Assert.assertEquals(loader2, cls2.getClassLoader());
136+
137+
DefaultClassFinder finder = new DefaultClassFinder(Set.of(cls1, cls2));
138+
Assert.assertEquals(contextClassLoader, finder.getClassLoader());
139+
}
140+
94141
}

0 commit comments

Comments
 (0)