0
# Resources and Classpath
1
2
ClassGraph provides comprehensive support for discovering, accessing, and managing resources and classpath elements. This includes files in JARs, directories, modules, and various classpath configurations.
3
4
## Resource Discovery and Access
5
6
```java { .api }
7
import io.github.classgraph.Resource;
8
import io.github.classgraph.ResourceList;
9
import java.io.InputStream;
10
import java.nio.ByteBuffer;
11
import java.nio.charset.StandardCharsets;
12
import java.util.Map;
13
import java.util.regex.Pattern;
14
import java.util.Properties;
15
```
16
17
### Basic Resource Operations
18
19
```java { .api }
20
try (ScanResult scanResult = new ClassGraph().acceptPaths("META-INF", "config").scan()) {
21
// Get all resources found during scan
22
ResourceList allResources = scanResult.getAllResources();
23
24
// Get resources as a map (path -> ResourceList)
25
Map<String, ResourceList> resourceMap = scanResult.getAllResourcesAsMap();
26
27
// Find resources by exact path
28
ResourceList springFactories = scanResult.getResourcesWithPath("META-INF/spring.factories");
29
30
// Find resources ignoring accept/reject filters
31
ResourceList allSpringFactories = scanResult.getResourcesWithPathIgnoringAccept("META-INF/spring.factories");
32
}
33
```
34
35
### Resource Filtering and Pattern Matching
36
37
```java { .api }
38
// Find by filename (leaf name)
39
ResourceList applicationProperties = scanResult.getResourcesWithLeafName("application.properties");
40
ResourceList configFiles = scanResult.getResourcesWithLeafName("config.xml");
41
42
// Find by file extension
43
ResourceList jsonFiles = scanResult.getResourcesWithExtension("json");
44
ResourceList sqlFiles = scanResult.getResourcesWithExtension("sql");
45
ResourceList propertiesFiles = scanResult.getResourcesWithExtension("properties");
46
47
// Find by regex pattern
48
Pattern logbackPattern = Pattern.compile(".*logback.*\\.xml");
49
ResourceList logbackConfigs = scanResult.getResourcesMatchingPattern(logbackPattern);
50
51
// Find by wildcard pattern
52
ResourceList allJsonInConfig = scanResult.getResourcesMatchingWildcard("**/config/**/*.json");
53
ResourceList migrationFiles = scanResult.getResourcesMatchingWildcard("db/migration/**/*.sql");
54
```
55
56
## Resource Content Access
57
58
### Reading Resource Content
59
60
```java { .api }
61
Resource resource = scanResult.getResourcesWithPath("config/database.properties").get(0);
62
63
// Basic resource information
64
String path = resource.getPath(); // "config/database.properties"
65
String relativePath = resource.getPathRelativeToClasspathElement(); // Relative to JAR/directory root
66
long lastModified = resource.getLastModified(); // Timestamp
67
long length = resource.getLength(); // Size in bytes
68
69
// Content access methods
70
try (InputStream inputStream = resource.open()) {
71
// Read as stream
72
Properties props = new Properties();
73
props.load(inputStream);
74
}
75
76
// Read all content at once
77
byte[] content = resource.load();
78
String textContent = resource.getContentAsString(); // UTF-8 decoded
79
80
// Read as ByteBuffer (memory-efficient for large files)
81
ByteBuffer buffer = resource.read();
82
// Remember to call resource.close() when done with ByteBuffer
83
```
84
85
### Bulk Resource Processing
86
87
```java { .api }
88
// Process multiple resources with forEach methods
89
scanResult.getResourcesWithExtension("json")
90
.forEachByteArray((resource, content) -> {
91
String json = new String(content, StandardCharsets.UTF_8);
92
System.out.println("Processing " + resource.getPath() + ": " + json.length() + " bytes");
93
94
// Parse and process JSON
95
try {
96
JsonNode jsonNode = objectMapper.readTree(json);
97
processConfiguration(resource.getPath(), jsonNode);
98
} catch (Exception e) {
99
System.err.println("Failed to parse JSON in " + resource.getPath() + ": " + e.getMessage());
100
}
101
});
102
103
// Process with input streams
104
scanResult.getResourcesWithExtension("properties")
105
.forEach(resource -> {
106
try (InputStream input = resource.open()) {
107
Properties props = new Properties();
108
props.load(input);
109
110
System.out.println("Loaded " + props.size() + " properties from " + resource.getPath());
111
processProperties(resource.getPath(), props);
112
} catch (IOException e) {
113
System.err.println("Failed to load properties from " + resource.getPath());
114
}
115
});
116
```
117
118
## Resource Location and Context
119
120
### Location Information
121
122
```java { .api }
123
Resource resource = scanResult.getResourcesWithPath("META-INF/MANIFEST.MF").get(0);
124
125
// Resource URIs and URLs
126
URI resourceURI = resource.getURI(); // Full resource URI
127
URL resourceURL = resource.getURL(); // Full resource URL
128
129
// Containing classpath element information
130
URI classpathElementURI = resource.getClasspathElementURI(); // JAR or directory URI
131
URL classpathElementURL = resource.getClasspathElementURL(); // JAR or directory URL
132
File classpathElementFile = resource.getClasspathElementFile(); // JAR or directory as File
133
134
// Module information (if resource is in a module)
135
ModuleRef moduleRef = resource.getModuleRef(); // null if not in module
136
```
137
138
### Classpath Element Context
139
140
```java { .api }
141
// Determine resource context
142
if (resource.getModuleRef() != null) {
143
// Resource is in a JPMS module
144
ModuleRef module = resource.getModuleRef();
145
System.out.println("Resource in module: " + module.getName());
146
System.out.println("Module location: " + module.getLocationStr());
147
} else {
148
// Resource is in traditional classpath
149
File classpathElement = resource.getClasspathElementFile();
150
if (classpathElement.isFile()) {
151
System.out.println("Resource in JAR: " + classpathElement.getName());
152
} else {
153
System.out.println("Resource in directory: " + classpathElement.getPath());
154
}
155
}
156
```
157
158
## Classpath Management
159
160
### Classpath Information Access
161
162
```java { .api }
163
// Get classpath information from ClassGraph (before scanning)
164
ClassGraph classGraph = new ClassGraph();
165
166
List<File> classpathFiles = classGraph.getClasspathFiles();
167
String classpathString = classGraph.getClasspath();
168
List<URI> classpathURIs = classGraph.getClasspathURIs();
169
List<URL> classpathURLs = classGraph.getClasspathURLs();
170
171
// Get classpath information from ScanResult (after scanning)
172
try (ScanResult scanResult = new ClassGraph().scan()) {
173
List<File> scannedFiles = scanResult.getClasspathFiles();
174
String scannedClasspath = scanResult.getClasspath();
175
List<URI> scannedURIs = scanResult.getClasspathURIs();
176
List<URL> scannedURLs = scanResult.getClasspathURLs();
177
}
178
```
179
180
### Classpath Element Types
181
182
```java { .api }
183
// Analyze different types of classpath elements
184
List<File> classpathElements = classGraph.getClasspathFiles();
185
186
for (File element : classpathElements) {
187
if (element.isFile()) {
188
if (element.getName().endsWith(".jar") || element.getName().endsWith(".zip")) {
189
System.out.println("JAR/ZIP file: " + element.getPath());
190
} else {
191
System.out.println("Other file: " + element.getPath());
192
}
193
} else if (element.isDirectory()) {
194
System.out.println("Directory: " + element.getPath());
195
}
196
}
197
```
198
199
## Module System Support
200
201
### Module Information
202
203
```java { .api }
204
// Get module information from ClassGraph
205
List<ModuleRef> modules = classGraph.getModules();
206
ModulePathInfo modulePathInfo = classGraph.getModulePathInfo();
207
208
// Module path configuration
209
if (modulePathInfo != null) {
210
Set<String> modulePath = modulePathInfo.modulePath;
211
Set<String> addModules = modulePathInfo.addModules;
212
Set<String> patchModules = modulePathInfo.patchModules;
213
Set<String> addExports = modulePathInfo.addExports;
214
Set<String> addOpens = modulePathInfo.addOpens;
215
Set<String> addReads = modulePathInfo.addReads;
216
}
217
```
218
219
### Module Content Access
220
221
```java { .api }
222
// Access module information from scan results
223
try (ScanResult scanResult = new ClassGraph().enableSystemJarsAndModules().scan()) {
224
ModuleInfoList modules = scanResult.getModuleInfo();
225
226
for (ModuleInfo module : modules) {
227
System.out.println("Module: " + module.getName());
228
System.out.println("Location: " + module.getLocation());
229
230
// Module contents
231
ClassInfoList classesInModule = module.getClassInfo();
232
PackageInfoList packagesInModule = module.getPackageInfo();
233
234
System.out.println(" Classes: " + classesInModule.size());
235
System.out.println(" Packages: " + packagesInModule.size());
236
237
// Module annotations
238
AnnotationInfoList moduleAnnotations = module.getAnnotationInfo();
239
if (!moduleAnnotations.isEmpty()) {
240
System.out.println(" Annotations: " + moduleAnnotations.size());
241
}
242
}
243
}
244
```
245
246
### ModuleRef Details
247
248
```java { .api }
249
ModuleRef moduleRef = resource.getModuleRef();
250
251
if (moduleRef != null) {
252
// Basic module information
253
String name = moduleRef.getName(); // Module name
254
URI location = moduleRef.getLocation(); // Module location
255
String locationStr = moduleRef.getLocationStr(); // Location as string
256
File locationFile = moduleRef.getLocationFile(); // Location as File
257
258
// Module version
259
String version = moduleRef.getRawVersion(); // Version string if available
260
261
// Module contents
262
List<String> packages = moduleRef.getPackages(); // Packages in module
263
264
// Module system objects (via reflection)
265
Object moduleReference = moduleRef.getReference(); // ModuleReference
266
Object moduleLayer = moduleRef.getLayer(); // ModuleLayer
267
Object moduleDescriptor = moduleRef.getDescriptor(); // ModuleDescriptor
268
269
System.out.println("Module: " + name + " v" + version);
270
System.out.println("Location: " + locationStr);
271
System.out.println("Packages: " + packages.size());
272
}
273
```
274
275
## Advanced Resource Operations
276
277
### Custom Resource Processing
278
279
```java { .api }
280
// Custom resource filtering with functional interface
281
ResourceList filteredResources = scanResult.getAllResources()
282
.filter(resource -> {
283
String path = resource.getPath();
284
return path.startsWith("META-INF/") &&
285
path.endsWith(".xml") &&
286
!path.contains("test");
287
});
288
289
// Process configuration files by type
290
Map<String, List<Resource>> configByType = scanResult.getResourcesMatchingWildcard("**/config/**")
291
.stream()
292
.collect(groupingBy(resource -> {
293
String path = resource.getPath();
294
int lastDot = path.lastIndexOf('.');
295
return lastDot > 0 ? path.substring(lastDot + 1).toLowerCase() : "unknown";
296
}));
297
298
System.out.println("Configuration files by type:");
299
configByType.forEach((type, resources) -> {
300
System.out.println(" " + type + ": " + resources.size() + " files");
301
});
302
```
303
304
### Resource Content Analysis
305
306
```java { .api }
307
// Analyze SQL migration files
308
ResourceList sqlFiles = scanResult.getResourcesMatchingWildcard("db/migration/**/*.sql");
309
310
for (Resource sqlFile : sqlFiles) {
311
String content = sqlFile.getContentAsString();
312
313
// Extract version from filename (e.g., V001__create_users.sql)
314
String filename = sqlFile.getPath();
315
Pattern versionPattern = Pattern.compile("V(\\d+)__(.+)\\.sql");
316
Matcher matcher = versionPattern.matcher(filename);
317
318
if (matcher.find()) {
319
String version = matcher.group(1);
320
String description = matcher.group(2).replace("_", " ");
321
322
System.out.println("Migration " + version + ": " + description);
323
System.out.println(" File: " + filename);
324
System.out.println(" Size: " + content.length() + " characters");
325
326
// Analyze SQL content
327
boolean hasCreate = content.toUpperCase().contains("CREATE TABLE");
328
boolean hasInsert = content.toUpperCase().contains("INSERT INTO");
329
boolean hasUpdate = content.toUpperCase().contains("UPDATE ");
330
331
System.out.println(" Operations: " +
332
(hasCreate ? "CREATE " : "") +
333
(hasInsert ? "INSERT " : "") +
334
(hasUpdate ? "UPDATE " : ""));
335
}
336
}
337
```
338
339
### Resource Dependency Analysis
340
341
```java { .api }
342
// Find Spring configuration files and their dependencies
343
ResourceList springConfigs = scanResult.getResourcesMatchingWildcard("**/spring/**/*.xml");
344
345
for (Resource config : springConfigs) {
346
String content = config.getContentAsString();
347
348
// Parse for import statements
349
Pattern importPattern = Pattern.compile("<import\\s+resource=[\"']([^\"']+)[\"']");
350
Matcher importMatcher = importPattern.matcher(content);
351
352
List<String> imports = new ArrayList<>();
353
while (importMatcher.find()) {
354
imports.add(importMatcher.group(1));
355
}
356
357
// Parse for bean definitions
358
Pattern beanPattern = Pattern.compile("<bean\\s+[^>]*class=[\"']([^\"']+)[\"']");
359
Matcher beanMatcher = beanPattern.matcher(content);
360
361
Set<String> referencedClasses = new HashSet<>();
362
while (beanMatcher.find()) {
363
referencedClasses.add(beanMatcher.group(1));
364
}
365
366
System.out.println("Spring config: " + config.getPath());
367
System.out.println(" Imports: " + imports.size());
368
System.out.println(" Bean classes: " + referencedClasses.size());
369
370
// Check if referenced classes exist in scan results
371
for (String className : referencedClasses) {
372
ClassInfo classInfo = scanResult.getClassInfo(className);
373
if (classInfo == null) {
374
System.out.println(" WARNING: Missing class " + className);
375
}
376
}
377
}
378
```
379
380
## Resource Lists and Collection Operations
381
382
### ResourceList Operations
383
384
```java { .api }
385
ResourceList resources = scanResult.getResourcesWithExtension("properties");
386
387
// Get paths and URLs
388
List<String> paths = resources.getPaths();
389
List<String> relativePaths = resources.getPathsRelativeToClasspathElement();
390
List<URL> urls = resources.getURLs();
391
List<URI> uris = resources.getURIs();
392
393
// Access specific resources
394
ResourceList configResources = resources.get("application.properties"); // Resources with specific path
395
Resource firstConfig = configResources.isEmpty() ? null : configResources.get(0);
396
397
// Filtering
398
ResourceList prodConfigs = resources.filter(resource ->
399
resource.getPath().contains("prod") || resource.getPath().contains("production"));
400
401
// Combine with other ResourceLists
402
ResourceList allConfigs = resources.union(
403
scanResult.getResourcesWithExtension("yml"),
404
scanResult.getResourcesWithExtension("yaml")
405
);
406
```
407
408
## Error Handling and Resource Management
409
410
### Safe Resource Access
411
412
```java { .api }
413
// Safe resource processing with proper cleanup
414
ResourceList jsonConfigs = scanResult.getResourcesWithExtension("json");
415
416
for (Resource resource : jsonConfigs) {
417
try {
418
// Option 1: Use try-with-resources for streams
419
try (InputStream input = resource.open()) {
420
JsonNode config = objectMapper.readTree(input);
421
processConfiguration(resource.getPath(), config);
422
}
423
424
// Option 2: Use convenience method for small files
425
String content = resource.getContentAsString();
426
JsonNode config = objectMapper.readTree(content);
427
processConfiguration(resource.getPath(), config);
428
429
// Option 3: Use ByteBuffer for large files (remember to close resource)
430
ByteBuffer buffer = resource.read();
431
try {
432
// Process buffer...
433
} finally {
434
resource.close(); // Important: close resource when using ByteBuffer
435
}
436
437
} catch (IOException e) {
438
System.err.println("Failed to process " + resource.getPath() + ": " + e.getMessage());
439
// Continue processing other resources
440
}
441
}
442
```
443
444
### Resource Change Detection
445
446
```java { .api }
447
try (ScanResult scanResult = new ClassGraph().scan()) {
448
// Check if any resources have changed since scan
449
boolean modified = scanResult.classpathContentsModifiedSinceScan();
450
451
if (modified) {
452
System.out.println("Classpath contents have been modified since scan");
453
454
// Get timestamp of most recent modification
455
long lastModified = scanResult.classpathContentsLastModifiedTime();
456
System.out.println("Last modified: " + new Date(lastModified));
457
458
// Consider rescanning for updated results
459
}
460
}
461
```
462
463
ClassGraph's resource system provides comprehensive access to all classpath and module path resources with efficient processing capabilities and proper resource management, making it ideal for configuration discovery, asset processing, and build-time analysis tasks.