Class ClassNodeResolver
ClassNode or a SourceUnit.
An instance is installed on a CompilationUnit via
CompilationUnit.setClassNodeResolver(ClassNodeResolver). 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 ClassNodeResolver.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
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
ClassNode. 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).
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic classHelper class to return either a SourceUnit or ClassNode. -
Field Summary
Fields -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidcacheClass(String name, ClassNode res) caches a ClassNodefindClassNode(String name, CompilationUnit compilationUnit) Extension point for custom lookup logic.getFromClassCache(String name) returns whatever is stored in the class cache for the given nameresolveName(String name, CompilationUnit compilationUnit) Resolves a class name to aSourceUnitorClassNode.resolvePackage(String packageName, CompilationUnit compilationUnit) Resolves a package name to aPackageNodecarrying the annotations found on the package's compiledpackage-info.class, if any (GROOVY-12207).
-
Field Details
-
NO_CLASS
Internal helper used to indicate a cache hit for a class that does not exist. This way further lookups through a slowfindClassNode(String, CompilationUnit)path can be avoided. WARNING: This class is not to be used outside of ClassNodeResolver.
-
-
Constructor Details
-
ClassNodeResolver
public ClassNodeResolver()
-
-
Method Details
-
resolveName
Resolves a class name to aSourceUnitorClassNode. Returnsnullif neither is found.The cache is consulted first. A cached
NO_CLASSis returned asnull. On a cache missfindClassNode(String, CompilationUnit)is called. AClassNoderesult is cached; aSourceUnitresult is not, becauseResolveVisitorwill subsequently find that class in the compilation queue. A miss is cached asNO_CLASSso the slow lookup path is not repeated.- Parameters:
name- the fully qualified class namecompilationUnit- the current compilation unit- Returns:
- the lookup result, or
nullif the name cannot be resolved
-
cacheClass
caches a ClassNode- Parameters:
name- - the name of the classres- - the ClassNode for that name
-
getFromClassCache
returns whatever is stored in the class cache for the given name- Parameters:
name- - the name of the class- Returns:
- the result of the lookup, which may be null
-
resolvePackage
Resolves a package name to aPackageNodecarrying the annotations found on the package's compiledpackage-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.classis 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. Returnsnullif the package has no such metadata.- Parameters:
packageName- the fully qualified package name (no trailing dot), e.g."foo.bar"compilationUnit- the currentCompilationUnit- Returns:
- a
PackageNodewith the package's annotations, ornullif none
-
findClassNode
Extension point for custom lookup logic. The default implementation uses the compilation unit class loader: ASM decompilation of a.classresource first, thenClassLoader.loadClass(String), then a groovy source of the same name if that source is newer than the loaded class (or if no class was found).NoClassDefFoundErrorfrom 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.- Parameters:
name- the fully qualified class namecompilationUnit- the current compilation unit- Returns:
- the lookup result, or
nullifcompilationUnitisnullor the name cannot be resolved
-