web-dev-qa-db-fra.com

Spring Cloud @SqsListener MessageConversionException: impossible de convertir à partir de [Java.lang.String] pour GenericMessage

Je vois l'exception suivante lorsque j'essaie de consommer un message SQS:

org.springframework.messaging.converter.MessageConversionException: 

Cannot convert from [Java.lang.String] to [com.example.demo.Foo] for GenericMessage [payload={}, headers={LogicalResourceId=my-queue, ApproximateReceiveCount=1, SentTimestamp=1529021258825, ReceiptHandle=xxxx, Visibility=org.springframework.cloud.aws.messaging.listener.QueueMessageVisibility@47ce6922, SenderId=xxxx, lookupDestination=my-queue, ApproximateFirstReceiveTimestamp=1529021264456, MessageId=xxxx}]
    at org.springframework.messaging.handler.annotation.support.PayloadArgumentResolver.resolveArgument(PayloadArgumentResolver.Java:144)
    at org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.Java:116)
    at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.Java:137)
    at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.Java:109)
    at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMatch(AbstractMethodMessageHandler.Java:515)
    at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessageInternal(AbstractMethodMessageHandler.Java:473)
    at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessage(AbstractMethodMessageHandler.Java:409)
    at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer.executeMessage(SimpleMessageListenerContainer.Java:205)
    at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer$MessageExecutor.run(SimpleMessageListenerContainer.Java:342)
    at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer$SignalExecutingRunnable.run(SimpleMessageListenerContainer.Java:397)
    at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1149)
    at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:624)
    at Java.lang.Thread.run(Thread.Java:748)

Le code Spring Boot est le suivant:

@Configuration
@EnableSqs
public class AmazonSqsConfiguration {

    @Bean
    public AmazonSQS amazonSQSAsync() {
        return AmazonSQSAsyncClientBuilder.standard()
            .withRegion(Regions.US_WEST_2)
            .build();
    }
}

@Service
public class MyService {

    // Throws MessageConversionException
    @SqsListener("my-queue")
    public void listen(Foo payload) {

    }

    // Works fine
    @SqsListener("my-queue")
    public void listen(String payload) {

    }
}

J'utilise org.springframework.cloud:spring-cloud-aws-messaging:2.0.0.RC2

J'ai des bibliothèques Jackson 2 sur mon chemin de classe, donc PayloadArgumentResolver essaie d'utiliser MappingJackson2MessageConverter pour désérialiser la charge utile de mon message. Cependant, comme le message SQS manque un en-tête contentType et que strictContentTypeMatch est défini sur true, canConvertFrom renvoie false.

https://github.com/spring-projects/spring-framework/blob/f5e8f4983f7653169f3da8a3287499fce93cadd4/spring-messaging/src/main/Java/org/springframework/messaging/converterage # L237

Je ne vois pas comment il est possible de définir l'en-tête contentType pour les messages SQS - manque-t-il quelque chose?

Spring Cloud QueueMessageHandler doit-il définir strictContentTypeMatch sur true?

https://github.com/spring-cloud/spring-cloud-aws/blob/6a7c3c31709d4239131b27936de29385df414d41/spring-cloud-aws-messaging/src/main/Java/org/springframework/cloud /aws/messaging/listener/QueueMessageHandler.Java#L217

11
Joe Stepowski

Ran dans le même problème, et je répondrais à la question de deux façons en fonction de qui génère le message

  • Oui, il est possible de définir contentType sur le message, et si vous contrôlez les messages générés, cela est préférable. Dans la console AWS, lorsque vous envoyez un message à la main, il existe un onglet pour les "attributs de message". Vous ajouteriez un attribut avec le nom contentType et la valeur application/json. Les appels AWS SDK devraient vous permettre de faire de même à partir du code d'application.

  • Pour les messages générés par AWS sans type de contenu spécifié, comme les événements S3, vous devez en fait définir strictContentMatch sur false. Ceci est documenté ici: http://cloud.spring.io/spring-cloud-static/spring-cloud-aws/2.0.0.RELEASE/multi/multi__messaging.html#_consuming_aws_event_messages_with_Amazon_sqs

Le document est déroutant car il dit "sans l'en-tête de type MIME" mais le nom réel de l'en-tête est contentType, comme vous vous en êtes aperçu.

8
wrschneider