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 (UnresolvedElementsSubProcessor → CompletionEngine). 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
Environment
Description
When
@Builderand@Jacksonizedare combined on an inner class of asealed interface, JDT'sCompletionParserinvokes Lombok annotationhandlers via
visitAnnotationOnFieldwith aCompletionOnFieldTypenodeinstead of a
TypeDeclarationnode. This causes aClassCastExceptionin
lombok.eclipse.handlers.HandleValuewhich cascades into falsecompilation errors reported by JDT on the affected file.
The
CompletionParserbuilds a partial AST when resolving quick fixproposals (
UnresolvedElementsSubProcessor→CompletionEngine). Inthis context, field type nodes are represented as
CompletionOnFieldTypeinstances (which extend
TypeReference) rather thanTypeDeclaration.Lombok's
TransformEclipseASTis invoked on this partial AST viatransform_swapped, and itsAnnotationVisitorcallsvisitAnnotationOnFieldwith these partial nodes, which Lombok handlersdo not expect.
This has been reported to the Lombok project as issue
projectlombok/lombok#4051, where a fix via
instanceofguard inHandleValueis proposed. However the root questionis whether the
CompletionParsershould be invoking Lombok's transformon a partial AST at all, or whether JDT should guard against passing
incomplete AST nodes to annotation processors in this path.
Impact
HandleValuecrashes repeatedly on every autocompletion and quick fixattempt on the affected file
cannot be resolved to a type)on Jackson annotations in the affected class, cascading from the crash
as having compilation errors
mvn compilesucceeds without errorsStack trace
Minimal reproducer
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/CompletionEnginebe invokingTransformEclipseAST.transform_swapped(the Lombok AST transform entrypoint) on a partial AST? If the answer is no, a guard in
CompletionParser.endParsebefore invoking any registered AST transformswould prevent this class of issue generically, rather than requiring every
Lombok handler to individually guard against partial AST nodes.
Related
[BUG] Internal package changes in ECJ will break Lombok. projectlombok/lombok#3564
(originally filed on eclipse-jdtls)