public class ClassNodeResolver
extends Object
Pluggable lookup of class names to a ClassNode or a SourceUnit.
An instance is installed on a CompilationUnit via CompilationUnit.setClassNodeResolver. The compilation unit then sets the resolver on ResolveVisitor for each resolving pass. ResolveVisitor prepares the name and asks this resolver whether the class exists. A SourceUnit result means the compiler should add that source to the compilation queue; a ClassNode result completes resolving for that name. The outcome is wrapped in LookupResult.
Lookup is two independent strategies selected by the compilation unit's
optimization options asmResolving and classLoaderResolving
(both default on). They are not each other's fallback:
ASM describes a type from bytecode without linking it, so a missing superclass does not prevent a ClassNode.
ClassNodeResolver lookup modes Mode asm class loader Lookup default on on ASM first; loadClassonly if ASM has no matchASM-only on off ASM only; class-format errors thrown loader-only off on loadClassonly; no decompileneither off off groovy source only
loadClass is for types that exist
only in memory (or when ASM is off). A ClassHelper hit for an already
resolved name is not loadClass.
NoClassDefFoundError means the class was found but could not be linked. It is wrapped with the looked-up name and rethrown, and is not cached as a miss. Script fallback on that error is only for an ASM bytecode-name mismatch (the requested name never existed). A groovy source replaces a found class only when that class came from another loader and the source is newer.
Lookups are cached. Override cacheClass(String, ClassNode) and getFromClassCache(String) to disable or replace the cache. Custom lookup logic belongs in findClassNode(String, CompilationUnit); the entry point is resolveName(String, CompilationUnit).
| Modifiers | Name | Description |
|---|---|---|
static class |
ClassNodeResolver.LookupResult |
Helper class to return either a SourceUnit or ClassNode. |
| Type Params | Return Type | Name and description |
|---|---|---|
|
public void |
cacheClass(String name, ClassNode res)caches a ClassNode |
|
public ClassNodeResolver.LookupResult |
findClassNode(String name, CompilationUnit compilationUnit)Extension point for custom lookup logic. |
|
public ClassNode |
getFromClassCache(String name)returns whatever is stored in the class cache for the given name |
|
public ClassNodeResolver.LookupResult |
resolveName(String name, CompilationUnit compilationUnit)Resolves a class name to a SourceUnit or ClassNode. |
|
public PackageNode |
resolvePackage(String packageName, CompilationUnit compilationUnit)Resolves a package name to a PackageNode carrying the annotations found on the package's compiled package-info.class, if any (GROOVY-12207). |
Internal helper used to indicate a cache hit for a class that does not exist. This way further lookups through a slow findClassNode(String, CompilationUnit) path can be avoided. WARNING: This class is not to be used outside of ClassNodeResolver.
caches a ClassNode
name - - the name of the classres - - the ClassNode for that name Extension point for custom lookup logic. The default implementation uses
the compilation unit class loader: ASM decompilation of a .class
resource first, then ClassLoader.loadClass, then a groovy
source of the same name if that source is newer than the loaded class
(or if no class was found).
NoClassDefFoundError from class loading is not treated as a miss. It is wrapped and rethrown. Decompilation is not used as a fallback from that error; matching bytecode is the ASM strategy, which runs first when it is enabled. A groovy source replaces an existing class only when it came from another class loader and is newer.
name - the fully qualified class namecompilationUnit - the current compilation unitnull if compilationUnit is
null or the name cannot be resolvedreturns whatever is stored in the class cache for the given name
name - - the name of the class Resolves a class name to a SourceUnit or ClassNode.
Returns null if neither is found.
The cache is consulted first. A cached NO_CLASS is returned as
null. On a cache miss findClassNode(String, CompilationUnit)
is called. A ClassNode result is cached; a SourceUnit result
is not, because ResolveVisitor will subsequently find that class in
the compilation queue. A miss is cached as NO_CLASS so the slow
lookup path is not repeated.
name - the fully qualified class namecompilationUnit - the current compilation unitnull if the name cannot be resolved Resolves a package name to a PackageNode carrying the annotations found on the
package's compiled package-info.class, if any (GROOVY-12207). This makes
package-level annotations of precompiled dependencies (e.g. JSpecify's @NullMarked)
visible to type checkers and AST transforms.
The package-info.class is located on the compilation unit's class path and decompiled
on demand using the same ASM infrastructure as ordinary classes; results are cached per
resolver, including a negative cache for packages that have no (annotation-bearing)
package-info. Returns null if the package has no such metadata.
packageName - the fully qualified package name (no trailing dot), e.g. "foo.bar"compilationUnit - the current CompilationUnitnull if none