I have an SqsListener using a custom QueueMessageHandlerFactory with a message converter to go from JSON to POJO and back. If for whatever reason the listener method can't parse the JSON body in a message, it will throw a org.springframework.messaging.converter.MessageConversionException. I want to catch this exception and log it properly. I know that JMS listeners allow you to add a custom ErrorHandler as part of the Factory definition.
Is there a similar way to define a custom ErrorHandler to catch this exception using Spring's SqsListener and log it?
Thanks!
@Bean
public QueueMessageHandlerFactory queueMessageHandlerFactory(MessageConverter messageConverter) {
QueueMessageHandlerFactory factory = new QueueMessageHandlerFactory();
AcknowledgmentHandlerMethodArgumentResolver acknowledgmentResolver =
new AcknowledgmentHandlerMethodArgumentResolver(
ACKNOWLEDGMENT_HEADER_NAME);
PayloadArgumentResolver payloadArgumentResolver = new PayloadArgumentResolver(messageConverter);
factory.setArgumentResolvers(Arrays.asList(acknowledgmentResolver, payloadArgumentResolver));
return factory;
}
@Bean
protected MessageConverter messageConverter(ObjectMapper objectMapper) {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setObjectMapper(objectMapper);
converter.setStrictContentTypeMatch(false);
return converter;
}
Listener:
@SqsListener(value = "${aws.sqs.queueName}", deletionPolicy = SqsMessageDeletionPolicy.NEVER)
public void receiveMessage(MyCustomPOJO pollo, Acknowledgment acknowledgment) {
LOG.info("Message Received using SQS Listener " + pollo);
try {
acknowledgment.acknowledge().get();
} catch (InterruptedException | ExecutionException e) {
LOG.error("Error acknowledging message: " + pollo);
}
}
Exception triggered by sending "Test Message" instead of a deserialized POJO.
org.springframework.messaging.converter.MessageConversionException: Could not read JSON: Unrecognized token 'Test': was expecting ('true', 'false' or 'null')
at [Source: Test Message!; line: 1, column: 5]; nested exception is com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'Test': was expecting ('true', 'false' or 'null')
at [Source: Test Message!; line: 1, column: 5]
at org.springframework.messaging.converter.MappingJackson2MessageConverter.convertFromInternal(MappingJackson2MessageConverter.java:224) ~[spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.messaging.converter.AbstractMessageConverter.fromMessage(AbstractMessageConverter.java:175) ~[spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.messaging.handler.annotation.support.PayloadArgumentResolver.resolveArgument(PayloadArgumentResolver.java:135) ~[spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:112) ~[spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:135) ~[spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:107) ~[spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMatch(AbstractMethodMessageHandler.java:502) [spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessageInternal(AbstractMethodMessageHandler.java:461) [spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessage(AbstractMethodMessageHandler.java:399) [spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer.executeMessage(SimpleMessageListenerContainer.java:228) [spring-cloud-aws-messaging-2.2.4.RELEASE.jar:2.2.4.RELEASE]
at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer$MessageExecutor.run(SimpleMessageListenerContainer.java:418) [spring-cloud-aws-messaging-2.2.4.RELEASE.jar:2.2.4.RELEASE]
at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer$SignalExecutingRunnable.run(SimpleMessageListenerContainer.java:310) [spring-cloud-aws-messaging-2.2.4.RELEASE.jar:2.2.4.RELEASE]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_251]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_251]
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_251]
Caused by: com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'Test': was expecting ('true', 'false' or 'null')
at [Source: Test Message!; line: 1, column: 5]
at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1702) ~[jackson-core-2.8.7.jar:2.8.7]
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:558) ~[jackson-core-2.8.7.jar:2.8.7]
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._reportInvalidToken(ReaderBasedJsonParser.java:2839) ~[jackson-core-2.8.7.jar:2.8.7]
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._handleOddValue(ReaderBasedJsonParser.java:1903) ~[jackson-core-2.8.7.jar:2.8.7]
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.nextToken(ReaderBasedJsonParser.java:749) ~[jackson-core-2.8.7.jar:2.8.7]
at com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:3834) ~[jackson-databind-2.8.7.jar:2.8.7]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3783) ~[jackson-databind-2.8.7.jar:2.8.7]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2880) ~[jackson-databind-2.8.7.jar:2.8.7]
at org.springframework.messaging.converter.MappingJackson2MessageConverter.convertFromInternal(MappingJackson2MessageConverter.java:219) ~[spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
... 14 more
Nevermind, seems like all I need to do is add a @MessageExceptionHandler annotation to my custom handler:
@MessageExceptionHandler(MessageConversionException.class)
public void exceptionHandler(MessageConversionException e) {
LOG.info("Failed to deserialize that pollo", e);
}