From 1741803975301b02e466d0f173e7d1406bc7d3f3 Mon Sep 17 00:00:00 2001 From: Raul Avila <87972502+raul-avila-ph@users.noreply.github.com> Date: Wed, 12 Mar 2025 14:43:20 +0000 Subject: [PATCH] GH-3006: Read x-death count in a safer way Fixes: #3006 We had an issue in our system trying to consume a message from RabbitMQ that contained an `x-death` header, with count value typed as `Integer`. This caused a `ClassCastException`. The reason the count value was an int and not a long is that we were storing headers in an internal database as part of a recovery process, and the typing was slightly changed during serialisation / deserialisation. * Use `target.setRetryCount(numberValue.longValue());` in the `DefaultMessagePropertiesConverter` instead of cast to `long` Signed-off-by: Raul Avila [artem.bilan@broadcom.com Improve commit message] **Auto-cherry-pick to `3.2.x`** Signed-off-by: Artem Bilan --- .../DefaultMessagePropertiesConverter.java | 7 ++++++- .../DefaultMessagePropertiesConverterTests.java | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/DefaultMessagePropertiesConverter.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/DefaultMessagePropertiesConverter.java index 0d9e3cfd..728b43e9 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/DefaultMessagePropertiesConverter.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/DefaultMessagePropertiesConverter.java @@ -44,6 +44,7 @@ import org.springframework.util.StringUtils; * @author Artem Bilan * @author Ngoc Nhan * @author Johan Kaving + * @author Raul Avila * * @since 1.0 */ @@ -147,7 +148,11 @@ public class DefaultMessagePropertiesConverter implements MessagePropertiesConve if (target.getRetryCount() == 0) { List> xDeathHeader = target.getXDeathHeader(); if (!CollectionUtils.isEmpty(xDeathHeader)) { - target.setRetryCount((long) xDeathHeader.get(0).get("count")); + Object value = xDeathHeader.get(0).get("count"); + + if (value instanceof Number numberValue) { + target.setRetryCount(numberValue.longValue()); + } } } diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/DefaultMessagePropertiesConverterTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/DefaultMessagePropertiesConverterTests.java index 91ce1189..dd2cc1ea 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/DefaultMessagePropertiesConverterTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/DefaultMessagePropertiesConverterTests.java @@ -104,6 +104,21 @@ public class DefaultMessagePropertiesConverterTests { assertThat(((Map) messageProperties.getHeaders().get("map")).get("longString")).as("LongString nested in Map not converted to String").isEqualTo(longStringString); } + @Test + public void testToMessagePropertiesXDeathCount() { + Map headers = new HashMap(); + + headers.put("x-death", List.of(Map.of("count", Integer.valueOf(2)))); + + BasicProperties source = new BasicProperties.Builder() + .headers(headers) + .build(); + + MessageProperties messageProperties = messagePropertiesConverter.toMessageProperties(source, envelope, "UTF-8"); + + assertThat(messageProperties.getRetryCount()).isEqualTo(2); + } + @Test public void testLongLongString() { Map headers = new HashMap();