spring-cloud / spring-cloud-function

Apache License 2.0
1.03k stars 615 forks source link

AWS: AWSTypesMessageConverter fails to deserialize JSON array as body for functions that take reactive inputs of POJOs #1052

Closed ArnauAregall closed 1 year ago

ArnauAregall commented 1 year ago

Describe the bug

Using:

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.json

The 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_REGION

The same command against the lambda URL will result in "Internal Server Error" with the mentioned stacktrace above.

ArnauAregall commented 1 year ago

Adding a bit more info if it helps:

The error is also somehow reproducible when serializing the return type POJOs.

Managed to reproduce it by invoking the lambda using aws lambda invoke cli command.

aws lambda invoke   \
  --function-name aws-lambda-spring-cloud-f-SpringCloudFunctionLambd-.... \
      --cli-binary-format raw-in-base64-out  \
          --payload '[{"latitude": 42.99, "longitude": 2.83 }, {"latitude": 43.01, "longitude": 2.21 } ]' output.txt

Response:

{
    "StatusCode": 200,
    "FunctionError": "Unhandled",
    "ExecutedVersion": "$LATEST"
}

output.txt:

{
    "errorType": "IllegalArgumentException",
    "errorMessage": "Payload must not be null",
    "stackTrace": "java.lang.IllegalArgumentException: Payload must not be null\n\tat org.springframework.util.Assert.notNull(Assert.java:204)\n\tat org.springframework.messaging.support.MessageBuilder.<init>(MessageBuilder.java:58)\n\tat org.springframework.messaging.support.MessageBuilder.withPayload(MessageBuilder.java:190)\n\tat org.springframework.cloud.function.adapter.aws.AWSLambdaUtils.generateOutputFromObject(AWSLambdaUtils.java:176)\n\tat org.springframework.cloud.function.adapter.aws.CustomRuntimeEventLoop.eventLoop(CustomRuntimeEventLoop.java:166)\n\tat org.springframework.cloud.function.adapter.aws.CustomRuntimeEventLoop.lambda$run$0(CustomRuntimeEventLoop.java:90)\n\tat java.base@17.0.5/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)\n\tat java.base@17.0.5/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)\n\tat java.base@17.0.5/java.lang.Thread.run(Thread.java:833)\n\tat org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:775)\n\tat org.graalvm.nativeimage.builder/com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:203)\n"
}

Logs:

2023-06-25T19:00:36.111Z DEBUG 9 --- [pool-5-thread-1] c.f.c.c.BeanFactoryAwareFunctionRegistry : Invoking function forecast<reactor.core.publisher.Flux<tech.aaregall.lab.function.weather.domain.GeoLocation>, reactor.core.publisher.Flux<tech.aaregall.lab.function.weather.domain.Forecast>>
2023-06-25T19:00:36.111000 2023-06-25T19:00:36.111Z DEBUG 9 --- [pool-5-thread-1] c.f.c.c.BeanFactoryAwareFunctionRegistry : Converting JSON string representing collection to a list of Messages. Function 'forecast<reactor.core.publisher.Flux<tech.aaregall.lab.function.weather.domain.GeoLocation>, reactor.core.publisher.Flux<tech.aaregall.lab.function.weather.domain.Forecast>>' will be invoked iteratively
2023-06-25T19:00:36.112000 2023-06-25T19:00:36.112Z DEBUG 9 --- [pool-5-thread-1] c.f.c.c.BeanFactoryAwareFunctionRegistry : Invoking function: forecast<reactor.core.publisher.Flux<tech.aaregall.lab.function.weather.domain.GeoLocation>, reactor.core.publisher.Flux<tech.aaregall.lab.function.weather.domain.Forecast>>with input type: reactor.core.publisher.Flux<tech.aaregall.lab.function.weather.domain.GeoLocation>
2023-06-25T19:00:36.112000 2023-06-25T19:00:36.112Z DEBUG 9 --- [pool-5-thread-1] o.s.c.f.a.aws.CustomRuntimeEventLoop     : Reply from function: FluxMap
2023-06-25T19:00:36.112000 2023-06-25T19:00:36.112Z DEBUG 9 --- [pool-5-thread-1] c.f.c.c.BeanFactoryAwareFunctionRegistry : Converted Message: GenericMessage [payload={latitude=42.99, longitude=2.83}, headers={id=540951aa-c67b-22e2-56a7-6ed76137007a, timestamp=1687719636111}] to: class tech.aaregall.lab.function.weather.domain.GeoLocation
2023-06-25T19:00:36.112000 2023-06-25T19:00:36.112Z DEBUG 9 --- [pool-5-thread-1] c.f.c.c.BeanFactoryAwareFunctionRegistry : Converted Message: GenericMessage [payload={latitude=43.01, longitude=2.21}, headers={id=ab6b39c9-f56f-5d19-2512-22fbca5f7820, timestamp=1687719636111}] to: class tech.aaregall.lab.function.weather.domain.GeoLocation
2023-06-25T19:00:36.145000 2023-06-25T19:00:36.145Z DEBUG 9 --- [pool-5-thread-1] o.s.c.f.adapter.aws.AWSLambdaUtils       : Response value: GenericMessage [payload=byte[11831], headers={contentType=application/json, id=7025cb06-5e20-7770-6884-90ca27b037ae, timestamp=1687719636145}]
2023-06-25T19:00:36.148000 2023-06-25T19:00:36.148Z DEBUG 9 --- [pool-5-thread-1] o.s.c.f.adapter.aws.AWSLambdaUtils       : Response value: GenericMessage [payload=byte[11835], headers={contentType=application/json, id=0c1ca3d6-8c58-438e-d5a6-c0b8cdc8ddda, timestamp=1687719636148}]
2023-06-25T19:00:36.148000 2023-06-25T19:00:36.148Z DEBUG 9 --- [pool-5-thread-1] o.s.c.f.adapter.aws.AWSLambdaUtils       : OUTPUT: [GenericMessage [payload=byte[11831], headers={contentType=application/json, id=7025cb06-5e20-7770-6884-90ca27b037ae, timestamp=1687719636145}], GenericMessage [payload=byte[11835], headers={contentType=application/json, id=0c1ca3d6-8c58-438e-d5a6-c0b8cdc8ddda, timestamp=1687719636148}]] - java.util.ArrayList
2023-06-25T19:00:36.151000 2023-06-25T19:00:36.150Z  INFO 9 --- [pool-5-thread-1] o.s.c.f.a.aws.CustomRuntimeEventLoop     : Result ERROR status: 202 ACCEPTED

Reading the logs it can be appreciated that the two JSON objects in the array of the payload were successfully converted to GeoLocation POJOs.

But apparently it also failed on when converting the return type: org.springframework.cloud.function.adapter.aws.AWSLambdaUtils.generateOutputFromObject(AWSLambdaUtils.java:176)

OUTPUT ... log produced by AWSLambdaUtils also indicates the return class is an java.uti.ArrayList whereas the function is defined with a return type of Flux<Forecast>.

olegz commented 1 year ago

Was able to reproduce with your sample, so thank you. Will let you know once I figure out the issue

olegz commented 1 year ago

I thought it may have something to do with native hints, but just reproduced it locally, by sending a JSON representing an actual API Gateway request, so will have a test case for this.

ArnauAregall commented 1 year ago

That's actually really good news, thanks @olegz!

olegz commented 1 year ago

I believe I got it. I am assuming this is what you are expecting..?

curl -X POST -H "Content-Type: application/json" -d '[{"latitude": 41.34, "longitude": 2.78}]' https://emcdxu5ijj.execute-api.us-east-2.amazonaws.com/question
..
{"geoLocation":{"latitude":41.34,"longitude":2.7799997},"hourlyForecasts":[{"time":"2023-07-12T00:00:00","temperature":24.7,"precipitation":0.0},{"time":"2023-07-12T01:00:00","temperature":24.4,"precipitation":0.0},{"time":"2023-07-12T02:00:00","temperature":24.5,"precipitation":0.0},{"time":"2023-07-12T03:00:00","temperature":24.5,"precipitation":0.0},{"time":"2023-07-12T04:00:00","temperature":24.2,"precipitation":0.0},{"time":"2023-07-12T05:00:00","temperature":24.5,"precipitation":0.0},{"time":"2023-07-12T06:00:00","temperature":24.4,"precipitation":0.0},{"time":"2023-07-12T07:00:00","temperature":24.4,"precipitation":0.0},{"time":"2023-07-12T08:00:00","temperature":24.6,"precipitation":0.0},{"time":"2023-07-12T09:00:00","temperature":24.7,"precipitation":0.0},{"time":"2023-07-12T10:00:00","temperature":24.7,"precipitation":0.0},{"time":"2023-07-12T11:00:00","temperature":24.7,"precipitation":0.0},{"time":"2023-07-12T12:00:00","temperature":25.1,"precipitation":0.0},{"time":"2023-07-12T13:00:00","temperature":25.3,"precipitation":0.0},{"time":"2023-07-12T14:00:00","temperature":25.4,"precipitation":0.0},
ArnauAregall commented 1 year ago

Yes, that's it!

Although would be great to double check with multiple objects in the array, which was the original intended use case.

[
  {
    "latitude": 41.3874,
    "longitude": 2.1686
  },
  {
    "latitude": 47.9990,
    "longitude": 7.8421
  }
]
olegz commented 1 year ago

It's fixed, so give it a shot, I'll kick off a snapshot build so 4.0.5-SNAPSHOT will be available soon

olegz commented 1 year ago

Snapshots are now available

ArnauAregall commented 1 year ago

Tested OK on AWS with 4.0.5-SNAPSHOT, thanks a lot! 👍

Had to manually add org.springframework.cloud:spring-cloud-function-context to confirm it (I was using it the one provided by s-c-f web).

    implementation("org.springframework.cloud:spring-cloud-function-context:4.0.5-SNAPSHOT")
    implementation("org.springframework.cloud:spring-cloud-function-web:4.0.5-SNAPSHOT")
    implementation("org.springframework.cloud:spring-cloud-function-adapter-aws:4.0.5-SNAPSHOT")
ArnauAregall commented 1 year ago

Noticed this https://github.com/spring-cloud/spring-cloud-function/commit/f45131f0f040a3f4da18967e74f1ad23c952fd2c?diff=unified#r121514572

olegz commented 1 year ago

Thanks @ArnauAregall will fix the sysout with the next commit. Accidental leftover

jeusdi commented 5 months ago

I'm getting same issue.

I'm using spring cloud function version 4.1.0.

curl command:

curl --header 'Content-Type: application/json' --data '{"label": "folder1", "references": ["028bba85-b605-4f25-be42-27e3d72566ec"]}' 'https://.execute-api.eu-west-1.amazonaws.com:443/des/reference/4862ff49-c44e-47b0-99a2-34850ec45a20/linkage'

log I'm getting:


2024-04-05T10:18:48.494Z  INFO 8 --- [           main] o.s.c.f.adapter.aws.FunctionInvoker      : Located function: 'createReferenceLinkageFunction'
--
START RequestId: 9deaa3b1-6869-4a38-9b24-4e92891f0751 Version: $LATEST
2024-04-05T10:18:48.502Z  INFO 8 --- [           main] o.s.c.f.adapter.aws.AWSLambdaUtils       : Received: {     "resource": "/reference/{referenceId}/linkage",     "path": "/reference/4862ff49-c44e-47b0-99a2-34850ec45a20/linkage",     "httpMethod": "POST",     "headers": {         "Accept": "*/*",         "CloudFront-Forwarded-Proto": "https",         "CloudFront-Is-Desktop-Viewer": "true",         "CloudFront-Is-Mobile-Viewer": "false",         "CloudFront-Is-SmartTV-Viewer": "false",         "CloudFront-Is-Tablet-Viewer": "false",         "CloudFront-Viewer-ASN": "35699",         "CloudFront-Viewer-Country": "ES",         "content-type": "application/json",         "Host": "bad1udgbzk.execute-api.eu-west-1.amazonaws.com",         "User-Agent": "curl/8.6.0",         "Via": "2.0 3785ee12fd6da5a022c1747ed7b60a80.cloudfront.net (CloudFront)",         "X-Amz-Cf-Id": "CeElKosFWSk4e6EcKG2fVKRJPkPcJvhq_j0FNm3PHNVIeCPd5RGMXw==",         "X-Amzn-Trace-Id": "Root=1-660fcfff-599c465b4c6426b34c958f45",         "X-Forwarded-For": "91.126.208.13, 15.158.57.19",         "X-Forwarded-Port": "443",         "X-Forwarded-Proto": "https"     },     "multiValueHeaders": {         "Accept": [             "*/*"         ],         "CloudFront-Forwarded-Proto": [             "https"         ],         "CloudFront-Is-Desktop-Viewer": [             "true"         ],         "CloudFront-Is-Mobile-Viewer": [             "false"         ],         "CloudFront-Is-SmartTV-Viewer": [             "false"         ],         "CloudFront-Is-Tablet-Viewer": [             "false"         ],         "CloudFront-Viewer-ASN": [             "35699"         ],         "CloudFront-Viewer-Country": [             "ES"         ],         "content-type": [             "application/json"         ],         "Host": [             "bad1udgbzk.execute-api.eu-west-1.amazonaws.com"         ],         "User-Agent": [             "curl/8.6.0"         ],         "Via": [             "2.0 3785ee12fd6da5a022c1747ed7b60a80.cloudfront.net (CloudFront)"         ],         "X-Amz-Cf-Id": [             "CeElKosFWSk4e6EcKG2fVKRJPkPcJvhq_j0FNm3PHNVIeCPd5RGMXw=="         ],         "X-Amzn-Trace-Id": [             "Root=1-660fcfff-599c465b4c6426b34c958f45"         ],         "X-Forwarded-For": [             "91.126.208.13, 15.158.57.19"         ],         "X-Forwarded-Port": [             "443"         ],         "X-Forwarded-Proto": [             "https"         ]     },     "queryStringParameters": null,     "multiValueQueryStringParameters": null,     "pathParameters": {         "referenceId": "4862ff49-c44e-47b0-99a2-34850ec45a20"     },     "stageVariables": null,     "requestContext": {         "resourceId": "jldtmb",         "resourcePath": "/reference/{referenceId}/linkage",         "httpMethod": "POST",         "extendedRequestId": "Vv1v6EdiDoEEmzA=",         "requestTime": "05/Apr/2024:10:18:39 +0000",         "path": "/des/reference/4862ff49-c44e-47b0-99a2-34850ec45a20/linkage",         "accountId": "058264555121",         "protocol": "HTTP/1.1",         "stage": "des",         "domainPrefix": "bad1udgbzk",         "requestTimeEpoch": 1712312319131,         "requestId": "4aeb8a6f-d8bb-4ffc-add7-8d47dfecdced",         "identity": {             "cognitoIdentityPoolId": null,             "accountId": null,             "cognitoIdentityId": null,             "caller": null,             "sourceIp": "91.126.208.13",             "principalOrgId": null,             "accessKey": null,             "cognitoAuthenticationType": null,             "cognitoAuthenticationProvider": null,             "userArn": null,             "userAgent": "curl/8.6.0",             "user": null         },         "domainName": "bad1udgbzk.execute-api.eu-west-1.amazonaws.com",         "deploymentId": "ru0w5s",         "apiId": "bad1udgbzk"     },     "body": "[{\"label\": \"folder1\", \"references\": [\"028bba85-b605-4f25-be42-27e3d72566ec\"]}]",     "isBase64Encoded": false }
2024-04-05T10:18:48.996Z  WARN 8 --- [           main] s.c.f.c.c.SmartCompositeMessageConverter : Failure during type conversion by org.springframework.cloud.function.adapter.aws.AWSTypesMessageConverter@43af351a. Will try the next converter.
java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class [B (java.util.LinkedHashMap and [B are in module java.base of loader 'bootstrap')
at org.springframework.cloud.function.adapter.aws.AWSTypesMessageConverter.convertFromInternal(AWSTypesMessageConverter.java:82) ~[task/:na]
at org.springframework.messaging.converter.AbstractMessageConverter.fromMessage(AbstractMessageConverter.java:183) ~[task/:na]
at org.springframework.messaging.converter.AbstractMessageConverter.fromMessage(AbstractMessageConverter.java:174) ~[task/:na]
at org.springframework.cloud.function.context.config.SmartCompositeMessageConverter.fromMessage(SmartCompositeMessageConverter.java:63) ~[task/:na]
at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.convertInputMessageIfNecessary(SimpleFunctionRegistry.java:1357) ~[task/:na]
at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.convertInputIfNecessary(SimpleFunctionRegistry.java:1120) ~[task/:na]
at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.lambda$convertInputPublisherIfNecessary$24(SimpleFunctionRegistry.java:1469) ~[task/:na]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:113) ~[task/:na]
at reactor.core.publisher.FluxIterable$IterableSubscription.slowPath(FluxIterable.java:335) ~[task/:na]
at reactor.core.publisher.FluxIterable$IterableSubscription.request(FluxIterable.java:294) ~[task/:na]
...

When I send request without body, it works.

Any ideas?