-
Notifications
You must be signed in to change notification settings - Fork 637
Description
Describe the bug
Using:
- Spring Boot
3.1.1 - Spring Cloud
2022.0.3(SCF4.0.3)
Related to org.springframework.cloud:spring-cloud-function-adapter-aws:
When running a Spring Cloud Function application on an AWS Lambda, AWSTypesMessageConverter seems to not be capable to correctly convert a JSON array body when the functions consume a Flux<T>, where T is a regular application domain class/POJO.
The domain class:
public record GeoLocation(Float latitude, Float longitude) {}The function definition:
@Configuration
public class WeatherFunctions {
@Bean
public Function<Flux<GeoLocation>, Flux<Forecast>> forecast(WeatherService weatherService) {
return weatherService::getForecast;
}
}When invoking the AWS Lambda function with a body such as
[
{
"latitude": 42.99,
"longitude": 2.83
}
]It fails with the following Jackson conversion error:
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 2023-06-25T14:07:34.526Z WARN 9 --- [pool-5-thread-1] s.c.f.c.c.SmartCompositeMessageConverter : Failure during type conversion by org.springframework.cloud.function.adapter.aws.AWSTypesMessageConverter@7e33992. Will try the next converter.
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 java.lang.IllegalStateException: Failed to convert. Possible bug as the conversion probably shouldn't have been attempted here
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at org.springframework.cloud.function.json.JacksonMapper.doFromJson(JacksonMapper.java:65) ~[na:na]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at org.springframework.cloud.function.json.JsonMapper.fromJson(JsonMapper.java:66) ~[aws-lambda-spring-cloud-function-reactive-java:4.0.3]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at org.springframework.cloud.function.adapter.aws.AWSTypesMessageConverter.convertFromInternal(AWSTypesMessageConverter.java:90) ~[aws-lambda-spring-cloud-function-reactive-java:4.0.3]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at org.springframework.messaging.converter.AbstractMessageConverter.fromMessage(AbstractMessageConverter.java:185) ~[aws-lambda-spring-cloud-function-reactive-java:6.0.10]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at org.springframework.messaging.converter.AbstractMessageConverter.fromMessage(AbstractMessageConverter.java:176) ~[aws-lambda-spring-cloud-function-reactive-java:6.0.10]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at org.springframework.cloud.function.context.config.SmartCompositeMessageConverter.fromMessage(SmartCompositeMessageConverter.java:63) ~[na:na]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.convertInputMessageIfNecessary(SimpleFunctionRegistry.java:1353) ~[aws-lambda-spring-cloud-function-reactive-java:4.0.3]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.convertInputIfNecessary(SimpleFunctionRegistry.java:1106) ~[aws-lambda-spring-cloud-function-reactive-java:4.0.3]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.lambda$convertInputPublisherIfNecessary$24(SimpleFunctionRegistry.java:1465) ~[aws-lambda-spring-cloud-function-reactive-java:4.0.3]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:113) ~[na:na]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2545) ~[aws-lambda-spring-cloud-function-reactive-java:3.5.7]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:171) ~[na:na]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:171) ~[na:na]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:171) ~[na:na]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at reactor.core.publisher.FluxFlatMap$FlatMapMain.onSubscribe(FluxFlatMap.java:371) ~[aws-lambda-spring-cloud-function-reactive-java:3.5.7]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:96) ~[na:na]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:96) ~[na:na]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:96) ~[na:na]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at reactor.core.publisher.FluxJust.subscribe(FluxJust.java:68) ~[na:na]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at reactor.core.publisher.InternalFluxOperator.subscribe(InternalFluxOperator.java:62) ~[aws-lambda-spring-cloud-function-reactive-java:3.5.7]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at reactor.core.publisher.BlockingIterable.iterator(BlockingIterable.java:86) ~[na:na]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at org.springframework.cloud.function.adapter.aws.AWSLambdaUtils.generateOutputFromObject(AWSLambdaUtils.java:153) ~[na:na]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at org.springframework.cloud.function.adapter.aws.CustomRuntimeEventLoop.eventLoop(CustomRuntimeEventLoop.java:166) ~[na:na]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at org.springframework.cloud.function.adapter.aws.CustomRuntimeEventLoop.lambda$run$0(CustomRuntimeEventLoop.java:90) ~[na:na]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at java.base@17.0.5/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[aws-lambda-spring-cloud-function-reactive-java:na]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at java.base@17.0.5/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at java.base@17.0.5/java.lang.Thread.run(Thread.java:833) ~[aws-lambda-spring-cloud-function-reactive-java:na]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:775) ~[aws-lambda-spring-cloud-function-reactive-java:na]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at org.graalvm.nativeimage.builder/com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:203) ~[na:na]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `tech.aaregall.lab.function.weather.domain.GeoLocation` from Array value (token `JsonToken.START_ARRAY`)
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at [Source: (String)"[
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 {
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 "latitude": 42.99,
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 "longitude": 2.83
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 }
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 ]"; line: 1, column: 1]
2023/06/25/[$LATEST]2b2c53a6597a485481146cabafd1247e 2023-06-25T14:07:34.527000 at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1752) ~[aws-lambda-spring-cloud-function-reactive-java:2.15.2]
Nevertheless it works perfectly when the application is not running on AWS (locally, or on a Docker Image) being able to take more "geolocations" in the payload, which is the intention.
[
{
"latitude": 42.99,
"longitude": 2.83
},
{
"latitude": 43.01,
"longitude": 2.21
}
]Sample
I built a sample application to demonstrate the issue: https://github.com/ArnauAregall/aws-lambda-spring-cloud-function-reactive-java
If you clone and run the application locally:
$ ./gradlew nativeRun
$ curl -X POST -H "Content-Type: application/json" -d '[{"latitude": 41.34, "longitude": 2.78}]' http://localhost:8080/question | jq > response.jsonThe response.json file will be a JSON array containing a single object representing the weather forecast for those coordinates.
But when running in AWS:
$ ./aws-image/build-aws-image.sh
$ sam build --use-container --build-image tech.aaregall.lab/amazonlinux-graalvm:latest
$ export AWS_REGION=...
$ sam deploy --region $AWS_REGIONThe same command against the lambda URL will result in "Internal Server Error" with the mentioned stacktrace above.