Как изменить сопоставитель объектов, который Spring Cloud AWS использует для десериализации сообщений SQS?

Мне нужно изменить сопоставитель объектов Jackson2, который Spring Cloud AWS использует при десериализации JSON, и зарегистрировать в нем модуль JavaTime. Это связано с тем, что полезная нагрузка SQS содержит экземпляр класса Java Instant, который необходимо десериализовать с помощью модуля JavaTime.

Детали:

Это метод прослушивателя SQS:

@SqsListener(value = "mysqs",deletionPolicy = SqsMessageDeletionPolicy.ON_SUCCESS)
public void handleChangedEventFromSqsQueue(@NotificationMessage ChangeEvent event) {
    try {
        // Handle ChangeEvent object here
    } catch (Throwable t) {
        // Do something
    }
}

Это класс ChangedEvent:

public class ChangeEvent {
    private final Long oldValue;
    private final Long newValue;
    private final Instant changedAt;
    // This is the ID of the user who performed the change
    private final Long changedBy;

    // Constructors, getters, and setters omitted
}

Это ошибка, которую я получаю:

org.springframework.messaging.MessagingException: An exception occurred while invoking the handler method; nested exception is org.springframework.messaging.converter.MessageConversionException: Could not read JSON: Can not construct instance of java.time.Instant: no String-argument constructor/factory method to deserialize from String value ('2017-10-20T01:58:09.298Z')
 at [Source: {"oldValue": 1,"newValue": 2,"changedAt":"2017-10-20T01:58:09.298Z","changedBy":20116}; line: 1, column: 124] (through reference chain: com.company.ChangeEvent["changedAt"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of java.time.Instant: no String-argument constructor/factory method to deserialize from String value ('2017-10-20T01:58:09.298Z')
 at [Source: {"oldValue": 1,"newValue": 2,"changedAt":"2017-10-20T01:58:09.298Z","changedBy":20116}; line: 1, column: 124] (through reference chain: com.company.ChangeEvent["changedAt"])
    at org.springframework.cloud.aws.messaging.listener.QueueMessageHandler.processHandlerMethodException(QueueMessageHandler.java:195) ~[spring-cloud-aws-messaging-1.1.0.RELEASE.jar:1.1.0.RELEASE]
    at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMatch(AbstractMethodMessageHandler.java:506) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessageInternal(AbstractMethodMessageHandler.java:451) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessage(AbstractMethodMessageHandler.java:389) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer.executeMessage(SimpleMessageListenerContainer.java:181) ~[spring-cloud-aws-messaging-1.1.0.RELEASE.jar:1.1.0.RELEASE]
    at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer$MessageExecutor.run(SimpleMessageListenerContainer.java:314) ~[spring-cloud-aws-messaging-1.1.0.RELEASE.jar:1.1.0.RELEASE]
    at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer$SignalExecutingRunnable.run(SimpleMessageListenerContainer.java:368) [spring-cloud-aws-messaging-1.1.0.RELEASE.jar:1.1.0.RELEASE]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_111]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_111]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_111]
Caused by: org.springframework.messaging.converter.MessageConversionException: Could not read JSON: Can not construct instance of java.time.Instant: no String-argument constructor/factory method to deserialize from String value ('2017-10-20T01:58:09.298Z')
 at [Source: {"oldValue": 1,"newValue": 2,"changedAt":"2017-10-20T01:58:09.298Z","changedBy":20116}; line: 1, column: 124] (through reference chain: com.company.ChangeEvent["changedAt"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of java.time.Instant: no String-argument constructor/factory method to deserialize from String value ('2017-10-20T01:58:09.298Z')
 at [Source: {"oldValue": 1,"newValue": 2,"changedAt":"2017-10-20T01:58:09.298Z","changedBy":20116}; line: 1, column: 124] (through reference chain: com.company.ChangeEvent["changedAt"])
    at org.springframework.messaging.converter.MappingJackson2MessageConverter.convertFromInternal(MappingJackson2MessageConverter.java:223) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.messaging.converter.AbstractMessageConverter.fromMessage(AbstractMessageConverter.java:175) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.messaging.converter.AbstractMessageConverter.fromMessage(AbstractMessageConverter.java:167) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.messaging.converter.CompositeMessageConverter.fromMessage(CompositeMessageConverter.java:55) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.cloud.aws.messaging.support.converter.NotificationRequestConverter.fromMessage(NotificationRequestConverter.java:80) ~[spring-cloud-aws-messaging-1.1.0.RELEASE.jar:1.1.0.RELEASE]
    at org.springframework.cloud.aws.messaging.support.NotificationMessageArgumentResolver.resolveArgument(NotificationMessageArgumentResolver.java:45) ~[spring-cloud-aws-messaging-1.1.0.RELEASE.jar:1.1.0.RELEASE]
    at org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:98) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:138) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:107) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMatch(AbstractMethodMessageHandler.java:490) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    ... 8 common frames omitted
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of java.time.Instant: no String-argument constructor/factory method to deserialize from String value ('2017-10-20T01:58:09.298Z')
 at [Source: {"oldValue": 1,"newValue": 2,"changedAt":"2017-10-20T01:58:09.298Z","changedBy":20116}; line: 1, column: 124] (through reference chain: com.company.ChangeEvent["changedAt"])
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:270) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.DeserializationContext.instantiationException(DeserializationContext.java:1456) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1012) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:370) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:315) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1282) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:159) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:150) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:499) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:511) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:396) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1198) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:314) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:148) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:499) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:101) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:357) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:148) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3798) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2880) ~[jackson-databind-2.8.5.jar:2.8.5]
    at org.springframework.messaging.converter.MappingJackson2MessageConverter.convertFromInternal(MappingJackson2MessageConverter.java:218) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    ... 17 common frames omitted

Дополнительная информация:

  • Модуль Jackson JSR-310 находится на пути к классам.
  • Другие части приложения используют JSR-310 без всяких сомнений. На самом деле мне не нужно было настраивать JSR-310 для работы - все, что я делал, это добавлял модуль Jackson JSR-310 в путь к классам, и все это работало просто отлично.

Моя первая попытка это исправить (сбой)

В моей первой попытке это исправить я попытался выставить бин типа QueueMessageHandlerFactory и настроить его с помощью моего собственного ObjectMapper. К сожалению, это тоже не сработало. Детали этой ошибки ниже. Я не уверен, помогут ли они с отладкой или нет.

Это боб, который я выставил:

@Configuration
public class AwsSqsConfig {

    @Bean
    public QueueMessageHandlerFactory queueMessageHandlerFactory(AmazonSQS amazonSQS,
                                                                 BeanFactory beanFactory) {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());

        MappingJackson2MessageConverter mappingJackson2MessageConverter = new MappingJackson2MessageConverter();
        mappingJackson2MessageConverter.setSerializedPayloadClass(String.class);
        mappingJackson2MessageConverter.setObjectMapper(objectMapper);

        Assert.notNull(amazonSQS);
        Assert.notNull(beanFactory);
        QueueMessageHandlerFactory factory = new QueueMessageHandlerFactory();
        factory.setAmazonSqs(amazonSQS);
        factory.setBeanFactory(beanFactory);
        factory.setArgumentResolvers(Arrays.asList(new PayloadArgumentResolver(mappingJackson2MessageConverter)));
        return factory;
    }

}

Я оставил метод слушателя и класс ChangeEvent одинаковыми, но на этот раз я получил другую ошибку:

org.springframework.messaging.MessagingException: An exception occurred while invoking the handler method; nested exception is org.springframework.messaging.converter.MessageConversionException: Could not read JSON: Unrecognized field "Type" (class com.company.ChangeEvent), not marked as ignorable
 at [Source: {
  "Type" : "Notification",
  "MessageId" : "e9e26416-ae16-5c60-b3a3-36752ebc3512",
  "TopicArn" : "arn:aws:sns:us-east-1:799735207477:matchStatusUpdated-dev",
  "Message" : "{\"oldValue\":1,\"newValue\":2,\"changedAt\":\"2017-10-20T04:41:15.024Z\",\"changedBy\":20116}",
  "Timestamp" : "2017-10-20T04:41:14.667Z",
  "SignatureVersion" : "1",
  "Signature" : "XXD+IAuCr6TUzkG1RIrreqf6OjAdvy7Bi/xZTBWOJI/LsTz5HG4QdTiTD4pZYI6jgupEhsG8BWYR8krKrwdSjfpYLD2z8pxBl4hEjgmgcCOHatKR7Hk9Sydsecr4yagrs0LUSjItB3EGv5O5Qfilps//swNaQnC+1VuIVedmaHxQi8McWBBzdBjFVs5WBHzItbRhC1KIsbf08Fnhc/XK9iAJTjY+09wUzVRs8x60NpaPoTQOYPJ1Yl7UNk4s8TQFd/pnWvRZpxv3hlh+Cz6CqwluER65lHol1tzCgAM60NcbxM+wqXE4IxfYHVG2PRKnE05x4mdjBqyVodOOXJYhtQ==",
  "SigningCertURL" : "https://sns.us-east-1.amazonaws.com/SimpleNotificationService-433026a4050d206028891664da859041.pem",
  "UnsubscribeURL" : "https://sns.us-east-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-east-1:799735207477:matchStatusUpdated-dev:135541fc-37de-40b3-84bc-d54cee36a10f",
  "MessageAttributes" : {
    "id" : {"Type":"String","Value":"1d18420f-bfcc-81b5-be6e-b7be543d5247"},
    "contentType" : {"Type":"String","Value":"application/json;charset=UTF-8"},
    "timestamp" : {"Type":"Number.java.lang.Long","Value":"1508474475049"}
  }
}; line: 2, column: 13] (through reference chain: com.company.ChangeEvent["Type"]); nested exception is com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "Type" (class com.company.ChangeEvent), not marked as ignorable)
 at [Source: {
  "Type" : "Notification",
  "MessageId" : "e9e26416-ae16-5c60-b3a3-36752ebc3512",
  "TopicArn" : "arn:aws:sns:us-east-1:799735207477:matchStatusUpdated-dev",
  "Message" : "{\"oldValue\":1,\"newValue\":2,\"changedAt\":\"2017-10-20T04:41:15.024Z\",\"changedBy\":20116}",
  "Timestamp" : "2017-10-20T04:41:14.667Z",
  "SignatureVersion" : "1",
  "Signature" : "XXD+IAuCr6TUzkG1RIrreqf6OjAdvy7Bi/xZTBWOJI/LsTz5HG4QdTiTD4pZYI6jgupEhsG8BWYR8krKrwdSjfpYLD2z8pxBl4hEjgmgcCOHatKR7Hk9Sydsecr4yagrs0LUSjItB3EGv5O5Qfilps//swNaQnC+1VuIVedmaHxQi8McWBBzdBjFVs5WBHzItbRhC1KIsbf08Fnhc/XK9iAJTjY+09wUzVRs8x60NpaPoTQOYPJ1Yl7UNk4s8TQFd/pnWvRZpxv3hlh+Cz6CqwluER65lHol1tzCgAM60NcbxM+wqXE4IxfYHVG2PRKnE05x4mdjBqyVodOOXJYhtQ==",
  "SigningCertURL" : "https://sns.us-east-1.amazonaws.com/SimpleNotificationService-433026a4050d206028891664da859041.pem",
  "UnsubscribeURL" : "https://sns.us-east-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-east-1:799735207477:matchStatusUpdated-dev:135541fc-37de-40b3-84bc-d54cee36a10f",
  "MessageAttributes" : {
    "id" : {"Type":"String","Value":"1d18420f-bfcc-81b5-be6e-b7be543d5247"},
    "contentType" : {"Type":"String","Value":"application/json;charset=UTF-8"},
    "timestamp" : {"Type":"Number.java.lang.Long","Value":"1508474475049"}
  }
}; line: 2, column: 13] (through reference chain: com.company.ChangeEvent["Type"])
    at org.springframework.cloud.aws.messaging.listener.QueueMessageHandler.processHandlerMethodException(QueueMessageHandler.java:195) ~[spring-cloud-aws-messaging-1.1.0.RELEASE.jar:1.1.0.RELEASE]
    at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMatch(AbstractMethodMessageHandler.java:506) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessageInternal(AbstractMethodMessageHandler.java:451) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessage(AbstractMethodMessageHandler.java:389) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer.executeMessage(SimpleMessageListenerContainer.java:181) ~[spring-cloud-aws-messaging-1.1.0.RELEASE.jar:1.1.0.RELEASE]
    at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer$MessageExecutor.run(SimpleMessageListenerContainer.java:314) ~[spring-cloud-aws-messaging-1.1.0.RELEASE.jar:1.1.0.RELEASE]
    at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer$SignalExecutingRunnable.run(SimpleMessageListenerContainer.java:368) [spring-cloud-aws-messaging-1.1.0.RELEASE.jar:1.1.0.RELEASE]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_111]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_111]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_111]
Caused by: org.springframework.messaging.converter.MessageConversionException: Could not read JSON: Unrecognized field "Type" (class com.company.ChangeEvent), not marked as ignorable
 at [Source: {
  "Type" : "Notification",
  "MessageId" : "e9e26416-ae16-5c60-b3a3-36752ebc3512",
  "TopicArn" : "arn:aws:sns:us-east-1:799735207477:matchStatusUpdated-dev",
  "Message" : "{\"oldValue\":1,\"newValue\":2,\"changedAt\":\"2017-10-20T04:41:15.024Z\",\"changedBy\":20116}",
  "Timestamp" : "2017-10-20T04:41:14.667Z",
  "SignatureVersion" : "1",
  "Signature" : "XXD+IAuCr6TUzkG1RIrreqf6OjAdvy7Bi/xZTBWOJI/LsTz5HG4QdTiTD4pZYI6jgupEhsG8BWYR8krKrwdSjfpYLD2z8pxBl4hEjgmgcCOHatKR7Hk9Sydsecr4yagrs0LUSjItB3EGv5O5Qfilps//swNaQnC+1VuIVedmaHxQi8McWBBzdBjFVs5WBHzItbRhC1KIsbf08Fnhc/XK9iAJTjY+09wUzVRs8x60NpaPoTQOYPJ1Yl7UNk4s8TQFd/pnWvRZpxv3hlh+Cz6CqwluER65lHol1tzCgAM60NcbxM+wqXE4IxfYHVG2PRKnE05x4mdjBqyVodOOXJYhtQ==",
  "SigningCertURL" : "https://sns.us-east-1.amazonaws.com/SimpleNotificationService-433026a4050d206028891664da859041.pem",
  "UnsubscribeURL" : "https://sns.us-east-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-east-1:799735207477:matchStatusUpdated-dev:135541fc-37de-40b3-84bc-d54cee36a10f",
  "MessageAttributes" : {
    "id" : {"Type":"String","Value":"1d18420f-bfcc-81b5-be6e-b7be543d5247"},
    "contentType" : {"Type":"String","Value":"application/json;charset=UTF-8"},
    "timestamp" : {"Type":"Number.java.lang.Long","Value":"1508474475049"}
  }
}; line: 2, column: 13] (through reference chain: com.company.ChangeEvent["Type"]); nested exception is com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "Type" (class com.company.ChangeEvent), not marked as ignorable
 at [Source: {
  "Type" : "Notification",
  "MessageId" : "e9e26416-ae16-5c60-b3a3-36752ebc3512",
  "TopicArn" : "arn:aws:sns:us-east-1:799735207477:matchStatusUpdated-dev",
  "Message" : "{\"oldValue\":1,\"newValue\":2,\"changedAt\":\"2017-10-20T04:41:15.024Z\",\"changedBy\":20116}",
  "Timestamp" : "2017-10-20T04:41:14.667Z",
  "SignatureVersion" : "1",
  "Signature" : "XXD+IAuCr6TUzkG1RIrreqf6OjAdvy7Bi/xZTBWOJI/LsTz5HG4QdTiTD4pZYI6jgupEhsG8BWYR8krKrwdSjfpYLD2z8pxBl4hEjgmgcCOHatKR7Hk9Sydsecr4yagrs0LUSjItB3EGv5O5Qfilps//swNaQnC+1VuIVedmaHxQi8McWBBzdBjFVs5WBHzItbRhC1KIsbf08Fnhc/XK9iAJTjY+09wUzVRs8x60NpaPoTQOYPJ1Yl7UNk4s8TQFd/pnWvRZpxv3hlh+Cz6CqwluER65lHol1tzCgAM60NcbxM+wqXE4IxfYHVG2PRKnE05x4mdjBqyVodOOXJYhtQ==",
  "SigningCertURL" : "https://sns.us-east-1.amazonaws.com/SimpleNotificationService-433026a4050d206028891664da859041.pem",
  "UnsubscribeURL" : "https://sns.us-east-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-east-1:799735207477:matchStatusUpdated-dev:135541fc-37de-40b3-84bc-d54cee36a10f",
  "MessageAttributes" : {
    "id" : {"Type":"String","Value":"1d18420f-bfcc-81b5-be6e-b7be543d5247"},
    "contentType" : {"Type":"String","Value":"application/json;charset=UTF-8"},
    "timestamp" : {"Type":"Number.java.lang.Long","Value":"1508474475049"}
  }
}; line: 2, column: 13] (through reference chain: com.company.ChangeEvent["Type"])
    at org.springframework.messaging.converter.MappingJackson2MessageConverter.convertFromInternal(MappingJackson2MessageConverter.java:223) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.messaging.converter.AbstractMessageConverter.fromMessage(AbstractMessageConverter.java:175) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.messaging.handler.annotation.support.PayloadArgumentResolver.resolveArgument(PayloadArgumentResolver.java:115) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:98) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:138) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:107) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMatch(AbstractMethodMessageHandler.java:490) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    ... 8 common frames omitted
Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "Type" (class com.company.ChangeEvent), not marked as ignorable
 at [Source: {
  "Type" : "Notification",
  "MessageId" : "e9e26416-ae16-5c60-b3a3-36752ebc3512",
  "TopicArn" : "arn:aws:sns:us-east-1:799735207477:matchStatusUpdated-dev",
  "Message" : "{\"oldValue\":1,\"newValue\":2,\"changedAt\":\"2017-10-20T04:41:15.024Z\",\"changedBy\":20116}",
  "Timestamp" : "2017-10-20T04:41:14.667Z",
  "SignatureVersion" : "1",
  "Signature" : "XXD+IAuCr6TUzkG1RIrreqf6OjAdvy7Bi/xZTBWOJI/LsTz5HG4QdTiTD4pZYI6jgupEhsG8BWYR8krKrwdSjfpYLD2z8pxBl4hEjgmgcCOHatKR7Hk9Sydsecr4yagrs0LUSjItB3EGv5O5Qfilps//swNaQnC+1VuIVedmaHxQi8McWBBzdBjFVs5WBHzItbRhC1KIsbf08Fnhc/XK9iAJTjY+09wUzVRs8x60NpaPoTQOYPJ1Yl7UNk4s8TQFd/pnWvRZpxv3hlh+Cz6CqwluER65lHol1tzCgAM60NcbxM+wqXE4IxfYHVG2PRKnE05x4mdjBqyVodOOXJYhtQ==",
  "SigningCertURL" : "https://sns.us-east-1.amazonaws.com/SimpleNotificationService-433026a4050d206028891664da859041.pem",
  "UnsubscribeURL" : "https://sns.us-east-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-east-1:799735207477:matchStatusUpdated-dev:135541fc-37de-40b3-84bc-d54cee36a10f",
  "MessageAttributes" : {
    "id" : {"Type":"String","Value":"1d18420f-bfcc-81b5-be6e-b7be543d5247"},
    "contentType" : {"Type":"String","Value":"application/json;charset=UTF-8"},
    "timestamp" : {"Type":"Number.java.lang.Long","Value":"1508474475049"}
  }
}; line: 2, column: 13] (through reference chain: com.company.ChangeEvent["Type"])
    at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:62) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:834) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1093) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1477) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1455) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:282) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3798) ~[jackson-databind-2.8.5.jar:2.8.5]
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2880) ~[jackson-databind-2.8.5.jar:2.8.5]
    at org.springframework.messaging.converter.MappingJackson2MessageConverter.convertFromInternal(MappingJackson2MessageConverter.java:218) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    ... 14 common frames omitted

По сути, все это означает, что я неправильно настроил QueueMessageHandler, что сделало невозможным десериализацию NotificationMessage.

Резюме

Как я уже говорил ранее, мне нужно знать, как изменить сопоставитель объектов, который Spring Cloud AWS использует для десериализации сообщений SQS. Кто-нибудь знает как это сделать?

Спасибо!

1 ответ

Вы пытаетесь прослушать сообщения SNS в очереди SQS. Поскольку они в основном являются сообщениями SNS, полезная нагрузка заключена в сообщение уведомления (поэтому в SQSListener установлена ​​аннотация @NotificationMessage).

Это фактически заставляет слушателя использовать NotificationMessageArgumentResolver вместо PayloadArgumentResolver для разрешения сообщений. NotificationMessageArgumentResolver необходим NotificationRequestConverter для выполнения этой работы.

Пожалуйста, попробуйте эту конфигурацию, я сам проверил ее в сообщении SNS ->SQS:

@Configuration
public class AwsSqsConfig {

    @Bean
    public QueueMessageHandlerFactory queueMessageHandlerFactory(
            AmazonSQSAsync amazonSQS, BeanFactory beanFactory) {

        ObjectMapper objectMapper = new ObjectMapper();
        // This is the java time module needed in the mapper (can be read in the question)
        objectMapper.registerModule(new JavaTimeModule());

        // Wrapped in this
        MappingJackson2MessageConverter jacksonMessageConverter = 
                new MappingJackson2MessageConverter();
        jacksonMessageConverter.setSerializedPayloadClass(String.class);
        jacksonMessageConverter.setObjectMapper(objectMapper);
        jacksonMessageConverter.setStrictContentTypeMatch(true);

        // Wrapped in this
        List<MessageConverter> payloadArgumentConverters = new ArrayList<>();
        payloadArgumentConverters.add(jacksonMessageConverter);

        // This is the converter that is invoked on SNS messages on SQS listener
        NotificationRequestConverter notificationRequestConverter = 
                new NotificationRequestConverter(jacksonMessageConverter);

        payloadArgumentConverters.add(notificationRequestConverter);
        payloadArgumentConverters.add(new SimpleMessageConverter());

        // It needs to be wrapped in this
        CompositeMessageConverter compositeMessageConverter = 
                new CompositeMessageConverter(payloadArgumentConverters);

        Assert.notNull(amazonSQS);
        Assert.notNull(beanFactory);
        QueueMessageHandlerFactory factory = new QueueMessageHandlerFactory();
        factory.setAmazonSqs(amazonSQS);
        factory.setBeanFactory(beanFactory);

        // The factory has this method for custom resolvers (can be read in the question)
        factory.setArgumentResolvers(Arrays.asList(
                new NotificationMessageArgumentResolver(compositeMessageConverter)));


        return factory;
    }
}

Вы были на правильном пути со своей попыткой, и это действительно очень помогло в вышеупомянутом решении, спасибо. Ваше решение абсолютно работает (также пробовало), если это простое сообщение SQS, а не SNS на SQS.

Другие вопросы по тегам