Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lombok + @Introspected generates incorrect parameter names #1566

Closed
achaphiv opened this issue Apr 20, 2019 · 19 comments · Fixed by projectlombok/lombok#2497
Closed

Lombok + @Introspected generates incorrect parameter names #1566

achaphiv opened this issue Apr 20, 2019 · 19 comments · Fixed by projectlombok/lombok#2497
Labels
status: awaiting third-party Awaiting changes to a third party library

Comments

@achaphiv
Copy link

Summary

The TLDR is that this simple class

@Introspected
@Value
public class Payload {
  private final String id;
}

leads to different parameter names:

// id
Payload.class.getConstructors()[0].getParameters()[0].getName();

// arg0
BeanIntrospection.getIntrospection(Payload.class).getConstructorArguments()[0].getName();

The longer version is that a application.yml:

jackson:
    bean-introspection-module: true

and a controller:

  @Post
  public String create(@Body Payload body) {
    return body.getId();
  }

fails when doing:

POST /bad

{
  "id": "123"
}

with a stack trace like:

io.micronaut.http.client.exceptions.HttpClientResponseException: Failed to convert argument [body] for value [null] due to: Cannot construct instance of `micronaut.introspection.issue.Payload`, problem: Null argument specified for [arg0]. If this argument is allowed to be null annotate it with @Nullable
     at [Source: UNKNOWN; line: -1, column: -1]

It fails in both gradle and maven.

Strangely, it works in eclipse.

Steps to Reproduce

  1. git clone https://github.com/achaphiv/micronaut-introspection-issue
  2. ./gradlew test -i or ./mvnw test

Expected Behaviour

Tests should pass.

Actual Behaviour

Tests fail.

Environment Information

  • Operating System: Mac & Linux
  • Micronaut Version: 1.1.0
  • JDK Version: 1.8.0_202 & 1.8.0_191

Example Application

https://github.com/achaphiv/micronaut-introspection-issue

@jameskleeh
Copy link
Contributor

Pretty sure this is an issue with Lombok. When we are reading the class the parameter name is not there

@graemerocher
Copy link
Contributor

We can only process what Lombok gives us. This seems to be a Lombok issue as it @Value is not translating id into a named constructor parameter. Probably worth a report to https://github.com/rzwitserloot/lombok/issues

@rspilker
Copy link

Possibly the problem is that both annotation processors are in the same round. Together with MapStruct, we've been working on a way to have multiple annotation processors that have to run in a specific order, including to run in a next round. Could this be the case here as well?

Alternatively, did someone try to generate a java file using an annotation processor that contains the @Introspected annotation? I see that the example project passes the -parameters argument, but I don't know if javac itself also passes that information to annotation processors for files that are generated.

@graemerocher
Copy link
Contributor

@rspilker MapStruct currently works with Micronaut, we had some issues with earlier versions, but they seem to be resolved now.

We currently write out bean definitions when processing is over https://github.com/micronaut-projects/micronaut-core/blob/master/inject-java/src/main/java/io/micronaut/annotation/processing/BeanDefinitionInjectProcessor.java#L219

However, in this case the issues appears to be that lombok is creating a constructor in the AST that is not representing the constructor arguments as the field name. The name of the constructor argument should be id instead it is arg0

How does lombok mutate the AST to produce this new node? When it does so does it use the field name to create the VariableElement that represents the constructor argument that is processed later downstream by Micronaut?

@asodja
Copy link
Contributor

asodja commented May 30, 2020

I have this issue too. First I though that this could be solved with java.beans.ConstructorProperties that Lombok can generate on constructor. Micronaut currently does not support reading that annotation, but it could. Although after some hacking Micronaut code I figured that annotations generated by Lombok are also not visible from on constructor.

@rspilker do you have any hint how this could be solved for Micronaut?

@asodja
Copy link
Contributor

asodja commented May 30, 2020

It seems that this is a Micronaut's issue. I hacked Micronaut code a bit and enabled IntrospectedTypeElementVisitor only when roundEnv.processingOver(). Code change can be seen here: asodja@9636b77.

If you run LombokIntrospectedClass you can see in build directory that $LombokIntrospectedClass$Introspection.getConstructorArguments() has constructor argument names correctly populated (also annotation java.beans.ConstructorProperties that is generated by Lombok if enabled can be read from constructor).

Although in this case IntrospectionException: No bean introspection available for type exception is thrown since it seems Bean definition is not written.

@graemerocher
Copy link
Contributor

Annotation processor order is important. The Lombok processor needs to be declared before the Micronaut one so that it runs first

@asodja
Copy link
Contributor

asodja commented May 30, 2020

In case, when you use Lombok's @AllArgsConstructor or @RequiredArgsConstructor and Micronaut's @Introspected there is an issue even if you have processors ordered correctly. Micronaut finds created constructor, but when doing Bean Introspection constructor argument names are: arg0, arg1 etc.

Simple reproducer: https://github.com/asodja/micronaut-lombok-reproducer.

I think MapStruct has similar issues and has special interface that is implemented by Lombok:
https://github.com/mapstruct/mapstruct/blob/12bfff8f46c00b22c384f9441d2928b2e588406d/processor/src/main/java/org/mapstruct/ap/spi/AstModifyingAnnotationProcessor.java. With that it can wait a round before visiting the type that is handled by Lombok.

@dstepanov
Copy link
Contributor

I have similar issue with adding @Named("xyz") to a field and adding lombok.copyableAnnotations += javax.inject.Named in lombok.config.

I can see the disassembled file is correctly generated by Lombok by Micronaut's classes are missing the annotation and fields with lost names.

It would be nice to have it working.

@dstepanov
Copy link
Contributor

I did some investigation and it looks like a new constructor generated in Lombok doesn't have parameter names and annotations but if the processing is deferred to the next round they are present.

@rspilker Any idea why is this happening? Doesn't look like it's Micronaut related, the processing order is correct otherwise there wouldn't be a constructor present.

@graemerocher I have a possible solution to defer introspected processing for classes with Lombok dstepanov@27f71c7

@graemerocher
Copy link
Contributor

Interesting, seems a bit hacky, would be interested to hear @rspilker comments on this

@asodja
Copy link
Contributor

asodja commented Jun 20, 2020

Maybe it's worth reading: mapstruct/mapstruct#510 (comment) (and other comments in this issue). It seems like similar issue.

Tl;dr of how they solved it can be found here: projectlombok/lombok#973 (comment)

@dstepanov
Copy link
Contributor

Found the problem to be in Lombok projectlombok/lombok#2497

@graemerocher
Copy link
Contributor

Thanks for the looking into that @dstepanov I don't personally think we should place hacks into Micronaut to workaround issues in Lombok so would greatly prefer this to be fixed upstream

@jameskleeh
Copy link
Contributor

This was fixed upstream

@altery
Copy link

altery commented Jul 30, 2020

Sorry to post to a closed Issue, but I discovered an unexpected behaviour that might of interest. I posted my findings in the lombok issue projectlombok/lombok#2497

Note: I do not use @introspected but @MappedEntity instead so it might not be the exact same issue.

@SchulteMarkus
Copy link

@altery Your latest post #1566 (comment) links back to this very post.
Endless loop 😱

@altery
Copy link

altery commented Jul 30, 2020

Thanks for noticing, @SchulteMarkus , the link is now corrected 🙈

@achaphiv
Copy link
Author

achaphiv commented Oct 15, 2020

Confirmed fixed with (finally released) lombok v1.18.16.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: awaiting third-party Awaiting changes to a third party library
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants