aws / serverless-java-container

A Java wrapper to run Spring, Spring Boot, Jersey, and other apps inside AWS Lambda.
https://aws.amazon.com/serverless/
Apache License 2.0
1.5k stars 561 forks source link

Cannot invoke "org.springframework.web.servlet.DispatcherServlet.getServletContext()" because "servlet" is null #828

Open fabiencoppens opened 7 months ago

fabiencoppens commented 7 months ago

To help us debug your issue fill in the basic information below using the options provided

Serverless Java Container version: 2.0.1

Implementations: Spring Boot

Framework version: Spring Boot 3.2.2

Frontend service: HTTP API (Spring GraphQl)

Deployment method: Local Docker image with AWS RIE runtime interface emulator

Scenario

I'm running a Spring Boot 3 based Lambda packaged as a Docker image and testing it via the RIE, as described here https://docs.aws.amazon.com/lambda/latest/dg/images-test.html#images-test-alt I'm using aws-serverless-java-container-springboot3 v2.0.1 Using the SpringDelegatingLambdaContainerHandler

Environment variables used: MAIN_CLASS="com.acme.ist.ebs.polaris.payschedules.Application" SPRING_PROFILES_ACTIVE="dev" DB_PASSWORD="redacted"

Expected behavior

I would expect the serverless container to properly bootstrap the Spring application context

Actual behavior

Caused by: java.lang.NullPointerException: Cannot invoke "org.springframework.web.servlet.DispatcherServlet.getServletContext()" because "servlet" is null at org.springframework.cloud.function.serverless.web.ServerlessMVC$ProxyFilterChain.(ServerlessMVC.java:224) at org.springframework.cloud.function.serverless.web.ServerlessMVC.service(ServerlessMVC.java:167) at org.springframework.cloud.function.serverless.web.ServerlessMVC.service(ServerlessMVC.java:163) at com.amazonaws.serverless.proxy.spring.AwsSpringHttpProcessingUtils.processRequest(AwsSpringHttpProcessingUtils.java:51)

Steps to reproduce

Environment variables used: MAIN_CLASS="com.acme.ist.ebs.polaris.payschedules.Application" SPRING_PROFILES_ACTIVE="dev" DB_PASSWORD="redacted"

Dockerfile entrypoint: ENTRYPOINT [ "/entry_script.sh","com.amazonaws.serverless.proxy.spring.SpringDelegatingLambdaContainerHandler" ]

docker build --platform linux/amd64 -t latest . docker run --platform linux/amd64 -p 9000:8080 latest

curl "http://localhost:9000/2015-03-31/functions/function/invocations" -H "Content-Type: application/json" -X POST -d '{}'

Full log output

Exception in thread "Thread-0" java.lang.IllegalStateException: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'payScheduleServiceImpl' defined in URL [jar:file:/usr/src/app/app.jar!/com/acme/ist/ebs/polaris/payschedules/service/PayScheduleServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'com.acme.ist.ebs.polaris.payschedules.repository.PayScheduleRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} at org.springframework.cloud.function.serverless.web.ServerlessMVC.lambda$initializeContextAsync$1(ServerlessMVC.java:116) at java.base/java.lang.Thread.run(Unknown Source) Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'payScheduleServiceImpl' defined in URL [jar:file:/usr/src/app/app.jar!/com/acme/ist/ebs/polaris/payschedules/service/PayScheduleServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'com.acme.ist.ebs.polaris.payschedules.repository.PayScheduleRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:801) at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:240) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1350) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:558) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:518) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:950) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:746) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:448) at org.springframework.boot.SpringApplication.run(SpringApplication.java:324) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1321) at org.springframework.cloud.function.serverless.web.ServerlessMVC.initContext(ServerlessMVC.java:126) at org.springframework.cloud.function.serverless.web.ServerlessMVC.lambda$initializeContextAsync$1(ServerlessMVC.java:113) ... 1 more Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.acme.ist.ebs.polaris.payschedules.repository.PayScheduleRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1824) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1383) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1337) at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:910) at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:788) ... 19 more %d [%thread] %-5level %logger - %msg%n org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'payScheduleServiceImpl' defined in URL [jar:file:/usr/src/app/app.jar!/com/acme/ist/ebs/polaris/payschedules/service/PayScheduleServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'com.acme.ist.ebs.polaris.payschedules.repository.PayScheduleRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:801) ~[app.jar:?] at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:240) ~[app.jar:?] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1350) ~[app.jar:?] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187) ~[app.jar:?] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:558) ~[app.jar:?] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:518) ~[app.jar:?] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) ~[app.jar:?] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[app.jar:?] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) ~[app.jar:?] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[app.jar:?] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) ~[app.jar:?] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:950) ~[app.jar:?] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) ~[app.jar:?] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:746) ~[app.jar:?] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:448) ~[app.jar:?] at org.springframework.boot.SpringApplication.run(SpringApplication.java:324) ~[app.jar:?] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1321) ~[app.jar:?] at org.springframework.cloud.function.serverless.web.ServerlessMVC.initContext(ServerlessMVC.java:126) ~[app.jar:?] at org.springframework.cloud.function.serverless.web.ServerlessMVC.lambda$initializeContextAsync$1(ServerlessMVC.java:113) ~[app.jar:?] at java.lang.Thread.run(Unknown Source) [?:?] Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.acme.ist.ebs.polaris.payschedules.repository.PayScheduleRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1824) ~[app.jar:?] at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1383) ~[app.jar:?] at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1337) ~[app.jar:?] at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:910) ~[app.jar:?] at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:788) ~[app.jar:?] ... 19 more java.lang.NullPointerException: Cannot invoke "org.springframework.web.servlet.DispatcherServlet.getServletContext()" because "servlet" is null at org.springframework.cloud.function.serverless.web.ServerlessMVC$ProxyFilterChain.(ServerlessMVC.java:224) at org.springframework.cloud.function.serverless.web.ServerlessMVC.service(ServerlessMVC.java:167) at org.springframework.cloud.function.serverless.web.ServerlessMVC.service(ServerlessMVC.java:163) at com.amazonaws.serverless.proxy.spring.AwsSpringHttpProcessingUtils.processRequest(AwsSpringHttpProcessingUtils.java:51) at com.amazonaws.serverless.proxy.spring.SpringDelegatingLambdaContainerHandler.handleRequest(SpringDelegatingLambdaContainerHandler.java:68) at com.amazonaws.services.lambda.runtime.api.client.EventHandlerLoader$2.call(EventHandlerLoader.java:907) at com.amazonaws.services.lambda.runtime.api.client.AWSLambda.startRuntime(AWSLambda.java:239) at com.amazonaws.services.lambda.runtime.api.client.AWSLambda.startRuntime(AWSLambda.java:191) at com.amazonaws.services.lambda.runtime.api.client.AWSLambda.main(AWSLambda.java:181) java.lang.NullPointerException: Cannot invoke "org.springframework.web.servlet.DispatcherServlet.getServletContext()" because "servlet" is null: java.lang.IllegalStateException java.lang.IllegalStateException: java.lang.NullPointerException: Cannot invoke "org.springframework.web.servlet.DispatcherServlet.getServletContext()" because "servlet" is null at com.amazonaws.serverless.proxy.spring.AwsSpringHttpProcessingUtils.processRequest(AwsSpringHttpProcessingUtils.java:61) at com.amazonaws.serverless.proxy.spring.SpringDelegatingLambdaContainerHandler.handleRequest(SpringDelegatingLambdaContainerHandler.java:68) Caused by: java.lang.NullPointerException: Cannot invoke "org.springframework.web.servlet.DispatcherServlet.getServletContext()" because "servlet" is null at org.springframework.cloud.function.serverless.web.ServerlessMVC$ProxyFilterChain.(ServerlessMVC.java:224) at org.springframework.cloud.function.serverless.web.ServerlessMVC.service(ServerlessMVC.java:167) at org.springframework.cloud.function.serverless.web.ServerlessMVC.service(ServerlessMVC.java:163) at com.amazonaws.serverless.proxy.spring.AwsSpringHttpProcessingUtils.processRequest(AwsSpringHttpProcessingUtils.java:51) ... 1 more

olegz commented 7 months ago

I am a bit puzzled by this error as I can not reproduce it, while it seems like few have already reproduced it. Perhaps I am missing something with regard to some specific configuration, so a sample app that reproduces it would help. The DispatcherServlet's ServletContext should me automatically set during the initialisation of application context, so the fact that it doesn't makes me wonder. I'll keep looking but if someone can produce a sample app that reproduces the issue it would help.

olegz commented 7 months ago

@fabiencoppens please see this comment https://github.com/aws/serverless-java-container/issues/770#issuecomment-2074977920 Please help me understand what is going on as I can not reproduce it

mircohacker commented 7 months ago

Hey @fabiencoppens I had the same error when I forgot to exclude the spring-boot-starter-tomcat from the jar deployed to Lambda. Maybe this helps you or any other person stumbling upon this issue 🤷

jahidmomin commented 5 months ago

@fabiencoppens please try this

handler = new SpringBootProxyHandlerBuilder<AwsProxyRequest>() .defaultProxy() .servletApplication() .asyncInit() .springBootApplication(GoalMainApplication.class) .buildAndInitialize();