17
17
import java .util .Collection ;
18
18
import java .util .Collections ;
19
19
import java .util .Enumeration ;
20
+ import java .util .HashSet ;
20
21
import java .util .LinkedHashSet ;
21
22
import java .util .List ;
22
23
import java .util .Map ;
25
26
import java .util .StringJoiner ;
26
27
import java .util .TreeMap ;
27
28
import java .util .function .Predicate ;
29
+ import java .util .jar .Attributes ;
28
30
import java .util .jar .JarEntry ;
29
31
import java .util .jar .JarFile ;
32
+ import java .util .jar .Manifest ;
30
33
import java .util .stream .Collectors ;
31
34
32
35
public final class ClassPathConfigSource extends FilteredPathConfigSource {
36
+
33
37
private static final String CLASSPATH = System .getProperty ("java.class.path" );
34
38
private static final String PATH_SEPARATOR = System .getProperty ("path.separator" );
39
+ private static final String CLASSPATH_ATTIBUTE_MANIFEST_SEPARATOR = " " ;
35
40
36
41
private Map <String , ConfigProperty > loadedConfig ;
37
42
@@ -79,16 +84,19 @@ public Map<String, ConfigProperty> loadConfig() {
79
84
.forEach (
80
85
uri -> {
81
86
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 );
91
97
}
98
+ } catch (Exception e ) {
99
+ throw ThrowableUtil .propagate (e );
92
100
}
93
101
});
94
102
@@ -150,7 +158,7 @@ private static Collection<URL> parseJavaClassPath() {
150
158
try {
151
159
urls .add (new File (entry ).toURI ().toURL ());
152
160
} catch (SecurityException e ) {
153
- urls . add ( new URL ( "file" , null , new File ( entry ). getAbsolutePath ()) );
161
+ throw ThrowableUtil . propagate ( e );
154
162
}
155
163
} catch (MalformedURLException ex ) {
156
164
throw ThrowableUtil .propagate (ex );
@@ -160,48 +168,96 @@ private static Collection<URL> parseJavaClassPath() {
160
168
}
161
169
162
170
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 )
164
172
throws IOException {
165
- File canonical = directory .getCanonicalFile ();
166
- if (ancestors .contains (canonical )) {
167
- return ;
168
- }
173
+
169
174
File [] files = directory .listFiles ();
170
175
if (files == null ) {
171
176
return ;
172
177
}
173
- Set <File > objects = new LinkedHashSet <>(ancestors );
174
- objects .add (canonical );
175
- Set <File > newAncestors = Collections .unmodifiableSet (objects );
178
+
176
179
for (File f : files ) {
177
180
String name = f .getName ();
178
181
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
+ }
180
187
} else {
181
- collector .add (f .toPath ());
188
+ String resourceName = prefix + name ;
189
+ if (!resourceName .equals (JarFile .MANIFEST_NAME )) {
190
+ collector .add (f .toPath ());
191
+ }
182
192
}
183
193
}
184
194
}
185
195
186
196
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 );
192
204
}
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 ();
195
211
while (entries .hasMoreElements ()) {
196
212
JarEntry entry = entries .nextElement ();
213
+ if (entry .isDirectory () || entry .getName ().equals (JarFile .MANIFEST_NAME )) {
214
+ continue ;
215
+ }
197
216
collector .add (zipfs .getPath (entry .getName ()));
198
217
}
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 ;
200
236
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 );
204
240
}
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 );
205
261
}
206
262
}
207
263
0 commit comments