or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

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

type-signatures.mddocs/

0

# Type Signatures and Generics

1

2

ClassGraph provides comprehensive support for Java's type system, including full generic type information, type parameters, wildcards, and complex nested generic types. This system allows precise analysis of generic types without requiring class loading.

3

4

## Type Signature Hierarchy

5

6

```java { .api }

7

import io.github.classgraph.TypeSignature;

8

import io.github.classgraph.BaseTypeSignature;

9

import io.github.classgraph.ClassRefTypeSignature;

10

import io.github.classgraph.ArrayTypeSignature;

11

import io.github.classgraph.TypeVariableSignature;

12

import io.github.classgraph.ClassTypeSignature;

13

import io.github.classgraph.MethodTypeSignature;

14

import io.github.classgraph.TypeParameter;

15

import io.github.classgraph.TypeArgument;

16

import java.util.List;

17

```

18

19

### TypeSignature - Base Class

20

21

All type signatures extend from the abstract TypeSignature base class:

22

23

```java { .api }

24

TypeSignature typeSignature = fieldInfo.getTypeSignature();

25

26

// Type annotations (Java 8+)

27

AnnotationInfoList typeAnnotations = typeSignature.getTypeAnnotationInfo();

28

29

// Equality comparison ignoring type parameters

30

boolean equalIgnoringGenerics = typeSignature.equalsIgnoringTypeParams(otherSignature);

31

32

// String representation

33

String typeString = typeSignature.toString();

34

```

35

36

## Primitive Types - BaseTypeSignature

37

38

Represents primitive Java types (int, long, boolean, etc.):

39

40

```java { .api }

41

BaseTypeSignature primitiveType = (BaseTypeSignature) fieldInfo.getTypeSignature();

42

43

// Single character type code ('I' for int, 'J' for long, etc.)

44

char typeChar = primitiveType.getTypeSignatureChar();

45

46

// Human-readable type name

47

String typeName = primitiveType.getTypeStr(); // "int", "long", "boolean"

48

49

// Get primitive Class object

50

Class<?> primitiveClass = primitiveType.getType(); // int.class, long.class, etc.

51

```

52

53

### Primitive Type Examples

54

55

```java { .api }

56

// Analyzing primitive fields

57

FieldInfoList fields = classInfo.getDeclaredFieldInfo();

58

for (FieldInfo field : fields) {

59

TypeSignature type = field.getTypeSignature();

60

if (type instanceof BaseTypeSignature) {

61

BaseTypeSignature primitive = (BaseTypeSignature) type;

62

System.out.println("Field " + field.getName() + " is primitive type: " + primitive.getTypeStr());

63

}

64

}

65

```

66

67

## Class References - ClassRefTypeSignature

68

69

Represents references to classes and interfaces, including generic types:

70

71

```java { .api }

72

ClassRefTypeSignature classRef = (ClassRefTypeSignature) fieldInfo.getTypeSignature();

73

74

// Basic class information

75

String baseClassName = classRef.getBaseClassName(); // "java.util.List"

76

String fullyQualifiedName = classRef.getFullyQualifiedClassName(); // "java.util.List"

77

78

// Generic type arguments

79

List<TypeArgument> typeArguments = classRef.getTypeArguments();

80

81

// Inner class information

82

List<String> suffixes = classRef.getSuffixes(); // ["Inner", "Nested"]

83

List<List<TypeArgument>> suffixTypeArguments = classRef.getSuffixTypeArguments();

84

85

// Load referenced class

86

Class<?> referencedClass = classRef.loadClass(false); // Don't initialize

87

Class<?> referencedClassThrow = classRef.loadClass(); // Throw on error

88

89

// Get ClassInfo for referenced class

90

ClassInfo referencedClassInfo = classRef.getClassInfo();

91

```

92

93

### Generic Type Analysis

94

95

```java { .api }

96

// Analyzing generic field: List<String>

97

FieldInfo listField = classInfo.getDeclaredFieldInfo("items");

98

if (listField.getTypeSignature() instanceof ClassRefTypeSignature) {

99

ClassRefTypeSignature listType = (ClassRefTypeSignature) listField.getTypeSignature();

100

101

System.out.println("Base type: " + listType.getBaseClassName()); // "java.util.List"

102

103

List<TypeArgument> typeArgs = listType.getTypeArguments();

104

if (!typeArgs.isEmpty()) {

105

TypeArgument firstArg = typeArgs.get(0);

106

System.out.println("First type argument: " + firstArg.getTypeSignature()); // "java.lang.String"

107

}

108

}

109

110

// Complex generic type: Map<String, List<User>>

111

FieldInfo mapField = classInfo.getDeclaredFieldInfo("userGroups");

112

ClassRefTypeSignature mapType = (ClassRefTypeSignature) mapField.getTypeSignature();

113

114

List<TypeArgument> mapArgs = mapType.getTypeArguments();

115

if (mapArgs.size() == 2) {

116

TypeSignature keyType = mapArgs.get(0).getTypeSignature(); // String

117

TypeSignature valueType = mapArgs.get(1).getTypeSignature(); // List<User>

118

119

if (valueType instanceof ClassRefTypeSignature) {

120

ClassRefTypeSignature listValueType = (ClassRefTypeSignature) valueType;

121

List<TypeArgument> listArgs = listValueType.getTypeArguments();

122

if (!listArgs.isEmpty()) {

123

TypeSignature userType = listArgs.get(0).getTypeSignature(); // User

124

System.out.println("User type: " + userType);

125

}

126

}

127

}

128

```

129

130

## Array Types - ArrayTypeSignature

131

132

Represents array types with full dimension information:

133

134

```java { .api }

135

ArrayTypeSignature arrayType = (ArrayTypeSignature) fieldInfo.getTypeSignature();

136

137

// Full array type signature string

138

String arraySignature = arrayType.getTypeSignatureStr(); // "[Ljava/lang/String;"

139

140

// Element type information

141

TypeSignature elementType = arrayType.getElementTypeSignature(); // String

142

int dimensions = arrayType.getNumDimensions(); // 1 for String[], 2 for String[][]

143

144

// Nested type for multi-dimensional arrays

145

TypeSignature nestedType = arrayType.getNestedType();

146

147

// Array class information

148

ArrayClassInfo arrayClassInfo = arrayType.getArrayClassInfo();

149

150

// Load element and array classes

151

Class<?> elementClass = arrayType.loadElementClass(false);

152

Class<?> elementClassThrow = arrayType.loadElementClass();

153

Class<?> arrayClass = arrayType.loadClass(false);

154

Class<?> arrayClassThrow = arrayType.loadClass();

155

```

156

157

### Array Type Analysis

158

159

```java { .api }

160

// Analyzing various array types

161

FieldInfoList fields = classInfo.getDeclaredFieldInfo();

162

for (FieldInfo field : fields) {

163

TypeSignature type = field.getTypeSignature();

164

if (type instanceof ArrayTypeSignature) {

165

ArrayTypeSignature arrayType = (ArrayTypeSignature) type;

166

167

System.out.println("Field: " + field.getName());

168

System.out.println(" Dimensions: " + arrayType.getNumDimensions());

169

System.out.println(" Element type: " + arrayType.getElementTypeSignature());

170

System.out.println(" Full signature: " + arrayType.getTypeSignatureStr());

171

}

172

}

173

174

// Example outputs:

175

// Field: names

176

// Dimensions: 1

177

// Element type: java.lang.String

178

// Full signature: [Ljava/lang/String;

179

180

// Field: matrix

181

// Dimensions: 2

182

// Element type: int

183

// Full signature: [[I

184

```

185

186

## Type Variables - TypeVariableSignature

187

188

Represents generic type variables (T, E, K, V, etc.):

189

190

```java { .api }

191

TypeVariableSignature typeVar = (TypeVariableSignature) signature;

192

193

// Type variable name

194

String name = typeVar.getName(); // "T", "E", "K", "V", etc.

195

196

// Resolve to type parameter definition

197

TypeParameter typeParam = typeVar.resolve();

198

199

// String representation with bounds

200

String withBounds = typeVar.toStringWithTypeBound(); // "T extends Number"

201

```

202

203

### Type Variable Examples

204

205

```java { .api }

206

// Analyzing generic class: class Container<T extends Number>

207

ClassTypeSignature classSignature = classInfo.getTypeSignature();

208

if (classSignature != null) {

209

List<TypeParameter> typeParams = classSignature.getTypeParameters();

210

for (TypeParameter param : typeParams) {

211

String paramName = param.getName(); // "T"

212

ReferenceTypeSignature classBound = param.getClassBound(); // Number

213

List<ReferenceTypeSignature> interfaceBounds = param.getInterfaceBounds();

214

215

System.out.println("Type parameter: " + paramName);

216

if (classBound != null) {

217

System.out.println(" Class bound: " + classBound);

218

}

219

for (ReferenceTypeSignature bound : interfaceBounds) {

220

System.out.println(" Interface bound: " + bound);

221

}

222

}

223

}

224

225

// Analyzing generic method: <T extends Comparable<T>> T max(T a, T b)

226

MethodInfo genericMethod = classInfo.getDeclaredMethodInfo("max").get(0);

227

MethodTypeSignature methodSignature = genericMethod.getTypeSignature();

228

if (methodSignature != null) {

229

List<TypeParameter> methodTypeParams = methodSignature.getTypeParameters();

230

TypeSignature returnType = methodSignature.getResultType();

231

List<TypeSignature> paramTypes = methodSignature.getParameterTypeSignatures();

232

}

233

```

234

235

## Class Type Signatures - ClassTypeSignature

236

237

Represents complete class signatures including generics:

238

239

```java { .api }

240

ClassTypeSignature classSignature = classInfo.getTypeSignature();

241

242

if (classSignature != null) {

243

// Generic type parameters of the class

244

List<TypeParameter> typeParameters = classSignature.getTypeParameters();

245

246

// Superclass with generic information

247

ClassRefTypeSignature superclassSignature = classSignature.getSuperclassSignature();

248

249

// Implemented interfaces with generic information

250

List<ClassRefTypeSignature> superinterfaceSignatures = classSignature.getSuperinterfaceSignatures();

251

}

252

```

253

254

### Class Signature Analysis

255

256

```java { .api }

257

// Analyzing: class MyList<T extends Number> extends AbstractList<T> implements Serializable

258

ClassTypeSignature signature = classInfo.getTypeSignature();

259

260

// Type parameters: <T extends Number>

261

List<TypeParameter> typeParams = signature.getTypeParameters();

262

if (!typeParams.isEmpty()) {

263

TypeParameter tParam = typeParams.get(0);

264

System.out.println("Type parameter: " + tParam.getName()); // "T"

265

System.out.println("Class bound: " + tParam.getClassBound()); // Number

266

}

267

268

// Superclass: AbstractList<T>

269

ClassRefTypeSignature superclass = signature.getSuperclassSignature();

270

if (superclass != null) {

271

System.out.println("Superclass: " + superclass.getBaseClassName()); // AbstractList

272

List<TypeArgument> superArgs = superclass.getTypeArguments();

273

if (!superArgs.isEmpty()) {

274

System.out.println("Super type arg: " + superArgs.get(0).getTypeSignature()); // T

275

}

276

}

277

278

// Interfaces: Serializable

279

List<ClassRefTypeSignature> interfaces = signature.getSuperinterfaceSignatures();

280

for (ClassRefTypeSignature iface : interfaces) {

281

System.out.println("Interface: " + iface.getBaseClassName()); // Serializable

282

}

283

```

284

285

## Method Type Signatures - MethodTypeSignature

286

287

Represents complete method signatures including generics:

288

289

```java { .api }

290

MethodTypeSignature methodSignature = methodInfo.getTypeSignature();

291

292

if (methodSignature != null) {

293

// Method-level type parameters

294

List<TypeParameter> typeParameters = methodSignature.getTypeParameters();

295

296

// Parameter types

297

List<TypeSignature> parameterTypes = methodSignature.getParameterTypeSignatures();

298

299

// Return type

300

TypeSignature returnType = methodSignature.getResultType();

301

302

// Thrown exceptions

303

List<ClassRefOrTypeVariableSignature> thrownSignatures = methodSignature.getThrowsSignatures();

304

305

// Receiver type annotations (for inner class methods)

306

AnnotationInfoList receiverAnnotations = methodSignature.getReceiverTypeAnnotationInfo();

307

}

308

```

309

310

### Method Signature Analysis

311

312

```java { .api }

313

// Analyzing: public <T extends Comparable<T>> List<T> sort(Collection<? extends T> items) throws IllegalArgumentException

314

MethodInfo sortMethod = classInfo.getDeclaredMethodInfo("sort").get(0);

315

MethodTypeSignature methodSig = sortMethod.getTypeSignature();

316

317

// Method type parameters: <T extends Comparable<T>>

318

List<TypeParameter> methodTypeParams = methodSig.getTypeParameters();

319

if (!methodTypeParams.isEmpty()) {

320

TypeParameter tParam = methodTypeParams.get(0);

321

System.out.println("Method type parameter: " + tParam.getName()); // "T"

322

323

List<ReferenceTypeSignature> bounds = tParam.getInterfaceBounds();

324

for (ReferenceTypeSignature bound : bounds) {

325

System.out.println(" Bound: " + bound); // Comparable<T>

326

}

327

}

328

329

// Return type: List<T>

330

TypeSignature returnType = methodSig.getResultType();

331

System.out.println("Return type: " + returnType);

332

333

// Parameter types: Collection<? extends T>

334

List<TypeSignature> paramTypes = methodSig.getParameterTypeSignatures();

335

for (TypeSignature paramType : paramTypes) {

336

System.out.println("Parameter type: " + paramType);

337

}

338

339

// Thrown exceptions: IllegalArgumentException

340

List<ClassRefOrTypeVariableSignature> thrownTypes = methodSig.getThrowsSignatures();

341

for (ClassRefOrTypeVariableSignature thrown : thrownTypes) {

342

System.out.println("Throws: " + thrown);

343

}

344

```

345

346

## Type Arguments and Wildcards

347

348

### TypeArgument Analysis

349

350

```java { .api }

351

// Analyzing generic types with wildcards: List<? extends Number>

352

ClassRefTypeSignature listType = (ClassRefTypeSignature) fieldInfo.getTypeSignature();

353

List<TypeArgument> typeArgs = listType.getTypeArguments();

354

355

for (TypeArgument arg : typeArgs) {

356

// Wildcard information

357

Wildcard wildcard = arg.getWildcard(); // NONE, ANY, EXTENDS, or SUPER

358

359

// Actual type signature

360

ReferenceTypeSignature typeSignature = arg.getTypeSignature();

361

362

switch (wildcard) {

363

case NONE:

364

System.out.println("Concrete type: " + typeSignature); // List<String>

365

break;

366

case ANY:

367

System.out.println("Unbounded wildcard: ?"); // List<?>

368

break;

369

case EXTENDS:

370

System.out.println("Upper bounded: ? extends " + typeSignature); // List<? extends Number>

371

break;

372

case SUPER:

373

System.out.println("Lower bounded: ? super " + typeSignature); // List<? super Integer>

374

break;

375

}

376

}

377

```

378

379

## Type Parameter Definitions

380

381

### TypeParameter Details

382

383

```java { .api }

384

// Analyzing bounded type parameters: <T extends Number & Comparable<T>>

385

ClassTypeSignature classSignature = classInfo.getTypeSignature();

386

List<TypeParameter> typeParams = classSignature.getTypeParameters();

387

388

for (TypeParameter param : typeParams) {

389

String name = param.getName(); // "T"

390

391

// Class bound (extends clause)

392

ReferenceTypeSignature classBound = param.getClassBound(); // Number

393

394

// Interface bounds (multiple interfaces after &)

395

List<ReferenceTypeSignature> interfaceBounds = param.getInterfaceBounds(); // [Comparable<T>]

396

397

System.out.println("Type parameter: " + name);

398

if (classBound != null) {

399

System.out.println(" Class bound: " + classBound);

400

}

401

for (ReferenceTypeSignature bound : interfaceBounds) {

402

System.out.println(" Interface bound: " + bound);

403

}

404

}

405

```

406

407

## Complex Generic Type Examples

408

409

### Nested Generic Types

410

411

```java { .api }

412

// Analyzing complex nested generics: Map<String, List<Map<Integer, Set<User>>>>

413

FieldInfo complexField = classInfo.getDeclaredFieldInfo("complexData");

414

ClassRefTypeSignature mapType = (ClassRefTypeSignature) complexField.getTypeSignature();

415

416

System.out.println("Base type: " + mapType.getBaseClassName()); // Map

417

418

List<TypeArgument> mapArgs = mapType.getTypeArguments();

419

TypeSignature keyType = mapArgs.get(0).getTypeSignature(); // String

420

TypeSignature valueType = mapArgs.get(1).getTypeSignature(); // List<Map<Integer, Set<User>>>

421

422

if (valueType instanceof ClassRefTypeSignature) {

423

ClassRefTypeSignature listType = (ClassRefTypeSignature) valueType;

424

System.out.println("Value list type: " + listType.getBaseClassName()); // List

425

426

List<TypeArgument> listArgs = listType.getTypeArguments();

427

TypeSignature listElementType = listArgs.get(0).getTypeSignature(); // Map<Integer, Set<User>>

428

429

if (listElementType instanceof ClassRefTypeSignature) {

430

ClassRefTypeSignature innerMapType = (ClassRefTypeSignature) listElementType;

431

System.out.println("Inner map type: " + innerMapType.getBaseClassName()); // Map

432

433

List<TypeArgument> innerMapArgs = innerMapType.getTypeArguments();

434

TypeSignature innerKeyType = innerMapArgs.get(0).getTypeSignature(); // Integer

435

TypeSignature innerValueType = innerMapArgs.get(1).getTypeSignature(); // Set<User>

436

437

// Continue drilling down...

438

}

439

}

440

```

441

442

### Generic Method with Multiple Bounds

443

444

```java { .api }

445

// Analyzing: <T extends Number & Comparable<T> & Serializable> T process(T input)

446

MethodInfo processMethod = classInfo.getDeclaredMethodInfo("process").get(0);

447

MethodTypeSignature methodSig = processMethod.getTypeSignature();

448

449

List<TypeParameter> typeParams = methodSig.getTypeParameters();

450

TypeParameter tParam = typeParams.get(0);

451

452

System.out.println("Type parameter: " + tParam.getName()); // "T"

453

454

// Class bound

455

ReferenceTypeSignature classBound = tParam.getClassBound();

456

if (classBound != null) {

457

System.out.println("Class bound: " + classBound); // Number

458

}

459

460

// Interface bounds

461

List<ReferenceTypeSignature> interfaceBounds = tParam.getInterfaceBounds();

462

for (ReferenceTypeSignature bound : interfaceBounds) {

463

System.out.println("Interface bound: " + bound); // Comparable<T>, Serializable

464

}

465

466

// Return type (should be T)

467

TypeSignature returnType = methodSig.getResultType();

468

if (returnType instanceof TypeVariableSignature) {

469

TypeVariableSignature returnTypeVar = (TypeVariableSignature) returnType;

470

System.out.println("Return type variable: " + returnTypeVar.getName()); // "T"

471

}

472

```

473

474

## Practical Applications

475

476

### Generic Repository Pattern Analysis

477

478

```java { .api }

479

// Find all repository classes and analyze their generic types

480

ClassInfoList repositories = scanResult.getClassesImplementing("com.example.Repository");

481

482

for (ClassInfo repo : repositories) {

483

ClassTypeSignature repoSignature = repo.getTypeSignature();

484

if (repoSignature != null) {

485

// Get implemented interfaces to find Repository<EntityType, IdType>

486

List<ClassRefTypeSignature> interfaces = repoSignature.getSuperinterfaceSignatures();

487

488

for (ClassRefTypeSignature iface : interfaces) {

489

if ("com.example.Repository".equals(iface.getBaseClassName())) {

490

List<TypeArgument> args = iface.getTypeArguments();

491

if (args.size() == 2) {

492

TypeSignature entityType = args.get(0).getTypeSignature();

493

TypeSignature idType = args.get(1).getTypeSignature();

494

495

System.out.println("Repository: " + repo.getName());

496

System.out.println(" Entity type: " + entityType);

497

System.out.println(" ID type: " + idType);

498

}

499

}

500

}

501

}

502

}

503

```

504

505

### Generic Service Method Analysis

506

507

```java { .api }

508

// Analyze service methods for generic return types

509

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

510

511

for (ClassInfo service : services) {

512

MethodInfoList publicMethods = service.getDeclaredMethodInfo()

513

.filter(method -> method.isPublic() && !method.isStatic());

514

515

for (MethodInfo method : publicMethods) {

516

MethodTypeSignature methodSig = method.getTypeSignature();

517

if (methodSig != null) {

518

TypeSignature returnType = methodSig.getResultType();

519

520

// Look for generic collection return types

521

if (returnType instanceof ClassRefTypeSignature) {

522

ClassRefTypeSignature classReturn = (ClassRefTypeSignature) returnType;

523

String returnClassName = classReturn.getBaseClassName();

524

525

if (returnClassName.equals("java.util.List") ||

526

returnClassName.equals("java.util.Set") ||

527

returnClassName.equals("java.util.Optional")) {

528

529

List<TypeArgument> typeArgs = classReturn.getTypeArguments();

530

if (!typeArgs.isEmpty()) {

531

TypeSignature elementType = typeArgs.get(0).getTypeSignature();

532

System.out.println(service.getName() + "." + method.getName() +

533

" returns " + returnClassName + "<" + elementType + ">");

534

}

535

}

536

}

537

}

538

}

539

}

540

```

541

542

The type signature system in ClassGraph provides complete access to Java's complex generic type system, enabling sophisticated analysis of generic types, bounds, and relationships without requiring class loading or runtime reflection.