aws / aws-lambda-java-libs

Official mirror for interface definitions and helper classes for Java code running on the AWS Lambda platform.
https://aws.amazon.com/lambda/
Apache License 2.0
521 stars 231 forks source link

Provide a mechanism for retrieving non-wrapped ObjectMapper instance #352

Open ash-sykes-acn opened 2 years ago

ash-sykes-acn commented 2 years ago

Hi, attempting to use Spring Cloud for an AWS lambda. Spring cloud looks for an instance of com.fasterxml.jackson.databind.ObjectMapper. However, the serialisation library only provides a mechanism (as far as I can see) to return a wrapped instance of the configured mapper (i.e. com.amazonaws.thirdparty...).

Is there a way to get the expected ObjectMapper instance that I've missed? Or an appetite to expose the appropriately typed instance?

msailes commented 2 years ago

Hi @ash-sykes-acn, is there a particular reason why you want to access that instance of ObjectMapper?

Thanks

Mark

ash-sykes-acn commented 2 years ago

@msailes Yes, when using Spring Cloud, the function handler that attempts to deserialise the incoming AWS event (in this instance a ScheduledEvent) fails as the input has an unexpected version property. This is despite the fact that the aws serialisation library has been added (see below log). It appears that Spring Cloud attempts to use the unwrapped ObjectMapper from Jackson. I was hoping that I would be able to add this dependency and then register it as the primary ObjectMapper bean:

    @Bean
    @Primary
    public ObjectMapper objectMapper() {
        return JacksonFactory.getInstance().getMapper();
    }

Which would work if the Mapper returned was of type com.fasterxml.jackson.databind.ObjectMapper

If I use the above and change other ObjectMapper imports to com.amazonaws.lambda.thirdparty.com.fasterxml.jackson.databind.ObjectMapper; deserialization still fails as a Spring Cloud Function doesn't use a mapper of that type during deserialisation.

10170 [main] WARN  o.s.c.f.c.c.JsonMessageConverter - Failed to convert value: {"version": "0", "id": "6bcff830-bc14-4e75-2559-1baf402bbd80", "detail-type": "Scheduled Event", "source": "aws.events", "account": "cccc", "time": "2022-06-27T14:10:00Z", "region": "eu-west-1", "resources": ["arn:aws:events:eu-west-1:XXXX:rule/ddddd"], "detail": {}}
java.lang.IllegalStateException: Failed to convert. Possible bug as the conversion probably shouldn't have been attampted here
    at org.springframework.cloud.function.json.JacksonMapper.doFromJson(JacksonMapper.java:70)
    at org.springframework.cloud.function.json.JsonMapper.fromJson(JsonMapper.java:94)
    at org.springframework.cloud.function.context.config.JsonMessageConverter.convertFromInternal(JsonMessageConverter.java:84)
    at org.springframework.messaging.converter.AbstractMessageConverter.fromMessage(AbstractMessageConverter.java:185)
    at org.springframework.messaging.converter.AbstractMessageConverter.fromMessage(AbstractMessageConverter.java:176)
    at org.springframework.cloud.function.context.config.SmartCompositeMessageConverter.fromMessage(SmartCompositeMessageConverter.java:57)
    at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.convertInputMessageIfNecessary(SimpleFunctionRegistry.java:1302)
    at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.convertInputIfNecessary(SimpleFunctionRegistry.java:1068)
    at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.doApply(SimpleFunctionRegistry.java:707)
    at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.apply(SimpleFunctionRegistry.java:562)
    at org.springframework.cloud.function.adapter.aws.FunctionInvoker.handleRequest(FunctionInvoker.java:113)
    at lambdainternal.EventHandlerLoader$2.call(EventHandlerLoader.java:899)
    at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:258)
    at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:192)
    at lambdainternal.AWSLambda.main(AWSLambda.java:187)
Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "version" (class com.amazonaws.services.lambda.runtime.events.ScheduledEvent), not marked as ignorable (8 known properties: "detail", "region", "resources", "detailType", "account", "source", "time", "id"])

I can lift and shift your mapper config into a bean that is of type com.fasterxml.jackson.databind.ObjectMapper and everything works as expected. However, I would prefer not to do this incase further changes are made to the mapping config.

Hopefully I managed to explain the reason for wanting this sufficiently :D

msailes commented 2 years ago

@olegz is there anything else that can be done in this case?