or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

class-info.mdindex.mdquerying.mdresources.mdscanning.mdtype-signatures.md

querying.mddocs/

0

# Querying and Results

1

2

The ScanResult class provides comprehensive querying capabilities for finding classes, interfaces, annotations, and resources from the scanned classpath. It implements Closeable and must be properly closed after use.

3

4

## Basic Result Access

5

6

```java { .api }

7

import io.github.classgraph.ScanResult;

8

import io.github.classgraph.ClassInfo;

9

import io.github.classgraph.ClassInfoList;

10

import io.github.classgraph.ResourceList;

11

import io.github.classgraph.MethodInfoList;

12

import io.github.classgraph.AnnotationInfo;

13

import java.util.Map;

14

import java.util.List;

15

import java.util.AbstractList;

16

import java.util.ArrayList;

17

import java.util.Arrays;

18

import java.util.Properties;

19

import java.io.InputStream;

20

import java.nio.charset.StandardCharsets;

21

import java.util.regex.Pattern;

22

```

23

24

### Class Information Queries

25

26

```java { .api }

27

try (ScanResult scanResult = new ClassGraph().enableAllInfo().scan()) {

28

// Get all classes found during scan

29

ClassInfoList allClasses = scanResult.getAllClasses();

30

31

// Get specific class by name

32

ClassInfo classInfo = scanResult.getClassInfo("com.example.MyClass");

33

34

// Get classes by type

35

ClassInfoList standardClasses = scanResult.getAllStandardClasses(); // Non-interface classes

36

ClassInfoList interfaces = scanResult.getAllInterfaces();

37

ClassInfoList annotations = scanResult.getAllAnnotations();

38

ClassInfoList enums = scanResult.getAllEnums();

39

ClassInfoList records = scanResult.getAllRecords(); // JDK 14+

40

41

// Combined queries

42

ClassInfoList interfacesAndAnnotations = scanResult.getAllInterfacesAndAnnotations();

43

44

// Get as Map for O(1) lookup

45

Map<String, ClassInfo> classMap = scanResult.getAllClassesAsMap();

46

}

47

```

48

49

## Inheritance and Implementation Queries

50

51

### Subclass and Superclass Queries

52

53

```java { .api }

54

try (ScanResult scanResult = new ClassGraph().enableAllInfo().scan()) {

55

// Find all subclasses (direct and indirect)

56

ClassInfoList subclasses = scanResult.getSubclasses("java.util.AbstractList");

57

ClassInfoList subclassesByClass = scanResult.getSubclasses(AbstractList.class);

58

59

// Find superclass hierarchy

60

ClassInfoList superclasses = scanResult.getSuperclasses("java.util.ArrayList");

61

ClassInfoList superclassesByClass = scanResult.getSuperclasses(ArrayList.class);

62

63

// Find interfaces of a class

64

ClassInfoList interfaces = scanResult.getInterfaces("java.util.ArrayList");

65

ClassInfoList interfacesByClass = scanResult.getInterfaces(ArrayList.class);

66

67

// Find all implementers of an interface

68

ClassInfoList implementers = scanResult.getClassesImplementing("java.util.List");

69

ClassInfoList implementersByClass = scanResult.getClassesImplementing(List.class);

70

}

71

```

72

73

### Complex Inheritance Examples

74

75

```java { .api }

76

// Find all service implementations

77

ClassInfoList serviceImpls = scanResult.getClassesImplementing("com.example.Service");

78

79

// Find all classes extending a specific abstract class

80

ClassInfoList controllerSubclasses = scanResult.getSubclasses("com.example.AbstractController");

81

82

// Find all classes that implement multiple interfaces

83

ClassInfoList multiInterface = scanResult.getAllClasses()

84

.filter(classInfo ->

85

classInfo.implementsInterface("java.io.Serializable") &&

86

classInfo.implementsInterface("java.lang.Cloneable"));

87

```

88

89

### Set Operations on ClassInfoList

90

91

ClassInfoList supports set operations for combining and filtering results:

92

93

```java { .api }

94

// Get two different sets of classes

95

ClassInfoList serviceClasses = scanResult.getClassesImplementing("com.example.Service");

96

ClassInfoList annotatedClasses = scanResult.getClassesWithAnnotation("com.example.Component");

97

98

// Union - classes that are in either list

99

ClassInfoList unionClasses = serviceClasses.union(annotatedClasses);

100

101

// Intersection - classes that are in both lists

102

ClassInfoList intersectionClasses = serviceClasses.intersect(annotatedClasses);

103

104

// Exclusion - classes in first list but not in second

105

ClassInfoList excludedClasses = serviceClasses.exclude(annotatedClasses);

106

107

// Multiple set operations

108

ClassInfoList controllers = scanResult.getClassesWithAnnotation("org.springframework.stereotype.Controller");

109

ClassInfoList restControllers = scanResult.getClassesWithAnnotation("org.springframework.web.bind.annotation.RestController");

110

ClassInfoList services = scanResult.getClassesWithAnnotation("org.springframework.stereotype.Service");

111

112

// All Spring components

113

ClassInfoList allSpringComponents = controllers.union(restControllers, services);

114

```

115

116

## Annotation Queries

117

118

### Basic Annotation Queries

119

120

```java { .api }

121

try (ScanResult scanResult = new ClassGraph().enableAnnotationInfo().scan()) {

122

// Classes with specific annotation

123

ClassInfoList annotatedClasses = scanResult.getClassesWithAnnotation("javax.persistence.Entity");

124

ClassInfoList annotatedByClass = scanResult.getClassesWithAnnotation(Entity.class);

125

126

// Classes with ALL specified annotations

127

ClassInfoList withAllAnnotations = scanResult.getClassesWithAllAnnotations(

128

"javax.persistence.Entity", "javax.persistence.Table");

129

130

// Classes with ANY of the specified annotations

131

ClassInfoList withAnyAnnotations = scanResult.getClassesWithAnyAnnotation(

132

"javax.ws.rs.GET", "javax.ws.rs.POST", "javax.ws.rs.PUT");

133

134

// Get annotations on a specific class

135

ClassInfoList annotations = scanResult.getAnnotationsOnClass("com.example.MyClass");

136

}

137

```

138

139

### Method and Field Annotation Queries

140

141

```java { .api }

142

// Find classes that have methods with specific annotations

143

ClassInfoList classesWithMethodAnnotation = scanResult.getClassesWithMethodAnnotation("javax.ws.rs.GET");

144

145

// Find classes that have fields with specific annotations

146

ClassInfoList classesWithFieldAnnotation = scanResult.getClassesWithFieldAnnotation("javax.persistence.Column");

147

148

// Find classes with method parameter annotations

149

ClassInfoList classesWithParamAnnotation = scanResult.getClassesWithMethodParameterAnnotation("javax.validation.Valid");

150

```

151

152

### Advanced Annotation Processing

153

154

```java { .api }

155

// Process REST endpoints

156

ClassInfoList restControllers = scanResult.getClassesWithAnnotation("org.springframework.web.bind.annotation.RestController");

157

158

for (ClassInfo controllerClass : restControllers) {

159

System.out.println("Controller: " + controllerClass.getName());

160

161

// Find all request mapping methods

162

MethodInfoList requestMethods = controllerClass.getDeclaredMethodInfo()

163

.filter(methodInfo ->

164

methodInfo.hasAnnotation("org.springframework.web.bind.annotation.RequestMapping") ||

165

methodInfo.hasAnnotation("org.springframework.web.bind.annotation.GetMapping") ||

166

methodInfo.hasAnnotation("org.springframework.web.bind.annotation.PostMapping"));

167

168

for (MethodInfo method : requestMethods) {

169

System.out.println(" Endpoint: " + method.getName());

170

171

// Extract annotation values

172

AnnotationInfo mapping = method.getAnnotationInfo("org.springframework.web.bind.annotation.GetMapping");

173

if (mapping != null) {

174

String[] paths = (String[]) mapping.getParameterValues().getValue("value");

175

System.out.println(" Paths: " + Arrays.toString(paths));

176

}

177

}

178

}

179

```

180

181

## Resource Queries

182

183

### Basic Resource Access

184

185

```java { .api }

186

try (ScanResult scanResult = new ClassGraph().acceptPaths("META-INF", "config").scan()) {

187

// Get all resources found

188

ResourceList allResources = scanResult.getAllResources();

189

Map<String, ResourceList> resourceMap = scanResult.getAllResourcesAsMap();

190

191

// Find resources by specific path

192

ResourceList configFiles = scanResult.getResourcesWithPath("META-INF/spring.factories");

193

194

// Find resources ignoring accept/reject filters

195

ResourceList allSpringFiles = scanResult.getResourcesWithPathIgnoringAccept("META-INF/spring.factories");

196

197

// Find by filename (leaf name)

198

ResourceList propertiesFiles = scanResult.getResourcesWithLeafName("application.properties");

199

200

// Find by extension

201

ResourceList jsonFiles = scanResult.getResourcesWithExtension("json");

202

ResourceList xmlFiles = scanResult.getResourcesWithExtension("xml");

203

}

204

```

205

206

### Pattern-Based Resource Queries

207

208

```java { .api }

209

import java.util.regex.Pattern;

210

211

// Find resources matching regex pattern

212

Pattern logbackPattern = Pattern.compile(".*logback.*\\.xml");

213

ResourceList logbackConfigs = scanResult.getResourcesMatchingPattern(logbackPattern);

214

215

// Find resources matching wildcard pattern

216

ResourceList sqlFiles = scanResult.getResourcesMatchingWildcard("**/*.sql");

217

ResourceList configFiles = scanResult.getResourcesMatchingWildcard("**/config/**");

218

```

219

220

### Resource Content Processing

221

222

```java { .api }

223

// Process JSON configuration files

224

scanResult.getResourcesWithExtension("json")

225

.forEachByteArrayIgnoringIOException((resource, content) -> {

226

String json = new String(content, StandardCharsets.UTF_8);

227

System.out.println("Processing " + resource.getPath() + ": " + json.length() + " bytes");

228

// Parse JSON and process...

229

});

230

231

// Load properties files

232

scanResult.getResourcesWithExtension("properties")

233

.forEach(resource -> {

234

try (InputStream inputStream = resource.open()) {

235

Properties props = new Properties();

236

props.load(inputStream);

237

System.out.println("Loaded " + props.size() + " properties from " + resource.getPath());

238

} catch (IOException e) {

239

System.err.println("Failed to load " + resource.getPath() + ": " + e.getMessage());

240

}

241

});

242

```

243

244

## Package and Module Information

245

246

### Package Queries

247

248

```java { .api }

249

try (ScanResult scanResult = new ClassGraph().enableAllInfo().scan()) {

250

// Get all packages

251

PackageInfoList allPackages = scanResult.getPackageInfo();

252

253

// Get specific package

254

PackageInfo packageInfo = scanResult.getPackageInfo("com.example");

255

256

if (packageInfo != null) {

257

// Get classes in package

258

ClassInfoList classesInPackage = packageInfo.getClassInfo();

259

260

// Get package annotations

261

AnnotationInfoList packageAnnotations = packageInfo.getAnnotationInfo();

262

263

// Package hierarchy

264

PackageInfo parent = packageInfo.getParent();

265

PackageInfoList children = packageInfo.getChildren();

266

}

267

}

268

```

269

270

### Module Queries (JPMS)

271

272

```java { .api }

273

// Get all modules

274

ModuleInfoList allModules = scanResult.getModuleInfo();

275

276

// Get specific module

277

ModuleInfo moduleInfo = scanResult.getModuleInfo("java.base");

278

279

if (moduleInfo != null) {

280

// Get classes in module

281

ClassInfoList classesInModule = moduleInfo.getClassInfo();

282

283

// Get packages in module

284

PackageInfoList packagesInModule = moduleInfo.getPackageInfo();

285

286

// Module location and reference

287

URI location = moduleInfo.getLocation();

288

ModuleRef moduleRef = moduleInfo.getModuleRef();

289

}

290

```

291

292

## Dependency Analysis

293

294

When `enableInterClassDependencies()` is enabled:

295

296

```java { .api }

297

try (ScanResult scanResult = new ClassGraph()

298

.enableInterClassDependencies()

299

.acceptPackages("com.example")

300

.scan()) {

301

302

// Get class dependency map (what each class depends on)

303

Map<ClassInfo, ClassInfoList> dependencyMap = scanResult.getClassDependencyMap();

304

305

// Get reverse dependency map (what depends on each class)

306

Map<ClassInfo, ClassInfoList> reverseDependencyMap = scanResult.getReverseClassDependencyMap();

307

308

// Analyze specific class dependencies

309

ClassInfo serviceClass = scanResult.getClassInfo("com.example.UserService");

310

if (serviceClass != null) {

311

ClassInfoList dependencies = serviceClass.getClassDependencies();

312

System.out.println("UserService depends on " + dependencies.size() + " other classes");

313

314

// Find what depends on UserService

315

ClassInfoList dependents = reverseDependencyMap.get(serviceClass);

316

if (dependents != null) {

317

System.out.println(dependents.size() + " classes depend on UserService");

318

}

319

}

320

}

321

```

322

323

## Change Detection and Monitoring

324

325

```java { .api }

326

try (ScanResult scanResult = new ClassGraph().scan()) {

327

// Check if classpath has been modified since scan

328

boolean modified = scanResult.classpathContentsModifiedSinceScan();

329

330

if (modified) {

331

System.out.println("Classpath has changed - consider rescanning");

332

333

// Get timestamp of latest modification

334

long lastModified = scanResult.classpathContentsLastModifiedTime();

335

System.out.println("Last modified: " + new Date(lastModified));

336

}

337

}

338

```

339

340

## Class Loading from Results

341

342

### Safe Class Loading

343

344

```java { .api }

345

// Load class by name with error handling

346

try {

347

Class<?> clazz = scanResult.loadClass("com.example.MyClass", false); // false = don't initialize

348

System.out.println("Loaded class: " + clazz.getName());

349

} catch (Exception e) {

350

System.err.println("Failed to load class: " + e.getMessage());

351

}

352

353

// Load and cast class with type safety

354

try {

355

Class<? extends Service> serviceClass = scanResult.loadClass("com.example.MyService", Service.class, false);

356

Service instance = serviceClass.getDeclaredConstructor().newInstance();

357

} catch (Exception e) {

358

System.err.println("Failed to instantiate service: " + e.getMessage());

359

}

360

```

361

362

### Bulk Class Loading

363

364

```java { .api }

365

ClassInfoList serviceClasses = scanResult.getClassesImplementing("com.example.Service");

366

367

// Load all service classes safely

368

List<Class<? extends Service>> loadedClasses = serviceClasses.loadClasses(Service.class, false);

369

370

// Filter out classes that failed to load

371

List<Class<? extends Service>> validClasses = loadedClasses.stream()

372

.filter(Objects::nonNull)

373

.collect(toList());

374

375

System.out.println("Successfully loaded " + validClasses.size() + " service classes");

376

```

377

378

## Serialization and Persistence

379

380

```java { .api }

381

try (ScanResult scanResult = new ClassGraph().enableAllInfo().scan()) {

382

// Serialize scan results to JSON

383

String json = scanResult.toJSON();

384

385

// Serialize with formatting

386

String prettyJson = scanResult.toJSON(2); // 2-space indentation

387

388

// Save to file for caching

389

Files.write(Paths.get("scan-results.json"), json.getBytes());

390

}

391

392

// Later, deserialize from JSON

393

String json = Files.readString(Paths.get("scan-results.json"));

394

try (ScanResult cachedResult = ScanResult.fromJSON(json)) {

395

// Use cached results (classes can't be loaded from deserialized results)

396

boolean fromCache = cachedResult.isObtainedFromDeserialization();

397

System.out.println("Using cached scan results: " + fromCache);

398

399

ClassInfoList allClasses = cachedResult.getAllClasses();

400

// Analyze metadata, but can't load actual classes

401

}

402

```

403

404

## Advanced Filtering and Processing

405

406

### Complex Queries with Streams

407

408

```java { .api }

409

// Find all public final classes with no-arg constructor

410

List<ClassInfo> utilityClasses = scanResult.getAllClasses()

411

.stream()

412

.filter(classInfo -> classInfo.isPublic() && classInfo.isFinal())

413

.filter(classInfo -> {

414

MethodInfoList constructors = classInfo.getDeclaredConstructorInfo();

415

return constructors.stream()

416

.anyMatch(constructor -> constructor.getParameterInfo().length == 0);

417

})

418

.collect(toList());

419

420

// Find all REST endpoints across the application

421

Map<String, List<String>> endpointMap = scanResult.getClassesWithAnnotation("org.springframework.web.bind.annotation.RestController")

422

.stream()

423

.flatMap(controller -> controller.getDeclaredMethodInfo().stream())

424

.filter(method -> method.hasAnnotation("org.springframework.web.bind.annotation.RequestMapping"))

425

.collect(groupingBy(

426

method -> method.getClassInfo().getName(),

427

mapping(method -> method.getName(), toList())

428

));

429

```

430

431

The ScanResult API provides powerful and flexible querying capabilities that enable deep introspection of your codebase structure, dependencies, and resources while maintaining type safety and performance.