Micronaut-core: Stack overflow in annotations processor during a build

Created on 25 Jan 2021  路  12Comments  路  Source: micronaut-projects/micronaut-core

After upgrading my project to 2.3.0, works well in 2.2.3. Build logs are included in the attachment.

gradle-shadowjar.log

high example attached bug

All 12 comments

A reproducible example would be nice

@l0co I would need an example here to debug this. Can you provide one? I'd like to get this fixed asap

I have some delay in the project right now I need to catch up but I'm gonna try to reproduce it and get back to you.

@l0co Have you had any time to create a reproducer? Should be an easy fix. 2.3.3 should be out in a couple days

@jameskleeh Unfortunately not, still busy. But I can do a quick check what's going on. Here it's:

The problem goes from AbstractJavaElement.mirrorToClassElement() which is called endlessly with the same arguments (bound is resolved to the same value as returnType):

image

Here is the context:

image

Nothing special about BaseSoftDeletableEntityService, it's not even a bean, just a base class for beans:

public class BaseSoftDeletableEntityService<T extends BaseSoftDeletableEntity, R extends BaseSoftDeletableEntityRepository<T>> extends BaseEntityService<T, R> {

    public BaseSoftDeletableEntityService(R repository) {
        super(repository);
    }

    public T delete(@Nonnull T entity) {
            // ...
    }

    public T undelete(@Nonnull T entity) {
            // ...
    }

}

Note, that derived beans can be written in java or kotlin.

Just a quick cheat sheet how I've generated this is you will ask me for something more in the future:

  1. Add implementation "io.micronaut:micronaut-inject-java" to build.gradle
  2. Reload gradle deps and stop with breakpoint in AbstractJavaElement:181 with pass count = 2000.
  3. Follow https://stackoverflow.com/a/52186665/320761

@jameskleeh It would be good to have a clean howto about debugging micronaut annotations processing in docs.

The culprit is here, and I haven't added it to the source above :)

@Validated // <-------------------------------------------- the culprit
public class BaseSoftDeletableEntityService<T extends BaseSoftDeletableEntity, R extends BaseSoftDeletableEntityRepository<T>> extends BaseEntityService<T, R> {

    public BaseSoftDeletableEntityService(R repository) {
        super(repository);
    }

    public T delete(@Nonnull T entity) {
            // ...
    }

    public T undelete(@Nonnull T entity) {
            // ...
    }

}

I don't use @Validate there, but two other @Around advices. In such a scenario this class is processed as it was a bean (while it isn't - it's just a base class for beans) and $BaseSoftDeletableEntity$Introspection and other stuff is generated for this class by the annotations processor.

Now, looking at the code in AbstractJavaElement, which processes this element, because it expects the class under processing is a bean, it also expects that all generics are already resolved. This is not true for this class, and we still have unbound T parameter which causes infinite loop and stackoverflow error finally.

I've successfully reproduced this scenario here.

And the funny part... adding abstract to this class declaration fixes the problem :D

Caught the same problem with a similar inheritance / generic structure and use of @Introspected. Removing @Introspected on the base classes "solved" it for us for now, but obliviously it's not a real solution.

And the funny part... adding abstract to this class declaration fixes the problem :D

It makes sense since the class should not be a bean if its abstract

@l0co Thanks for the reproducer. Will be included in the next release coming this week

I can confirm the project is now properly built in 2.3.4.

Was this page helpful?
0 / 5 - 0 ratings