micronaut-projects / micronaut-core

Micronaut Application Framework
http://micronaut.io
Apache License 2.0
6.1k stars 1.07k forks source link

@Inject fields in abstract classes not properly injected #7922

Open rsenden opened 2 years ago

rsenden commented 2 years ago

Expected Behavior

In our Micronaut/Picocli based command line application, we have multiple abstract classes containing fields annotated with @Inject. These abstract classes are used as base classes for concrete Picocli @Command implementations. We'd expect Micronaut to properly inject these fields with the corresponding @Singleton instances.

Actual Behaviour

Steps To Reproduce

  1. Clone sample project https://github.com/rsenden/micronaut-inject-issue
  2. Run ./gradlew clean shadowJar
  3. Run java -jar build/libs/mncli.jar annotated-superclass; outputs Singleton called
  4. Run java -jar build/libs/mncli.jar annotated-subclass; outputs Singleton called
  5. Run java -jar build/libs/mncli.jar field-annotation; outputs Singleton called
  6. Run java -jar build/libs/mncli.jar no-annotation; fails with NPE because singleton was not injected
  7. Run java -jar build/libs/mncli.jar standard-annotation; fails with NPE because singleton was not injected

Environment Information

Example Application

https://github.com/rsenden/micronaut-inject-issue

Version

3.4.2

rsenden commented 2 years ago

This seems to be somewhat related to the following block in build.gradle:

micronaut {
    testRuntime("junit5")
    processing {
        incremental(true)
        annotations("org.sample.micronaut.*")
    }
}

The annotations option in combination with our custom annotations seems to make Micronaut properly process class hierarchies that have any of our custom annotations. Removing the annotations option makes the other commands (with our custom annotations) fail as well.

However, I'd expect Micronaut to automatically pick up any jakarta.inject annotations independent of whether there are any custom annotations defined in the class hierarchy. Also, removing the annotations option (just in case we are overriding some defaults like jakarta.inject.*), or explicitly specifying annotations("jakarta.inject.*") doesn't fix the issue.

qolsoftware commented 1 year ago

I ran into a similar problem. I discovered if the abstract class has an @Inject field, that doesn't make the subclass a Micronaut bean. You need to either add an @Inject field to the subclass or make it @Singleton or @Prototype.