Skip to content

Commit 32af350

Browse files
honnixHongxin Liang
andauthored
Only load certain classes from child (#196)
Signed-off-by: Hongxin Liang <[email protected]> Co-authored-by: Hongxin Liang <[email protected]>
1 parent b217cd6 commit 32af350

File tree

2 files changed

+38
-23
lines changed

2 files changed

+38
-23
lines changed

jflyte/src/main/java/org/flyte/jflyte/ChildFirstClassLoader.java

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@
2525
import java.util.Iterator;
2626
import java.util.List;
2727
import java.util.Set;
28-
import java.util.stream.Collectors;
29-
import java.util.stream.Stream;
3028

3129
/**
3230
* {@link URLClassLoader} that loads classes into child class loader, instead of parent.
@@ -42,12 +40,11 @@ class ChildFirstClassLoader extends URLClassLoader {
4240

4341
// we have to load these classes in parent class loader
4442
// it's base shared between all plugins and user code
45-
private static final String[] PARENT_FIRST_PACKAGE_PREFIXES =
46-
new String[] {"org.flyte.api.v1.", "org.flyte.jflyte.api."};
43+
private static final Set<String> PARENT_FIRST_PACKAGE_PREFIXES =
44+
Set.of("org.flyte.api.v1.", "org.flyte.jflyte.api.");
4745

48-
private static final Set<String> CHILD_ONLY_RESOURCE_PREFIXES =
49-
Stream.of("org/slf4j/impl/StaticLoggerBinder.class", "META-INF/services/")
50-
.collect(Collectors.toSet());
46+
private static final Set<String> CHILD_ONLY_PREFIXES =
47+
Set.of("org.slf4j.impl.", "org/slf4j/impl/", "META-INF/services/");
5148

5249
@SuppressWarnings("JdkObsolete")
5350
private static class CustomEnumeration implements Enumeration<URL> {
@@ -79,15 +76,16 @@ protected synchronized Class<?> loadClass(String name, boolean resolve)
7976
@Var Class<?> cls = findLoadedClass(name);
8077

8178
if (cls == null) {
82-
for (String prefix : PARENT_FIRST_PACKAGE_PREFIXES) {
83-
if (name.startsWith(prefix)) {
84-
return super.loadClass(name, resolve);
85-
}
79+
if (parentFirst(name)) {
80+
return super.loadClass(name, resolve);
8681
}
8782

8883
try {
8984
cls = findClass(name);
9085
} catch (ClassNotFoundException e) {
86+
if (childOnly(name)) {
87+
throw e;
88+
}
9189
cls = getParent().loadClass(name);
9290
}
9391
}
@@ -107,10 +105,7 @@ public URL getResource(String name) {
107105
return resource;
108106
}
109107

110-
if (delegateResourceToParent(name)) {
111-
return getParent().getResource(name);
112-
}
113-
return null;
108+
return childOnly(name) ? null : getParent().getResource(name);
114109
}
115110

116111
@Override
@@ -123,7 +118,7 @@ public Enumeration<URL> getResources(String name) throws IOException {
123118
allResources.add(childResources.nextElement());
124119
}
125120

126-
if (delegateResourceToParent(name)) {
121+
if (!childOnly(name)) {
127122
Enumeration<URL> parentResources = getParent().getResources(name);
128123

129124
while (parentResources.hasMoreElements()) {
@@ -134,12 +129,11 @@ public Enumeration<URL> getResources(String name) throws IOException {
134129
return new CustomEnumeration(allResources.iterator());
135130
}
136131

137-
private static boolean delegateResourceToParent(String name) {
138-
for (String resourcePrefix : CHILD_ONLY_RESOURCE_PREFIXES) {
139-
if (name.startsWith(resourcePrefix)) {
140-
return false;
141-
}
142-
}
143-
return true;
132+
private static boolean parentFirst(String name) {
133+
return PARENT_FIRST_PACKAGE_PREFIXES.stream().anyMatch(name::startsWith);
134+
}
135+
136+
private static boolean childOnly(String name) {
137+
return CHILD_ONLY_PREFIXES.stream().anyMatch(name::startsWith);
144138
}
145139
}

jflyte/src/test/java/org/flyte/jflyte/ChildFirstClassLoaderTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static org.junit.jupiter.api.Assertions.assertEquals;
2020
import static org.junit.jupiter.api.Assertions.assertNotNull;
2121
import static org.junit.jupiter.api.Assertions.assertNull;
22+
import static org.junit.jupiter.api.Assertions.assertThrows;
2223

2324
import java.io.IOException;
2425
import java.net.URL;
@@ -70,6 +71,16 @@ void testGetResourceFromChild() throws IOException {
7071
}
7172
}
7273

74+
@Test
75+
void testLoadClassFromChild() throws IOException {
76+
try (URLClassLoader classLoader =
77+
new ChildFirstClassLoader(new URL[] {urlVisibleToChildOnly()})) {
78+
// The class file used by the test case is empty, so we expect ClassFormatError
79+
assertThrows(
80+
ClassFormatError.class, () -> classLoader.loadClass("org.slf4j.impl.StaticLoggerBinder"));
81+
}
82+
}
83+
7384
@Test
7485
void testGetResourceNotFound() throws IOException {
7586
try (URLClassLoader classLoader =
@@ -80,6 +91,16 @@ void testGetResourceNotFound() throws IOException {
8091
}
8192
}
8293

94+
@Test
95+
void testLoadClassNotFound() throws IOException {
96+
try (URLClassLoader classLoader =
97+
new ChildFirstClassLoader(new URL[] {urlVisibleToBothChildAndParent()})) {
98+
assertThrows(
99+
ClassNotFoundException.class,
100+
() -> classLoader.loadClass("org.slf4j.impl.StaticLoggerBinder"));
101+
}
102+
}
103+
83104
private String thisClassAsResourceName() {
84105
return getClass().getName().replace(".", "/") + ".class";
85106
}

0 commit comments

Comments
 (0)