1717import java .util .Collection ;
1818import java .util .Collections ;
1919import java .util .Enumeration ;
20+ import java .util .HashSet ;
2021import java .util .LinkedHashSet ;
2122import java .util .List ;
2223import java .util .Map ;
2526import java .util .StringJoiner ;
2627import java .util .TreeMap ;
2728import java .util .function .Predicate ;
29+ import java .util .jar .Attributes ;
2830import java .util .jar .JarEntry ;
2931import java .util .jar .JarFile ;
32+ import java .util .jar .Manifest ;
3033import java .util .stream .Collectors ;
3134
3235public final class ClassPathConfigSource extends FilteredPathConfigSource {
36+
3337 private static final String CLASSPATH = System .getProperty ("java.class.path" );
3438 private static final String PATH_SEPARATOR = System .getProperty ("path.separator" );
39+ private static final String CLASSPATH_ATTIBUTE_MANIFEST_SEPARATOR = " " ;
3540
3641 private Map <String , ConfigProperty > loadedConfig ;
3742
@@ -79,16 +84,19 @@ public Map<String, ConfigProperty> loadConfig() {
7984 .forEach (
8085 uri -> {
8186 File file = new File (uri );
82- if (file .exists ()) {
83- try {
84- if (file .isDirectory ()) {
85- scanDirectory (file , "" , Collections .emptySet (), pathCollection );
86- } else {
87- scanJar (file , pathCollection );
88- }
89- } catch (Exception e ) {
90- throw ThrowableUtil .propagate (e );
87+ if (!file .exists ()) {
88+ return ;
89+ }
90+ try {
91+ if (file .isDirectory ()) {
92+ Set <File > currentPath =
93+ new HashSet <>(Collections .singleton (file .getCanonicalFile ()));
94+ scanDirectory (file , "" , currentPath , pathCollection );
95+ } else {
96+ scanJar (file , pathCollection );
9197 }
98+ } catch (Exception e ) {
99+ throw ThrowableUtil .propagate (e );
92100 }
93101 });
94102
@@ -150,7 +158,7 @@ private static Collection<URL> parseJavaClassPath() {
150158 try {
151159 urls .add (new File (entry ).toURI ().toURL ());
152160 } catch (SecurityException e ) {
153- urls . add ( new URL ( "file" , null , new File ( entry ). getAbsolutePath ()) );
161+ throw ThrowableUtil . propagate ( e );
154162 }
155163 } catch (MalformedURLException ex ) {
156164 throw ThrowableUtil .propagate (ex );
@@ -160,48 +168,96 @@ private static Collection<URL> parseJavaClassPath() {
160168 }
161169
162170 private static void scanDirectory (
163- File directory , String prefix , Set <File > ancestors , Collection <Path > collector )
171+ File directory , String prefix , Set <File > currentPath , Collection <Path > collector )
164172 throws IOException {
165- File canonical = directory .getCanonicalFile ();
166- if (ancestors .contains (canonical )) {
167- return ;
168- }
173+
169174 File [] files = directory .listFiles ();
170175 if (files == null ) {
171176 return ;
172177 }
173- Set <File > objects = new LinkedHashSet <>(ancestors );
174- objects .add (canonical );
175- Set <File > newAncestors = Collections .unmodifiableSet (objects );
178+
176179 for (File f : files ) {
177180 String name = f .getName ();
178181 if (f .isDirectory ()) {
179- scanDirectory (f , prefix + name + "/" , newAncestors , collector );
182+ File deref = f .getCanonicalFile ();
183+ if (currentPath .add (deref )) {
184+ scanDirectory (deref , prefix + name + "/" , currentPath , collector );
185+ currentPath .remove (deref );
186+ }
180187 } else {
181- collector .add (f .toPath ());
188+ String resourceName = prefix + name ;
189+ if (!resourceName .equals (JarFile .MANIFEST_NAME )) {
190+ collector .add (f .toPath ());
191+ }
182192 }
183193 }
184194 }
185195
186196 private static void scanJar (File file , Collection <Path > collector ) throws IOException {
187- JarFile jarFile ;
188- try {
189- jarFile = new JarFile (file );
190- } catch (IOException ignore ) {
191- return ;
197+ try (JarFile jarFile = new JarFile (file )) {
198+ for (File path : getClassPathFromManifest (file , jarFile .getManifest ())) {
199+ if (collector .add (path .getCanonicalFile ().toPath ())) {
200+ scanFrom (path , collector );
201+ }
202+ }
203+ scanJarFile (jarFile , file .toPath (), collector );
192204 }
193- try (FileSystem zipfs = FileSystems .newFileSystem (file .toPath (), null )) {
194- Enumeration <JarEntry > entries = jarFile .entries ();
205+ }
206+
207+ private static void scanJarFile (JarFile file , Path path , Collection <Path > collector )
208+ throws IOException {
209+ try (FileSystem zipfs = FileSystems .newFileSystem (path , null )) {
210+ Enumeration <JarEntry > entries = file .entries ();
195211 while (entries .hasMoreElements ()) {
196212 JarEntry entry = entries .nextElement ();
213+ if (entry .isDirectory () || entry .getName ().equals (JarFile .MANIFEST_NAME )) {
214+ continue ;
215+ }
197216 collector .add (zipfs .getPath (entry .getName ()));
198217 }
199- } finally {
218+ }
219+ }
220+
221+ private static Set <File > getClassPathFromManifest (File jarFile , Manifest manifest ) {
222+ Set <File > result = new LinkedHashSet <>();
223+
224+ if (manifest == null ) {
225+ return result ;
226+ }
227+
228+ String classpathAttribute =
229+ manifest .getMainAttributes ().getValue (Attributes .Name .CLASS_PATH .toString ());
230+ if (classpathAttribute == null ) {
231+ return result ;
232+ }
233+
234+ for (String path : classpathAttribute .split (CLASSPATH_ATTIBUTE_MANIFEST_SEPARATOR )) {
235+ URL url ;
200236 try {
201- jarFile .close ( );
202- } catch (IOException ignore ) {
203- // ignore
237+ url = new URL ( jarFile .toURI (). toURL (), path );
238+ } catch (MalformedURLException e ) {
239+ throw ThrowableUtil . propagate ( e );
204240 }
241+ if (url .getProtocol ().equals ("file" )) {
242+ result .add (toFile (url ));
243+ }
244+ }
245+ return result ;
246+ }
247+
248+ private static void scanFrom (File file , Collection <Path > collector ) throws IOException {
249+ try {
250+ if (!file .exists ()) {
251+ return ;
252+ }
253+ } catch (SecurityException e ) {
254+ throw ThrowableUtil .propagate (e );
255+ }
256+ if (file .isDirectory ()) {
257+ Set <File > currentPath = new HashSet <>(Collections .singleton (file .getCanonicalFile ()));
258+ scanDirectory (file , "" , currentPath , collector );
259+ } else {
260+ scanJar (file , collector );
205261 }
206262 }
207263
0 commit comments