33import java .io .*;
44import java .net .JarURLConnection ;
55import java .net .URL ;
6+ import java .net .URISyntaxException ;
67import java .util .*;
78import java .util .jar .JarEntry ;
89import java .util .jar .JarFile ;
910import java .util .stream .Collectors ;
1011
1112public 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}
0 commit comments