Skip to content

[BUG] CompletionParser invokes Lombok annotation handlers with partial AST node (CompletionOnFieldType) causing ClassCastException cascade #3825

Description

@clementb49

Environment

  • Jackson: 3.1.4
  • JDT Language Server: 1.59.0-SNAPSHOT (OSGi 1.59.0.202606241329, commit ab9b695)
  • Lombok: 1.18.46
  • JDK: 21.0.11 (Eclipse Adoptium)
  • VSCode Java extension (redhat.java)
  • OS: Linux x86_64

Description

When @Builder and @Jacksonized are combined on an inner class of a
sealed interface, JDT's CompletionParser invokes Lombok annotation
handlers via visitAnnotationOnField with a CompletionOnFieldType node
instead of a TypeDeclaration node. This causes a ClassCastException
in lombok.eclipse.handlers.HandleValue which cascades into false
compilation errors reported by JDT on the affected file.

The CompletionParser builds a partial AST when resolving quick fix
proposals (UnresolvedElementsSubProcessorCompletionEngine). In
this context, field type nodes are represented as CompletionOnFieldType
instances (which extend TypeReference) rather than TypeDeclaration.
Lombok's TransformEclipseAST is invoked on this partial AST via
transform_swapped, and its AnnotationVisitor calls
visitAnnotationOnField with these partial nodes, which Lombok handlers
do not expect.

This has been reported to the Lombok project as issue
projectlombok/lombok#4051, where a fix via
instanceof guard in HandleValue is proposed. However the root question
is whether the CompletionParser should be invoking Lombok's transform
on a partial AST at all, or whether JDT should guard against passing
incomplete AST nodes to annotation processors in this path.

Impact

  • HandleValue crashes repeatedly on every autocompletion and quick fix
    attempt on the affected file
  • JDT reports false compilation errors (cannot be resolved to a type)
    on Jackson annotations in the affected class, cascading from the crash
  • The VSCode debug launch is blocked because JDT considers the project
    as having compilation errors
  • mvn compile succeeds without errors

Stack trace

!ENTRY org.eclipse.jdt.core 4 0 2026-06-26 13:56:59.246
!MESSAGE Lombok annotation handler class lombok.eclipse.handlers.HandleValue failed
!STACK 0
java.lang.ClassCastException: class org.eclipse.jdt.internal.codeassist.complete.CompletionOnFieldType
cannot be cast to class org.eclipse.jdt.internal.compiler.ast.TypeDeclaration
(org.eclipse.jdt.internal.codeassist.complete.CompletionOnFieldType is in unnamed module of loader
org.eclipse.osgi.internal.loader.EquinoxClassLoader @222140f1;
org.eclipse.jdt.internal.compiler.ast.TypeDeclaration is in unnamed module of loader
org.eclipse.osgi.internal.loader.EquinoxClassLoader @4d4271d6)
    at lombok.eclipse.handlers.HandleValue.handle(HandleValue.java:66)
    at lombok.eclipse.HandlerLibrary$AnnotationHandlerContainer.handle(HandlerLibrary.java:106)
    at lombok.eclipse.HandlerLibrary.handleAnnotation(HandlerLibrary.java:237)
    at lombok.eclipse.TransformEclipseAST$AnnotationVisitor.visitAnnotationOnField(TransformEclipseAST.java:249)
    at lombok.eclipse.EclipseNode.traverse(EclipseNode.java:110)
    at lombok.eclipse.EclipseAST.traverseChildren(EclipseAST.java:232)
    at lombok.eclipse.EclipseNode.traverse(EclipseNode.java:79)
    at lombok.eclipse.EclipseAST.traverseChildren(EclipseAST.java:232)
    at lombok.eclipse.EclipseNode.traverse(EclipseNode.java:74)
    at lombok.eclipse.EclipseAST.traverseChildren(EclipseAST.java:232)
    at lombok.eclipse.EclipseNode.traverse(EclipseNode.java:69)
    at lombok.eclipse.EclipseAST.traverse(EclipseAST.java:225)
    at lombok.eclipse.TransformEclipseAST.go(TransformEclipseAST.java:226)
    at lombok.eclipse.TransformEclipseAST.transform(TransformEclipseAST.java:187)
    at lombok.eclipse.TransformEclipseAST.transform_swapped(TransformEclipseAST.java:104)
    at org.eclipse.jdt.internal.compiler.parser.Parser.endParse(Parser.java:10537)
    at org.eclipse.jdt.internal.codeassist.complete.CompletionParser.endParse(CompletionParser.java:6302)
    at org.eclipse.jdt.internal.compiler.parser.Parser.parse(Parser.java:11729)
    at org.eclipse.jdt.internal.codeassist.CompletionEngine.complete(CompletionEngine.java:1996)
    at org.eclipse.jdt.internal.core.Openable.codeComplete(Openable.java:139)
    at org.eclipse.jdt.ls.core.internal.corrections.proposals.UnresolvedElementsSubProcessor
         .collectTypeProposals(UnresolvedElementsSubProcessor.java:330)
    at org.eclipse.jdt.ls.core.internal.handlers.CodeActionHandler
         .getCodeActionCommands(CodeActionHandler.java:204)

Minimal reproducer

import lombok.Builder;
import lombok.extern.jackson.Jacksonized;

public sealed interface MyInterface permits MyInterface.MyInnerDTO {

    @Builder
    @Jacksonized
    class MyInnerDTO implements MyInterface {
        String field;
    }
}

Open the file in VSCode and trigger autocompletion or a quick fix.
The crash occurs immediately and repeats on every completion attempt.

Question for JDT team

Should CompletionParser / CompletionEngine be invoking
TransformEclipseAST.transform_swapped (the Lombok AST transform entry
point) on a partial AST? If the answer is no, a guard in
CompletionParser.endParse before invoking any registered AST transforms
would prevent this class of issue generically, rather than requiring every
Lombok handler to individually guard against partial AST nodes.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions