javamicronautmicronaut-aws

BeanInstantiationException when a class extends from MicronautRequestHandler


I am recursively getting below error when it's going to init the bean extends from MicronautRequestHandler. But it's not the case for other regular beans.

My simplified version of the Handler class as below : (I removed all the injected services as well to simplify)

package org.example;

import com.amazonaws.services.lambda.runtime.events.S3Event;
import io.micronaut.function.aws.MicronautRequestHandler;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;

@Singleton
public class Handler extends MicronautRequestHandler<S3Event, Void> {

    @Inject
    public Handler() {
        // NOP
    }

    @Override
    public Void execute(S3Event input) {
        System.out.println("Received S3 event: " + input);
        return null;
    }
}

To re-create this locally without Lambda, I created this main method. This is the minimal version of the main LocalRunner class, which still cause the issue.

   package org.example;

import io.micronaut.context.ApplicationContext;

public class LocalRunner {
    public static void main(String[] args) {
        // Start the Micronaut application context
        try (ApplicationContext context = ApplicationContext.run()) {
            // Instantiate your handler class
            Handler handler = context.getBean(Handler.class);
        }
    }

}

I am getting the same error when it deploy to Lambda and trigger with a S3Event.

My build gradle file:

plugins {
    id("application")
}

version = "0.1"
group = "org.example"

repositories {
    mavenCentral()
    maven { url "https://s01.oss.sonatype.org/content/repositories/releases/" }
}

dependencies {
    annotationProcessor("io.micronaut:micronaut-http-validation:3.10.0")
    annotationProcessor("io.micronaut:micronaut-inject-java:3.10.0")
    implementation('io.micronaut.aws:micronaut-function-aws:3.18.0')
    implementation("io.micronaut:micronaut-inject:3.10.0")
    implementation("io.micronaut:micronaut-http-server-netty:3.10.0")
    implementation("io.micronaut:micronaut-json-core:3.10.0")
    implementation("io.micronaut:micronaut-jackson-databind:3.10.0")
    implementation("jakarta.inject:jakarta.inject-api:2.0.1")
    implementation("com.amazonaws:aws-lambda-java-events:3.11.0")
    implementation("software.amazon.awssdk:s3:2.29.0")
    implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-csv:2.16.0")
    implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.16.0")

    // https://mvnrepository.com/artifact/org.slf4j/slf4j-api
    implementation 'org.slf4j:slf4j-api:1.2.13'
    //https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl
    runtimeOnly("org.apache.logging.log4j:log4j-to-slf4j:2.18.0") 

    //JDBC
    implementation 'com.amazon.redshift:redshift-jdbc42:2.1.0.9'
    implementation 'commons-dbcp:commons-dbcp:1.4'

}
configurations {
    all*.exclude group: 'ch.qos.logback'
    all*.exclude group: 'org.apache.logging.log4j', module: 'log4j-to-slf4j'
}
java {
    sourceCompatibility = JavaVersion.toVersion("17")
    targetCompatibility = JavaVersion.toVersion("17")
}

piece of the error log (repeating it many times):

Path Taken: new Handler()
    ... 1024 more
Caused by: io.micronaut.context.exceptions.BeanInstantiationException: Bean 
definition [org.example.Handler] could not be loaded:

//...

    at org.example.Handler.<init>(Handler.java:12)
    at org.example.$Handler$Definition.build(Unknown Source)
    at io.micronaut.context.DefaultBeanContext.resolveByBeanFactory(DefaultBeanContext.java:2354)
    at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:2305)
    at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:2251)
    at io.micronaut.context.DefaultBeanContext.createRegistration(DefaultBeanContext.java:3016)
    at io.micronaut.context.SingletonScope.getOrCreate(SingletonScope.java:80)
    at io.micronaut.context.DefaultBeanContext.findOrCreateSingletonBeanRegistration(DefaultBeanContext.java:2918)
    at io.micronaut.context.DefaultBeanContext.loadContextScopeBean(DefaultBeanContext.java:2746)
    at io.micronaut.context.DefaultBeanContext.initializeContext(DefaultBeanContext.java:1915)
    at io.micronaut.context.DefaultApplicationContext.initializeContext(DefaultApplicationContext.java:249)
    at io.micronaut.context.DefaultBeanContext.readAllBeanDefinitionClasses(DefaultBeanContext.java:3326)
    at io.micronaut.context.DefaultBeanContext.finalizeConfiguration(DefaultBeanContext.java:3684)
    at io.micronaut.context.DefaultBeanContext.start(DefaultBeanContext.java:341)
    at io.micronaut.context.DefaultApplicationContext.start(DefaultApplicationContext.java:194)
    at io.micronaut.function.executor.AbstractExecutor.startEnvironment(AbstractExecutor.java:124)
    at io.micronaut.function.aws.MicronautRequestHandler.buildApplicationContext(MicronautRequestHandler.java:222)
    at io.micronaut.function.aws.MicronautRequestHandler.<init>(MicronautRequestHandler.java:108)
    at org.example.Handler.<init>(Handler.java:12)
    at org.example.$Handler$Definition.build(Unknown Source)
    at io.micronaut.context.DefaultBeanContext.resolveByBeanFactory(DefaultBeanContext.java:2354)
    at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:2305)
    at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:2251)
    at io.micronaut.context.DefaultBeanContext.createRegistration(DefaultBeanContext.java:3016)
    at io.micronaut.context.SingletonScope.getOrCreate(SingletonScope.java:80)
    at io.micronaut.context.DefaultBeanContext.findOrCreateSingletonBeanRegistration(DefaultBeanContext.java:2918)
    at io.micronaut.context.DefaultBeanContext.loadContextScopeBean(DefaultBeanContext.java:2746)
    at io.micronaut.context.DefaultBeanContext.initializeContext(DefaultBeanContext.java:1915)
    at io.micronaut.context.DefaultApplicationContext.initializeContext(DefaultApplicationContext.java:249)
    at io.micronaut.context.DefaultBeanContext.readAllBeanDefinitionClasses(DefaultBeanContext.java:3326)
    at io.micronaut.context.DefaultBeanContext.finalizeConfiguration(DefaultBeanContext.java:3684)
    at io.micronaut.context.DefaultBeanContext.start(DefaultBeanContext.java:341)
    at io.micronaut.context.DefaultApplicationContext.start(DefaultApplicationContext.java:194)
    at io.micronaut.function.executor.AbstractExecutor.startEnvironment(AbstractExecutor.java:124)
    at io.micronaut.function.aws.MicronautRequestHandler.buildApplicationContext(MicronautRequestHandler.java:222)
    at io.micronaut.function.aws.MicronautRequestHandler.<init>(MicronautRequestHandler.java:108)
    at org.example.Handler.<init>(Handler.java:12)

resolveByBeanFactory() is trying again to initialize the constructor , so it's recursively go in the circle.

UPDATE

I was able to re-create the issue with a fresh IntelliJ-Micronaut default project (Java 17, Micronaut 4.4.2) with 3 simple steps.

  1. Append these 2 dependencies to your build.gradle
implementation('io.micronaut.aws:micronaut-function-aws')
implementation("com.amazonaws:aws-lambda-java-events:3.11.0")
  1. Add the above simple Handler class
  2. Add these 2 lines to your Application.java after Micronaut.run
public class Application {

   public static void main(String[] args) {
       Micronaut.run(Application.class, args);
       try (ApplicationContext context = ApplicationContext.run()) {
           Handler handler = context.getBean(Handler.class);
       }
   }
}

Solution

  • I finally found the issue. A tiny little mistake cause this all :-(

    Never Use @Singleton on the Lambda Handler class!

    Here’s why:

    In Micronaut, @Singleton registers the class as a bean in the application context, which works well for services and other components. However, the Lambda Handler class (which extends MicronautRequestHandler here) shouldn’t be a singleton, as it is treated differently from other beans. Using @Singleton on the handler can lead to initialization issues and cause dependency injection to fail.

    Solution:

    Simply remove the @Singleton annotation from your handler class, and let Micronaut handle it as a Lambda function rather than as an application bean.