rewrite icon indicating copy to clipboard operation
rewrite copied to clipboard

Annotating method with `lombok.Generated` causes parser failure

Open protocol7 opened this issue 7 months ago • 2 comments

What version of OpenRewrite are you using?

org.openrewrite:rewrite-core:8.53.0

What is the smallest, simplest way to reproduce the problem?

When a method is annotated with lombok.Generated the parser will fail. We had this with a source code file, likely originating from delombok. Here's a test case:

  @Test
  void lombokGeneratedParsing() {
    rewriteRun(
        java(
            """
            import lombok.Generated;

            public class Foo {

              @Generated
              public void foo() {}
            }
            """));
  }

This fails with:

java.lang.AssertionError: Source file was parsed into an LST that contains non-whitespace characters in its whitespace. This is indicative of a bug in the parser.
import lombok.Generated;

public class Foo {~~(non-whitespace)~~>

  @Generated
  public void foo() {<~~}~~(non-whitespace)~~>
}<~~
	at org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:324)
	at org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:130)
	at org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:125)

In our rewrites, this generated invalid code, causing compilation failures.

protocol7 avatar May 24 '25 09:05 protocol7

Thanks! That's quite unexpected usage here. I suspect it's caused by our Lombok annotation handling, but would have to run your test to see what's going on. Is this a common pattern over there or did you already phase out what limited usage there was?

timtebeek avatar May 27 '25 15:05 timtebeek

This is rare and we have removed them, so not blocking for us. Sharing here to help improve the parser.

protocol7 avatar May 27 '25 16:05 protocol7

Indeed using @lombok.Generated manually like this is not typical / not expected usage. It's intended to be added by Lombok itself to generated methods (e.g., via @Setter, @Getter, etc.).

I've checked whether there's a reliable way to distinguish between @lombok.Generated annotations that are applied by Lombok vs ones written manually in source code, but unfortunately, I couldn't find solution..

I hoped that synthesized flag could help, but seems it is false in both cases.

e5LA avatar Jul 01 '25 20:07 e5LA

@timtebeek Seems I faced a similar issue. The run of recipe org.openrewrite.java.format.TabsAndIndents causes deleting the public modifier from class marked by lombok.Generated annotation. Before: @Generated public class Test

After: @Generated class Test

Also in combination with others: org.openrewrite.java.format.Spaces, org.openrewrite.java.format.RemoveTrailingWhitespace, org.openrewrite.java.format.NormalizeTabsOrSpaces It causes deleting @Generated annotation itslef.

Are there any workarounds?

onekzy avatar Jul 23 '25 16:07 onekzy

@onekzy if you're seeing code changes then it's a different issue: when there are parser issues as seen above there would be no code changes. In your case you can either configure excludes in your Maven or Gradle plugin, or use preconditions to stop changes to those files. Either works; the first stops parsing those files, while the second stops changes to parsed files.

timtebeek avatar Jul 23 '25 16:07 timtebeek

@timtebeek Thanks for the quick response.

I would like the recipes to apply to these files, but without unexpected behavior, just what the recipe promises. Removing the public modifier and the annotation itself should not happen as part of the indentation normalization recipe.

I think this should be considered a separate bug.

onekzy avatar Jul 23 '25 17:07 onekzy

@timtebeek same problem for us

if you're seeing code changes then it's a different issue: when there are parser issues as seen above there would be no code changes

I think it's the same issue.
In issue description, you see no code changes because there is some controls when running Unit tests in RewriteTest. But when you run a recipe, this control does not exist, and as described @onekzy, it remove other annotations and/or modifiers.

Example running RemoveTrailingWhitespace recipe on a class with lombok.Generated annotation :

Image

philippe-granet avatar Aug 04 '25 22:08 philippe-granet

Hmm; thanks for that added context; guess we could see if we can tolerate & retain those annotations even when unexpected.

https://github.com/openrewrite/rewrite/blob/8ce5308a9557dd6ca91253a5c8fb7e6c34a0ef5a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java#L2048-L2067

When I run the test provided above I see the following failure:

java.lang.AssertionError: Source file was parsed into an LST that contains non-whitespace characters in its whitespace. This is indicative of a bug in the parser. 
import lombok.Generated;

public class Foo {~~(non-whitespace)~~>

  @Generated
  public void foo() {<~~}~~(non-whitespace)~~>
}<~~

That indeed hints at a parser issue that could see those elements perhaps printed correctly at first, but then later removed.

timtebeek avatar Aug 04 '25 22:08 timtebeek