Package: org.codehaus.groovy.ast.decompiled

## [Java] Class DecompiledClassNode

- org.codehaus.groovy.ast.decompiled.DecompiledClassNode

-     public class DecompiledClassNode
      extends ClassNode

  Represents a ClassNode for classes loaded from compiled bytecode files decompiled using ASM. This class bridges the gap between raw bytecode metadata and Groovy's AST representation, providing lazy initialization of all class members to enable efficient runtime class loading and introspection without requiring source code.

  ## Architectural Role

  DecompiledClassNode is a deferred factory for AST nodes: it collects bytecode metadata from a ClassStub and reconstructs full AST nodes (methods, fields, constructors) on demand via lazy proxy classes (LazyFieldNode, LazyMethodNode, LazyConstructorNode). This enables Groovy to compile and introspect compiled classes without full bytecode decompilation upfront.

  ## Key Differences from Regular ClassNode

  - Immutability: Decompiled classes are read-only representations of bytecode; modification methods throw UnsupportedOperationException. See setName(String), setRedirect(ClassNode), setUsingGenerics(boolean), setGenericsPlaceHolder(boolean).
  - Always resolved: isResolved() always returns `true`. Unlike source-based classes that transition from unresolved to resolved, decompiled classes are inherently resolved because their metadata is extracted from compiled bytecode.
  - Non-primary: `isPrimaryNode = false`. This indicates the class is derived from compiled bytecode rather than primary source compilation.
  - Lazy initialization: Superclass and member information is initialized on first access, not at construction. This defers expensive metadata parsing until needed.
  - JVM introspection fallback: Certain operations (e.g., isSealed()) delegate to runtime JVM reflection via getTypeClass().

  ## Lazy Initialization Strategy

  DecompiledClassNode uses a two-phase lazy initialization pattern with double-checked locking:

  - Phase 1 - Superclass/Interface metadata: Triggered by accessors like getGenericsTypes(), getInterfaces(), getAnnotations(). lazyInitSupers() parses generic signatures and initializes annotations.
  - Phase 2 - Class members: Triggered by accessors like getMethods(), getFields(), getDeclaredConstructors(). lazyInitMembers() unpacks method and field stubs into AST nodes.
  Private members are wrapped in lazy proxies (LazyFieldNode, LazyMethodNode, LazyConstructorNode) to further defer parsing their complex signatures until accessed.

  ## Thread Safety

  DecompiledClassNode is thread-safe for lazy initialization. Both lazyInitSupers() and lazyInitMembers() use double-checked locking with volatile flags to ensure single initialization across multiple threads. The implementation protects initialization with `lazyInitLock` (inherited from ClassNode) to serialize critical sections.

  ## Caching Strategy

  The ASM decompiler and reference resolver are cached at the DecompiledClassNode level but not across multiple class loads. When the same bytecode is parsed by different AsmDecompiler instances, separate DecompiledClassNode instances are created. This ensures consistency within a compilation context.

  ## Inner Class Modifiers

  For nested classes, the INNERCLASS bytecode attribute (JVMS 4.7.6) provides authoritative access modifiers that correctly reflect nested visibility. getModifiers(ClassStub) prefers `innerClassModifiers` over the top-level `accessModifiers` when available.

  ## Timestamp Extraction

  Groovy embeds compilation timestamps in synthetic static field names for change detection. getCompilationTimeStamp() decodes this metadata using Verifier.getTimestampFromFieldName.

  See Also:
    AsmDecompiler.parseClass
    AsmReferenceResolver
    ClassStub
    LazyFieldNode
    LazyMethodNode
    LazyConstructorNode
    ClassSignatureParser.configureClass
    MemberSignatureParser.createFieldNode
    MemberSignatureParser.createMethodNode

- - Inherited fields
    Fields inherited from class | Fields
    --- | ---
    `class ClassNode` | `EMPTY_ARRAY, SUPER, THIS, clazz, isPrimaryNode, lazyInitLock`

  - ### Constructor Summary

    Constructors
    Constructor and description
    `DecompiledClassNode(ClassStub classData, AsmReferenceResolver resolver)` Creates a DecompiledClassNode from a class stub extracted from bytecode.

  - ### Methods Summary

    Methods
    Type Params | Return Type | Name and description
    --- | --- | ---
    `` | `public List<AnnotationNode>` | `getAnnotations()` Returns all annotations attached to this class.
    `` | `public List<AnnotationNode>` | `getAnnotations(ClassNode type)` Returns annotations of a specific type attached to this class.
    `` | `public long` | `getCompilationTimeStamp()` Extracts the compilation timestamp from static field metadata if present.
    `` | `public List<ConstructorNode>` | `getDeclaredConstructors()` Returns all constructors declared by this class.
    `` | `public FieldNode` | `getDeclaredField(String name)` Returns a field declared by this class with the given name.
    `` | `public List<MethodNode>` | `getDeclaredMethods(String name)` Returns all methods declared by this class with the given name.
    `` | `public List<FieldNode>` | `getFields()` Returns all fields declared by this class (excluding inherited fields).
    `` | `public GenericsType[]` | `getGenericsTypes()` Returns the generic type parameters of this class.
    `` | `public ClassNode[]` | `getInterfaces()` Returns the interfaces implemented by this class.
    `` | `public List<MethodNode>` | `getMethods()` Returns all methods and constructors declared by this class (excluding inherited methods).
    `` | `public PackageNode` | `getPackage()` Returns the PackageNode for this decompiled class, carrying any annotations declared on the package's compiled `package-info.class` (GROOVY-12207).
    `` | `public List<RecordComponentNode>` | `getRecordComponents()` Returns the record components of this record class (Java 16+).
    `` | `public Class` | `getTypeClass()` Resolves the runtime JVM Class object for this decompiled class node.
    `` | `public ClassNode[]` | `getUnresolvedInterfaces(boolean useRedirect)` Returns the unresolved (not yet redirected) interfaces implemented by this class.
    `` | `public ClassNode` | `getUnresolvedSuperClass(boolean useRedirect)` Returns the unresolved (not yet redirected) superclass of this class.
    `` | `public boolean` | `isParameterized()` Determines whether this class has generic type parameters by inspecting the bytecode signature.
    `` | `public boolean` | `isResolved()` Reports that this class node is fully resolved from bytecode.
    `` | `public boolean` | `isSealed()` Determines if this class is sealed, checking both Java sealed class annotations and Groovy `@Sealed` transform annotations.
    `` | `public boolean` | `isUsingGenerics()` Indicates whether this class is using generic types.
    `` | `public void` | `setGenericsPlaceHolder(boolean b)` Prevents marking decompiled class nodes as generic placeholders.
    `` | `public String` | `setName(String name)` Prevents renaming of decompiled class nodes, as they represent immutable bytecode definitions.
    `` | `public void` | `setRedirect(ClassNode cn)` Prevents redirection of decompiled class nodes to alternate implementations.
    `` | `public void` | `setUsingGenerics(boolean b)` Prevents modification of generic type usage for decompiled class nodes.

  - ### Inherited Methods Summary

    Inherited Methods
    Methods inherited from class | Name
    --- | ---
    `class ClassNode` | `addConstructor, addConstructor, addField, addField, addFieldFirst, addFieldFirst, addInterface, addMethod, addMethod, addMixin, addObjectInitializerStatements, addProperty, addProperty, addStaticInitializerStatements, addSyntheticMethod, addTransform, addTypeAnnotation, addTypeAnnotations, asGenericsType, declaresAnyInterfaces, declaresInterface, equals, getAbstractMethods, getAllDeclaredMethods, getAllInterfaces, getAnnotations, getAnnotations, getCompileUnit, getComponentType, getDeclaredConstructor, getDeclaredConstructors, getDeclaredField, getDeclaredMethod, getDeclaredMethods, getDeclaredMethodsMap, getEnclosingMethod, getField, getFieldIndex, getFields, getGenericsTypes, getGetterMethod, getGetterMethod, getInnerClasses, getInterfaces, getMethod, getMethods, getMethods, getMixins, getModifiers, getModule, getName, getNameWithoutPackage, getObjectInitializerStatements, getOuterClass, getOuterClassType, getOuterClasses, getOuterField, getPackage, getPackageName, getPermittedSubclasses, getPlainNodeReference, getPlainNodeReference, getProperties, getProperty, getRecordComponents, getSetterMethod, getSetterMethod, getSuperClass, getText, getTransforms, getTypeAnnotations, getTypeAnnotations, getTypeClass, getUnresolvedInterfaces, getUnresolvedInterfaces, getUnresolvedName, getUnresolvedSuperClass, getUnresolvedSuperClass, hasDeclaredMethod, hasMethod, hasPackageName, hasPossibleMethod, hasPossibleStaticMethod, hasProperty, hashCode, implementsAnyInterfaces, implementsInterface, isAbstract, isAnnotated, isAnnotationDefinition, isArray, isDerivedFrom, isDerivedFromGroovyObject, isEnum, isGenericsPlaceHolder, isInterface, isPrimaryClassNode, isRecord, isRedirectNode, isResolved, isScript, isScriptBody, isSealed, isStatic, isStaticClass, isSyntheticPublic, isUsingGenerics, makeArray, parametersEqual, positionStmtsAfterEnumInitStmts, redirect, removeConstructor, removeField, removeMethod, renameField, setAnnotated, setCompileUnit, setEnclosingMethod, setGenericsPlaceHolder, setGenericsTypes, setInterfaces, setMixins, setModifiers, setModule, setName, setOuterClassType, setPermittedSubclasses, setRecordComponents, setRedirect, setScript, setScriptBody, setStaticClass, setSuperClass, setSyntheticPublic, setUnresolvedSuperClass, setUsingGenerics, toString, toString, tryFindPossibleMethod, visitContents`
    `class AnnotatedNode` | `addAnnotation, addAnnotation, addAnnotations, getAnnotations, getAnnotations, getDeclaringClass, getGroovydoc, getInstance, hasNoRealSourcePosition, isSynthetic, setDeclaringClass, setHasNoRealSourcePosition, setSynthetic`
    `class ASTNode` | `copyNodeMetaData, getColumnNumber, getLastColumnNumber, getLastLineNumber, getLineNumber, getMetaDataMap, getText, setColumnNumber, setLastColumnNumber, setLastLineNumber, setLineNumber, setMetaDataMap, setSourcePosition, visit`

- - ### Constructor Detail

    - #### public DecompiledClassNode(ClassStub classData, AsmReferenceResolver resolver)

      Creates a DecompiledClassNode from a class stub extracted from bytecode.

      Parameters:
        `classData` - the ClassStub containing bytecode-derived metadata
        `resolver` - the AsmReferenceResolver used to resolve class references

  - ### Method Detail

    - #### public List<AnnotationNode> getAnnotations()

      Returns all annotations attached to this class. Triggers lazy initialization of superclass and interface metadata.

      Returns:
        list of AnnotationNode objects

    - #### public List<AnnotationNode> getAnnotations(ClassNode type)

      Returns annotations of a specific type attached to this class. Triggers lazy initialization of superclass and interface metadata.

      Parameters:
        `type` - the annotation type to filter by
      Returns:
        list of matching AnnotationNode objects

    - #### public long getCompilationTimeStamp()

      Extracts the compilation timestamp from static field metadata if present. Groovy embeds compilation timestamps in synthetic static field names using a special encoding.

      Returns:
        the compilation timestamp in milliseconds, or `Long.MAX_VALUE` if not available
      See Also:
        Verifier.getTimestampFromFieldName

    - #### public List<ConstructorNode> getDeclaredConstructors()

      Returns all constructors declared by this class. Triggers lazy initialization of class members.

      Returns:
        list of ConstructorNode objects

    - #### public FieldNode getDeclaredField(String name)

      Returns a field declared by this class with the given name. Triggers lazy initialization of class members.

      Parameters:
        `name` - the field name
      Returns:
        the FieldNode if found, or `null` if no such field exists

    - #### public List<MethodNode> getDeclaredMethods(String name)

      Returns all methods declared by this class with the given name. Triggers lazy initialization of class members.

      Parameters:
        `name` - the method name
      Returns:
        list of MethodNode objects with the specified name

    - #### public List<FieldNode> getFields()

      Returns all fields declared by this class (excluding inherited fields). Triggers lazy initialization of class members.

      Returns:
        list of FieldNode objects

    - #### public GenericsType[] getGenericsTypes()

      Returns the generic type parameters of this class. Triggers lazy initialization of generic type information from the class signature.

      Returns:
        array of GenericsType objects, or empty array if not generic

    - #### public ClassNode[] getInterfaces()

      Returns the interfaces implemented by this class. Triggers lazy initialization of interface metadata from the bytecode.

      Returns:
        array of ClassNode objects representing interfaces

    - #### public List<MethodNode> getMethods()

      Returns all methods and constructors declared by this class (excluding inherited methods). Triggers lazy initialization of class members.

      Returns:
        list of MethodNode objects

    - #### public PackageNode getPackage()

      Returns the PackageNode for this decompiled class, carrying any annotations declared on the package's compiled `package-info.class` (GROOVY-12207). Unlike a source-based ClassNode, a decompiled class has no owning module, so the package (and its annotations) is resolved on demand from the class path via the reference resolver's `ClassNodeResolver.resolvePackage` and cached there. Returns `null` for the default package or when the package has no such metadata.

      Returns:
        the package node with package-level annotations, or `null` if none

    - #### public List<RecordComponentNode> getRecordComponents()

      Returns the record components of this record class (Java 16+). Triggers lazy initialization of superclass and interface metadata.

      Returns:
        list of RecordComponentNode objects, or empty list if not a record

    - #### public Class getTypeClass()

      Resolves the runtime JVM Class object for this decompiled class node.

      throws:
        org.codehaus.groovy.GroovyBugError if the class cannot be resolved at runtime
      Returns:
        the loaded Class instance from the current classloader
      See Also:
        AsmReferenceResolver.resolveJvmClass

    - #### public ClassNode[] getUnresolvedInterfaces(boolean useRedirect)

      Returns the unresolved (not yet redirected) interfaces implemented by this class. Triggers lazy initialization of interface metadata.

      Parameters:
        `useRedirect` - whether to follow class redirects (typically false for decompiled classes)
      Returns:
        array of ClassNode objects representing interfaces

    - #### public ClassNode getUnresolvedSuperClass(boolean useRedirect)

      Returns the unresolved (not yet redirected) superclass of this class. Triggers lazy initialization of superclass metadata.

      Parameters:
        `useRedirect` - whether to follow class redirects (typically false for decompiled classes)
      Returns:
        the ClassNode representing the superclass

    - #### public boolean isParameterized()

      Determines whether this class has generic type parameters by inspecting the bytecode signature. A parameterized class signature begins with `'<'` to indicate type variable declarations.

      Returns:
        `true` if the class signature contains generic type parameters

    - #### public boolean isResolved()

      Reports that this class node is fully resolved from bytecode. Decompiled classes are always resolved, unlike source-based classes which may be unresolved during compilation.

      Returns:
        always `true` for decompiled classes

    - #### public boolean isSealed()

      Determines if this class is sealed, checking both Java sealed class annotations and Groovy `@Sealed` transform annotations.

      Returns:
        `true` if the class is declared as sealed with either Java or Groovy mechanisms

    - #### public boolean isUsingGenerics()

      Indicates whether this class is using generic types. Triggers lazy initialization of generic type information.

      Returns:
        `true` if the class uses generic type parameters

    - #### public void setGenericsPlaceHolder(boolean b)

      Prevents marking decompiled class nodes as generic placeholders.

      throws:
        UnsupportedOperationException always, as bytecode classes are immutable
      Parameters:
        `b` - ignored

    - #### public String setName(String name)

      Prevents renaming of decompiled class nodes, as they represent immutable bytecode definitions.

      throws:
        UnsupportedOperationException always, as bytecode classes are immutable
      Parameters:
        `name` - ignored
      Returns:
        never returns normally

    - #### public void setRedirect(ClassNode cn)

      Prevents redirection of decompiled class nodes to alternate implementations.

      throws:
        UnsupportedOperationException always, as bytecode classes cannot be redirected
      Parameters:
        `cn` - ignored

    - #### public void setUsingGenerics(boolean b)

      Prevents modification of generic type usage for decompiled class nodes.

      throws:
        UnsupportedOperationException always, as bytecode classes are immutable
      Parameters:
        `b` - ignored