SqsListener can't map object after Migration to 3.0

577 Views Asked by At

I am migrating my project to Spring Boot 3 and I also have to migrate AWS Libraries. After Migration, some functions with @SqsListener annotation stopped working because of messages that can't be mapped to my object

@SqsListener("my-queue")
fun onMessage(message: MyObject) {
... }

If I change the message field to String and use objectMapper in the function everything is working but I would like to have already mapped object in param I've already tried to create a custom mapper but it wasn't working:

    @Bean
fun sqsMessagingMessageConverter(objectMapper: ObjectMapper): SqsMessagingMessageConverter {
    val mapper = MappingJackson2MessageConverter()
    mapper.objectMapper = objectMapper
        .registerModule(JavaTimeModule())
        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
        .configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true)
        .configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true)
        .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
    mapper.setPrettyPrint(true)
    val converter = SqsMessagingMessageConverter()
    converter.setPayloadTypeHeader(APPLICATION_JSON_VALUE)
    converter.payloadMessageConverter = mapper
    return converter
}

I have no idea what I need to add more to make it works. The error that I am receiving is MessageConversionException: Cannot convert from [java.lang.String] to [...]

@Edit I also tried to register object mapper like in this instruction: https://docs.awspring.io/spring-cloud-aws/docs/3.0.0/reference/html/index.html#global-configuration-for-sqslisteners but it wasn't working either

1

There are 1 best solutions below

1
On

Ran into a similar issue. My custom mapper did't get picked up by the SqsListener configuration for some reason. I seem to have resolved the issue by registering my own SqsMessageListenerContainerFactory and configuring it that way.

Create an SqsMessagingMessageConverter with your custom mapper:

  private SqsMessagingMessageConverter sqsMessagingMessageConverter() {
    SqsMessagingMessageConverter converter = new SqsMessagingMessageConverter();
    converter.setPayloadMessageConverter(mappingJackson2MessageConverter());
    return converter;
  }

Add it to a SqsMessageListenerContainerFactory and expose as a bean, this will override the default factory.

@Bean
  SqsMessageListenerContainerFactory<Object> defaultSqsListenerContainerFactory(SqsAsyncClient sqsAsyncClient) {
    return SqsMessageListenerContainerFactory
        .builder()
        .configure(options -> options
            .messageConverter(sqsMessagingMessageConverter()))
        .sqsAsyncClient(sqsAsyncClient)
        .build();
  }

Code in Java, but you get the gist.