CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-github-classgraph--classgraph

The uber-fast, ultra-lightweight classpath and module scanner for JVM languages.

Pending
Overview
Eval results
Files

resources.mddocs/

Resources and Classpath

ClassGraph provides comprehensive support for discovering, accessing, and managing resources and classpath elements. This includes files in JARs, directories, modules, and various classpath configurations.

Resource Discovery and Access

import io.github.classgraph.Resource;
import io.github.classgraph.ResourceList;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.Properties;

Basic Resource Operations

try (ScanResult scanResult = new ClassGraph().acceptPaths("META-INF", "config").scan()) {
    // Get all resources found during scan
    ResourceList allResources = scanResult.getAllResources();
    
    // Get resources as a map (path -> ResourceList)
    Map<String, ResourceList> resourceMap = scanResult.getAllResourcesAsMap();
    
    // Find resources by exact path
    ResourceList springFactories = scanResult.getResourcesWithPath("META-INF/spring.factories");
    
    // Find resources ignoring accept/reject filters
    ResourceList allSpringFactories = scanResult.getResourcesWithPathIgnoringAccept("META-INF/spring.factories");
}

Resource Filtering and Pattern Matching

// Find by filename (leaf name)
ResourceList applicationProperties = scanResult.getResourcesWithLeafName("application.properties");
ResourceList configFiles = scanResult.getResourcesWithLeafName("config.xml");

// Find by file extension
ResourceList jsonFiles = scanResult.getResourcesWithExtension("json");
ResourceList sqlFiles = scanResult.getResourcesWithExtension("sql");
ResourceList propertiesFiles = scanResult.getResourcesWithExtension("properties");

// Find by regex pattern
Pattern logbackPattern = Pattern.compile(".*logback.*\\.xml");
ResourceList logbackConfigs = scanResult.getResourcesMatchingPattern(logbackPattern);

// Find by wildcard pattern
ResourceList allJsonInConfig = scanResult.getResourcesMatchingWildcard("**/config/**/*.json");
ResourceList migrationFiles = scanResult.getResourcesMatchingWildcard("db/migration/**/*.sql");

Resource Content Access

Reading Resource Content

Resource resource = scanResult.getResourcesWithPath("config/database.properties").get(0);

// Basic resource information
String path = resource.getPath();                                    // "config/database.properties"
String relativePath = resource.getPathRelativeToClasspathElement(); // Relative to JAR/directory root
long lastModified = resource.getLastModified();                     // Timestamp
long length = resource.getLength();                                 // Size in bytes

// Content access methods
try (InputStream inputStream = resource.open()) {
    // Read as stream
    Properties props = new Properties();
    props.load(inputStream);
}

// Read all content at once
byte[] content = resource.load();
String textContent = resource.getContentAsString();                 // UTF-8 decoded

// Read as ByteBuffer (memory-efficient for large files)
ByteBuffer buffer = resource.read();
// Remember to call resource.close() when done with ByteBuffer

Bulk Resource Processing

// Process multiple resources with forEach methods
scanResult.getResourcesWithExtension("json")
    .forEachByteArray((resource, content) -> {
        String json = new String(content, StandardCharsets.UTF_8);
        System.out.println("Processing " + resource.getPath() + ": " + json.length() + " bytes");
        
        // Parse and process JSON
        try {
            JsonNode jsonNode = objectMapper.readTree(json);
            processConfiguration(resource.getPath(), jsonNode);
        } catch (Exception e) {
            System.err.println("Failed to parse JSON in " + resource.getPath() + ": " + e.getMessage());
        }
    });

// Process with input streams
scanResult.getResourcesWithExtension("properties")
    .forEach(resource -> {
        try (InputStream input = resource.open()) {
            Properties props = new Properties();
            props.load(input);
            
            System.out.println("Loaded " + props.size() + " properties from " + resource.getPath());
            processProperties(resource.getPath(), props);
        } catch (IOException e) {
            System.err.println("Failed to load properties from " + resource.getPath());
        }
    });

Resource Location and Context

Location Information

Resource resource = scanResult.getResourcesWithPath("META-INF/MANIFEST.MF").get(0);

// Resource URIs and URLs
URI resourceURI = resource.getURI();                           // Full resource URI
URL resourceURL = resource.getURL();                           // Full resource URL

// Containing classpath element information
URI classpathElementURI = resource.getClasspathElementURI();   // JAR or directory URI
URL classpathElementURL = resource.getClasspathElementURL();   // JAR or directory URL
File classpathElementFile = resource.getClasspathElementFile(); // JAR or directory as File

// Module information (if resource is in a module)
ModuleRef moduleRef = resource.getModuleRef();                 // null if not in module

Classpath Element Context

// Determine resource context
if (resource.getModuleRef() != null) {
    // Resource is in a JPMS module
    ModuleRef module = resource.getModuleRef();
    System.out.println("Resource in module: " + module.getName());
    System.out.println("Module location: " + module.getLocationStr());
} else {
    // Resource is in traditional classpath
    File classpathElement = resource.getClasspathElementFile();
    if (classpathElement.isFile()) {
        System.out.println("Resource in JAR: " + classpathElement.getName());
    } else {
        System.out.println("Resource in directory: " + classpathElement.getPath());
    }
}

Classpath Management

Classpath Information Access

// Get classpath information from ClassGraph (before scanning)
ClassGraph classGraph = new ClassGraph();

List<File> classpathFiles = classGraph.getClasspathFiles();
String classpathString = classGraph.getClasspath();
List<URI> classpathURIs = classGraph.getClasspathURIs();
List<URL> classpathURLs = classGraph.getClasspathURLs();

// Get classpath information from ScanResult (after scanning)
try (ScanResult scanResult = new ClassGraph().scan()) {
    List<File> scannedFiles = scanResult.getClasspathFiles();
    String scannedClasspath = scanResult.getClasspath();
    List<URI> scannedURIs = scanResult.getClasspathURIs();
    List<URL> scannedURLs = scanResult.getClasspathURLs();
}

Classpath Element Types

// Analyze different types of classpath elements
List<File> classpathElements = classGraph.getClasspathFiles();

for (File element : classpathElements) {
    if (element.isFile()) {
        if (element.getName().endsWith(".jar") || element.getName().endsWith(".zip")) {
            System.out.println("JAR/ZIP file: " + element.getPath());
        } else {
            System.out.println("Other file: " + element.getPath());
        }
    } else if (element.isDirectory()) {
        System.out.println("Directory: " + element.getPath());
    }
}

Module System Support

Module Information

// Get module information from ClassGraph
List<ModuleRef> modules = classGraph.getModules();
ModulePathInfo modulePathInfo = classGraph.getModulePathInfo();

// Module path configuration
if (modulePathInfo != null) {
    Set<String> modulePath = modulePathInfo.modulePath;
    Set<String> addModules = modulePathInfo.addModules;
    Set<String> patchModules = modulePathInfo.patchModules;
    Set<String> addExports = modulePathInfo.addExports;
    Set<String> addOpens = modulePathInfo.addOpens;
    Set<String> addReads = modulePathInfo.addReads;
}

Module Content Access

// Access module information from scan results
try (ScanResult scanResult = new ClassGraph().enableSystemJarsAndModules().scan()) {
    ModuleInfoList modules = scanResult.getModuleInfo();
    
    for (ModuleInfo module : modules) {
        System.out.println("Module: " + module.getName());
        System.out.println("Location: " + module.getLocation());
        
        // Module contents
        ClassInfoList classesInModule = module.getClassInfo();
        PackageInfoList packagesInModule = module.getPackageInfo();
        
        System.out.println("  Classes: " + classesInModule.size());
        System.out.println("  Packages: " + packagesInModule.size());
        
        // Module annotations
        AnnotationInfoList moduleAnnotations = module.getAnnotationInfo();
        if (!moduleAnnotations.isEmpty()) {
            System.out.println("  Annotations: " + moduleAnnotations.size());
        }
    }
}

ModuleRef Details

ModuleRef moduleRef = resource.getModuleRef();

if (moduleRef != null) {
    // Basic module information
    String name = moduleRef.getName();                    // Module name
    URI location = moduleRef.getLocation();               // Module location
    String locationStr = moduleRef.getLocationStr();      // Location as string
    File locationFile = moduleRef.getLocationFile();      // Location as File
    
    // Module version
    String version = moduleRef.getRawVersion();           // Version string if available
    
    // Module contents
    List<String> packages = moduleRef.getPackages();      // Packages in module
    
    // Module system objects (via reflection)
    Object moduleReference = moduleRef.getReference();    // ModuleReference
    Object moduleLayer = moduleRef.getLayer();            // ModuleLayer
    Object moduleDescriptor = moduleRef.getDescriptor();  // ModuleDescriptor
    
    System.out.println("Module: " + name + " v" + version);
    System.out.println("Location: " + locationStr);
    System.out.println("Packages: " + packages.size());
}

Advanced Resource Operations

Custom Resource Processing

// Custom resource filtering with functional interface
ResourceList filteredResources = scanResult.getAllResources()
    .filter(resource -> {
        String path = resource.getPath();
        return path.startsWith("META-INF/") && 
               path.endsWith(".xml") && 
               !path.contains("test");
    });

// Process configuration files by type
Map<String, List<Resource>> configByType = scanResult.getResourcesMatchingWildcard("**/config/**")
    .stream()
    .collect(groupingBy(resource -> {
        String path = resource.getPath();
        int lastDot = path.lastIndexOf('.');
        return lastDot > 0 ? path.substring(lastDot + 1).toLowerCase() : "unknown";
    }));

System.out.println("Configuration files by type:");
configByType.forEach((type, resources) -> {
    System.out.println("  " + type + ": " + resources.size() + " files");
});

Resource Content Analysis

// Analyze SQL migration files
ResourceList sqlFiles = scanResult.getResourcesMatchingWildcard("db/migration/**/*.sql");

for (Resource sqlFile : sqlFiles) {
    String content = sqlFile.getContentAsString();
    
    // Extract version from filename (e.g., V001__create_users.sql)
    String filename = sqlFile.getPath();
    Pattern versionPattern = Pattern.compile("V(\\d+)__(.+)\\.sql");
    Matcher matcher = versionPattern.matcher(filename);
    
    if (matcher.find()) {
        String version = matcher.group(1);
        String description = matcher.group(2).replace("_", " ");
        
        System.out.println("Migration " + version + ": " + description);
        System.out.println("  File: " + filename);
        System.out.println("  Size: " + content.length() + " characters");
        
        // Analyze SQL content
        boolean hasCreate = content.toUpperCase().contains("CREATE TABLE");
        boolean hasInsert = content.toUpperCase().contains("INSERT INTO");
        boolean hasUpdate = content.toUpperCase().contains("UPDATE ");
        
        System.out.println("  Operations: " + 
            (hasCreate ? "CREATE " : "") +
            (hasInsert ? "INSERT " : "") +
            (hasUpdate ? "UPDATE " : ""));
    }
}

Resource Dependency Analysis

// Find Spring configuration files and their dependencies
ResourceList springConfigs = scanResult.getResourcesMatchingWildcard("**/spring/**/*.xml");

for (Resource config : springConfigs) {
    String content = config.getContentAsString();
    
    // Parse for import statements
    Pattern importPattern = Pattern.compile("<import\\s+resource=[\"']([^\"']+)[\"']");
    Matcher importMatcher = importPattern.matcher(content);
    
    List<String> imports = new ArrayList<>();
    while (importMatcher.find()) {
        imports.add(importMatcher.group(1));
    }
    
    // Parse for bean definitions
    Pattern beanPattern = Pattern.compile("<bean\\s+[^>]*class=[\"']([^\"']+)[\"']");
    Matcher beanMatcher = beanPattern.matcher(content);
    
    Set<String> referencedClasses = new HashSet<>();
    while (beanMatcher.find()) {
        referencedClasses.add(beanMatcher.group(1));
    }
    
    System.out.println("Spring config: " + config.getPath());
    System.out.println("  Imports: " + imports.size());
    System.out.println("  Bean classes: " + referencedClasses.size());
    
    // Check if referenced classes exist in scan results
    for (String className : referencedClasses) {
        ClassInfo classInfo = scanResult.getClassInfo(className);
        if (classInfo == null) {
            System.out.println("  WARNING: Missing class " + className);
        }
    }
}

Resource Lists and Collection Operations

ResourceList Operations

ResourceList resources = scanResult.getResourcesWithExtension("properties");

// Get paths and URLs
List<String> paths = resources.getPaths();
List<String> relativePaths = resources.getPathsRelativeToClasspathElement();
List<URL> urls = resources.getURLs();
List<URI> uris = resources.getURIs();

// Access specific resources
ResourceList configResources = resources.get("application.properties");  // Resources with specific path
Resource firstConfig = configResources.isEmpty() ? null : configResources.get(0);

// Filtering
ResourceList prodConfigs = resources.filter(resource -> 
    resource.getPath().contains("prod") || resource.getPath().contains("production"));

// Combine with other ResourceLists
ResourceList allConfigs = resources.union(
    scanResult.getResourcesWithExtension("yml"),
    scanResult.getResourcesWithExtension("yaml")
);

Error Handling and Resource Management

Safe Resource Access

// Safe resource processing with proper cleanup
ResourceList jsonConfigs = scanResult.getResourcesWithExtension("json");

for (Resource resource : jsonConfigs) {
    try {
        // Option 1: Use try-with-resources for streams
        try (InputStream input = resource.open()) {
            JsonNode config = objectMapper.readTree(input);
            processConfiguration(resource.getPath(), config);
        }
        
        // Option 2: Use convenience method for small files
        String content = resource.getContentAsString();
        JsonNode config = objectMapper.readTree(content);
        processConfiguration(resource.getPath(), config);
        
        // Option 3: Use ByteBuffer for large files (remember to close resource)
        ByteBuffer buffer = resource.read();
        try {
            // Process buffer...
        } finally {
            resource.close();  // Important: close resource when using ByteBuffer
        }
        
    } catch (IOException e) {
        System.err.println("Failed to process " + resource.getPath() + ": " + e.getMessage());
        // Continue processing other resources
    }
}

Resource Change Detection

try (ScanResult scanResult = new ClassGraph().scan()) {
    // Check if any resources have changed since scan
    boolean modified = scanResult.classpathContentsModifiedSinceScan();
    
    if (modified) {
        System.out.println("Classpath contents have been modified since scan");
        
        // Get timestamp of most recent modification
        long lastModified = scanResult.classpathContentsLastModifiedTime();
        System.out.println("Last modified: " + new Date(lastModified));
        
        // Consider rescanning for updated results
    }
}

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.

Install with Tessl CLI

npx tessl i tessl/maven-io-github-classgraph--classgraph

docs

class-info.md

index.md

querying.md

resources.md

scanning.md

type-signatures.md

tile.json