Skip to content

Commit 364ae22

Browse files
committed
Refactored ClassFinder to improve null handling, normalize class names, and support multiple resources; adjusted InjectionContext to use an effective class loader
1 parent 5d57e2e commit 364ae22

File tree

2 files changed

+53
-30
lines changed

2 files changed

+53
-30
lines changed

dependencyInjection/src/main/java/cat/michal/catbase/injector/ClassFinder.java

Lines changed: 51 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,25 @@
33
import java.io.*;
44
import java.net.JarURLConnection;
55
import java.net.URL;
6+
import java.net.URISyntaxException;
67
import java.util.*;
78
import java.util.jar.JarEntry;
89
import java.util.jar.JarFile;
910
import java.util.stream.Collectors;
1011

1112
public class ClassFinder {
1213
private final ClassLoader classLoader;
13-
private final Collection<String> excludedEntries;
14+
private final Set<String> excludedEntries;
1415

15-
ClassFinder(Collection<String> excludedEntries, ClassLoader classLoader) {
16+
public ClassFinder(Collection<String> excludedEntries, ClassLoader classLoader) {
1617
this.classLoader = classLoader;
17-
this.excludedEntries = excludedEntries;
18+
this.excludedEntries = excludedEntries == null ? Collections.emptySet() : excludedEntries.stream()
19+
.filter(Objects::nonNull)
20+
.map(ClassFinder::normalizeName)
21+
.collect(Collectors.toCollection(LinkedHashSet::new));
1822
}
1923

20-
ClassFinder() {
24+
public ClassFinder() {
2125
this(Collections.emptyList(), ClassLoader.getSystemClassLoader());
2226
}
2327

@@ -31,43 +35,52 @@ public List<Class<?>> findAllClasses(String packageName) {
3135

3236
public List<String> findAllClassesPaths(String packageName) {
3337
String path = packageName.replace('.', '/');
34-
URL resource = classLoader.getResource(path);
35-
List<String> classes = new ArrayList<>();
36-
37-
if (resource == null) {
38-
return classes;
39-
}
38+
Set<String> classes = new LinkedHashSet<>();
4039

4140
try {
42-
if ("jar".equals(resource.getProtocol())) {
43-
JarURLConnection conn = (JarURLConnection) resource.openConnection();
44-
try (JarFile jar = conn.getJarFile()) {
45-
Enumeration<JarEntry> entries = jar.entries();
46-
while (entries.hasMoreElements()) {
47-
JarEntry entry = entries.nextElement();
48-
if (entry.getName().startsWith(path + "/") && entry.getName().endsWith(".class")) {
49-
String className = entry.getName().replace('/', '.').replaceAll("\\.class$", "");
50-
classes.add(className);
41+
Enumeration<URL> resources = classLoader.getResources(path);
42+
while (resources.hasMoreElements()) {
43+
URL resource = resources.nextElement();
44+
String protocol = resource.getProtocol();
45+
if ("jar".equals(protocol)) {
46+
JarURLConnection conn = (JarURLConnection) resource.openConnection();
47+
try (JarFile jar = conn.getJarFile()) {
48+
Enumeration<JarEntry> entries = jar.entries();
49+
while (entries.hasMoreElements()) {
50+
JarEntry entry = entries.nextElement();
51+
String name = entry.getName();
52+
if (name.startsWith(path + "/") && name.endsWith(".class") && !name.contains("$")) {
53+
String className = normalizeName(name);
54+
classes.add(className);
55+
}
5156
}
5257
}
58+
} else if ("file".equals(protocol)) {
59+
File dir;
60+
try {
61+
dir = new File(resource.toURI());
62+
} catch (URISyntaxException e) {
63+
dir = new File(resource.getPath());
64+
}
65+
scanDirectory(packageName, dir, classes);
5366
}
54-
} else if ("file".equals(resource.getProtocol())) {
55-
File dir = new File(resource.getFile());
56-
scanDirectory(packageName, dir, classes);
5767
}
5868
} catch (IOException e) {
5969
e.printStackTrace();
6070
}
6171

62-
return classes;
72+
classes.removeIf(excludedEntries::contains);
73+
return new ArrayList<>(classes);
6374
}
6475

65-
private void scanDirectory(String packageName, File dir, List<String> classes) {
66-
if (!dir.exists()) return;
67-
for (File file : Objects.requireNonNull(dir.listFiles())) {
76+
private void scanDirectory(String packageName, File dir, Collection<String> classes) {
77+
if (dir == null || !dir.exists()) return;
78+
File[] files = dir.listFiles();
79+
if (files == null) return;
80+
for (File file : files) {
6881
if (file.isDirectory()) {
6982
scanDirectory(packageName + (packageName.isEmpty() ? "" : ".") + file.getName(), file, classes);
70-
} else if (file.getName().endsWith(".class")) {
83+
} else if (file.getName().endsWith(".class") && !file.getName().contains("$")) {
7184
String className = packageName + (packageName.isEmpty() ? "" : ".") + file.getName().replaceAll("\\.class$", "");
7285
classes.add(className);
7386
}
@@ -76,9 +89,18 @@ private void scanDirectory(String packageName, File dir, List<String> classes) {
7689

7790
private Class<?> getClass(String className) {
7891
try {
79-
return Class.forName(className.substring(0, className.lastIndexOf('.')));
80-
} catch (ClassNotFoundException ignored) {
92+
return classLoader.loadClass(className);
93+
} catch (Throwable ignored) {
8194
}
8295
return null;
8396
}
97+
98+
private static String normalizeName(String name) {
99+
if (name == null) return null;
100+
String normalized = name.replace('/', '.');
101+
if (normalized.endsWith(".class")) {
102+
normalized = normalized.substring(0, normalized.length() - 6);
103+
}
104+
return normalized;
105+
}
84106
}

dependencyInjection/src/main/java/cat/michal/catbase/injector/InjectionContext.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ public class InjectionContext {
1414
public InjectionContext(Collection<String> packagePaths, Collection<String> excludedEntries, ClassLoader classLoader) {
1515
this.classes = new ArrayList<>();
1616
this.dependencies = new ArrayList<>();
17-
ClassFinder classFinder = classLoader == null ? new ClassFinder() : new ClassFinder(excludedEntries, classLoader);
17+
ClassLoader effectiveClassLoader = classLoader != null ? classLoader : Thread.currentThread().getContextClassLoader();
18+
ClassFinder classFinder = new ClassFinder(excludedEntries, effectiveClassLoader);
1819

1920
packagePaths.forEach(packagePath -> this.classes.addAll(classFinder.findAllClasses(packagePath)));
2021
}

0 commit comments

Comments
 (0)