Skip to content

Commit 966338e

Browse files
raylaxartembilan
authored andcommitted
GH-2602: Fix x-delay header to Long
Fixes: #2602 * Update deprecated API * Fix code style * Remove deprecated API usage * Some code clean of the affected classes
1 parent cb15cf5 commit 966338e

File tree

6 files changed

+149
-57
lines changed

6 files changed

+149
-57
lines changed

Diff for: spring-amqp/src/main/java/org/springframework/amqp/core/MessageProperties.java

+71-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,8 @@
2424
import java.util.List;
2525
import java.util.Map;
2626

27+
import org.springframework.util.Assert;
28+
2729
/**
2830
* Message Properties for an AMQP message.
2931
*
@@ -33,6 +35,7 @@
3335
* @author Dmitry Chernyshov
3436
* @author Artem Bilan
3537
* @author Csaba Soti
38+
* @author Raylax Grey
3639
*/
3740
public class MessageProperties implements Serializable {
3841

@@ -66,6 +69,12 @@ public class MessageProperties implements Serializable {
6669

6770
public static final Integer DEFAULT_PRIORITY = 0;
6871

72+
/**
73+
* The maximum value of x-delay header.
74+
* @since 3.1.2
75+
*/
76+
public static final long X_DELAY_MAX = 0xffffffffL;
77+
6978
private final Map<String, Object> headers = new HashMap<>();
7079

7180
private Date timestamp;
@@ -118,7 +127,7 @@ public class MessageProperties implements Serializable {
118127

119128
private String consumerQueue;
120129

121-
private Integer receivedDelay;
130+
private Long receivedDelay;
122131

123132
private MessageDeliveryMode receivedDeliveryMode;
124133

@@ -352,19 +361,46 @@ public String getReceivedRoutingKey() {
352361
* received message contains the delay.
353362
* @return the received delay.
354363
* @since 1.6
364+
* @deprecated in favor of {@link #getReceivedDelayLong()}
355365
* @see #getDelay()
356366
*/
367+
@Deprecated(since = "3.1.2", forRemoval = true)
357368
public Integer getReceivedDelay() {
358-
return this.receivedDelay;
369+
Long receivedDelay = getReceivedDelayLong();
370+
return receivedDelay != null ? Math.toIntExact(receivedDelay) : null;
359371
}
360372

361373
/**
362374
* When a delayed message exchange is used the x-delay header on a
363375
* received message contains the delay.
364376
* @param receivedDelay the received delay.
365377
* @since 1.6
378+
* @deprecated in favor of {@link #setReceivedDelayLong(Long)}
366379
*/
380+
@Deprecated(since = "3.1.2", forRemoval = true)
367381
public void setReceivedDelay(Integer receivedDelay) {
382+
setReceivedDelayLong(receivedDelay != null ? receivedDelay.longValue() : null);
383+
}
384+
385+
/**
386+
* When a delayed message exchange is used the x-delay header on a
387+
* received message contains the delay.
388+
* @return the received delay.
389+
* @since 3.1.2
390+
* @see #getDelayLong()
391+
*/
392+
public Long getReceivedDelayLong() {
393+
return this.receivedDelay;
394+
}
395+
396+
/**
397+
* When a delayed message exchange is used the x-delay header on a
398+
* received message contains the delay.
399+
* @param receivedDelay the received delay.
400+
* @since 3.1.2
401+
* @see #setDelayLong(Long)
402+
*/
403+
public void setReceivedDelayLong(Long receivedDelay) {
368404
this.receivedDelay = receivedDelay;
369405
}
370406

@@ -434,30 +470,54 @@ public void setConsumerQueue(String consumerQueue) {
434470
* The x-delay header (outbound).
435471
* @return the delay.
436472
* @since 1.6
473+
* @deprecated in favor of {@link #getDelayLong()}
437474
* @see #getReceivedDelay()
438475
*/
476+
@Deprecated(since = "3.1.2", forRemoval = true)
439477
public Integer getDelay() {
478+
Long delay = getDelayLong();
479+
return delay != null ? Math.toIntExact(delay) : null;
480+
}
481+
482+
/**
483+
* Set the x-delay header.
484+
* @param delay the delay.
485+
* @since 1.6
486+
* @deprecated in favor of {@link #setDelayLong(Long)}
487+
*/
488+
@Deprecated(since = "3.1.2", forRemoval = true)
489+
public void setDelay(Integer delay) {
490+
setDelayLong(delay != null ? delay.longValue() : null);
491+
}
492+
493+
/**
494+
* Get the x-delay header long value.
495+
* @return the delay.
496+
* @since 3.1.2
497+
*/
498+
public Long getDelayLong() {
440499
Object delay = this.headers.get(X_DELAY);
441-
if (delay instanceof Integer) {
442-
return (Integer) delay;
500+
if (delay instanceof Long) {
501+
return (Long) delay;
443502
}
444503
else {
445504
return null;
446505
}
447506
}
448507

449508
/**
450-
* Set the x-delay header.
509+
* Set the x-delay header to a long value.
451510
* @param delay the delay.
452-
* @since 1.6
511+
* @since 3.1.2
453512
*/
454-
public void setDelay(Integer delay) {
513+
public void setDelayLong(Long delay) {
455514
if (delay == null || delay < 0) {
456515
this.headers.remove(X_DELAY);
516+
return;
457517
}
458-
else {
459-
this.headers.put(X_DELAY, delay);
460-
}
518+
519+
Assert.isTrue(delay <= X_DELAY_MAX, "Delay cannot exceed " + X_DELAY_MAX);
520+
this.headers.put(X_DELAY, delay);
461521
}
462522

463523
public boolean isFinalRetryForMessageWithNoId() {

Diff for: spring-amqp/src/main/java/org/springframework/amqp/support/SimpleAmqpHeaderMapper.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -48,6 +48,7 @@
4848
* @author Gary Russell
4949
* @author Artem Bilan
5050
* @author Stephane Nicoll
51+
* @author Raylax Grey
5152
* @since 1.4
5253
*/
5354
public class SimpleAmqpHeaderMapper extends AbstractHeaderMapper<MessageProperties> implements AmqpHeaderMapper {
@@ -69,8 +70,8 @@ public void fromHeaders(MessageHeaders headers, MessageProperties amqpMessagePro
6970
amqpMessageProperties.setCorrelationId((String) correlationId);
7071
}
7172
javaUtils
72-
.acceptIfNotNull(getHeaderIfAvailable(headers, AmqpHeaders.DELAY, Integer.class),
73-
amqpMessageProperties::setDelay)
73+
.acceptIfNotNull(getHeaderIfAvailable(headers, AmqpHeaders.DELAY, Long.class),
74+
amqpMessageProperties::setDelayLong)
7475
.acceptIfNotNull(getHeaderIfAvailable(headers, AmqpHeaders.DELIVERY_MODE, MessageDeliveryMode.class),
7576
amqpMessageProperties::setDeliveryMode)
7677
.acceptIfNotNull(getHeaderIfAvailable(headers, AmqpHeaders.DELIVERY_TAG, Long.class),
@@ -150,7 +151,7 @@ public MessageHeaders toHeaders(MessageProperties amqpMessageProperties) {
150151
javaUtils
151152
.acceptIfCondition(priority != null && priority > 0, AmqpMessageHeaderAccessor.PRIORITY, priority,
152153
putObject)
153-
.acceptIfNotNull(AmqpHeaders.RECEIVED_DELAY, amqpMessageProperties.getReceivedDelay(), putObject)
154+
.acceptIfNotNull(AmqpHeaders.RECEIVED_DELAY, amqpMessageProperties.getReceivedDelayLong(), putObject)
154155
.acceptIfHasText(AmqpHeaders.RECEIVED_EXCHANGE, amqpMessageProperties.getReceivedExchange(),
155156
putString)
156157
.acceptIfHasText(AmqpHeaders.RECEIVED_ROUTING_KEY, amqpMessageProperties.getReceivedRoutingKey(),

Diff for: spring-amqp/src/test/java/org/springframework/amqp/core/MessagePropertiesTests.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@
3030
* @author Artem Bilan
3131
* @author Gary Russell
3232
* @author Csaba Soti
33+
* @author Raylax Grey
3334
*
3435
*/
3536
public class MessagePropertiesTests {
@@ -53,10 +54,10 @@ public void testReplyToNullByDefault() {
5354
@Test
5455
public void testDelayHeader() {
5556
MessageProperties properties = new MessageProperties();
56-
Integer delay = 100;
57-
properties.setDelay(delay);
57+
Long delay = 100L;
58+
properties.setDelayLong(delay);
5859
assertThat(properties.getHeaders().get(MessageProperties.X_DELAY)).isEqualTo(delay);
59-
properties.setDelay(null);
60+
properties.setDelayLong(null);
6061
assertThat(properties.getHeaders().containsKey(MessageProperties.X_DELAY)).isFalse();
6162
}
6263

Diff for: spring-amqp/src/test/java/org/springframework/amqp/support/SimpleAmqpHeaderMapperTests.java

+36-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
1717
package org.springframework.amqp.support;
1818

1919
import static org.assertj.core.api.Assertions.assertThat;
20+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
2021
import static org.assertj.core.api.Assertions.fail;
2122

2223
import java.util.Date;
@@ -37,21 +38,22 @@
3738
* @author Mark Fisher
3839
* @author Gary Russell
3940
* @author Oleg Zhurakousky
41+
* @author Raylax Grey
4042
*/
4143
public class SimpleAmqpHeaderMapperTests {
4244

4345
@Test
4446
public void fromHeaders() {
4547
SimpleAmqpHeaderMapper headerMapper = new SimpleAmqpHeaderMapper();
46-
Map<String, Object> headerMap = new HashMap<String, Object>();
48+
Map<String, Object> headerMap = new HashMap<>();
4749
headerMap.put(AmqpHeaders.APP_ID, "test.appId");
4850
headerMap.put(AmqpHeaders.CLUSTER_ID, "test.clusterId");
4951
headerMap.put(AmqpHeaders.CONTENT_ENCODING, "test.contentEncoding");
5052
headerMap.put(AmqpHeaders.CONTENT_LENGTH, 99L);
5153
headerMap.put(AmqpHeaders.CONTENT_TYPE, "test.contentType");
5254
String testCorrelationId = "foo";
5355
headerMap.put(AmqpHeaders.CORRELATION_ID, testCorrelationId);
54-
headerMap.put(AmqpHeaders.DELAY, 1234);
56+
headerMap.put(AmqpHeaders.DELAY, 1234L);
5557
headerMap.put(AmqpHeaders.DELIVERY_MODE, MessageDeliveryMode.NON_PERSISTENT);
5658
headerMap.put(AmqpHeaders.DELIVERY_TAG, 1234L);
5759
headerMap.put(AmqpHeaders.EXPIRATION, "test.expiration");
@@ -92,13 +94,39 @@ public void fromHeaders() {
9294
assertThat(amqpProperties.getTimestamp()).isEqualTo(testTimestamp);
9395
assertThat(amqpProperties.getType()).isEqualTo("test.type");
9496
assertThat(amqpProperties.getUserId()).isEqualTo("test.userId");
95-
assertThat(amqpProperties.getDelay()).isEqualTo(Integer.valueOf(1234));
97+
assertThat(amqpProperties.getDelayLong()).isEqualTo(Long.valueOf(1234));
9698
}
9799

100+
@Test
101+
public void fromHeadersWithLongDelay() {
102+
SimpleAmqpHeaderMapper headerMapper = new SimpleAmqpHeaderMapper();
103+
Map<String, Object> headerMap = new HashMap<>();
104+
headerMap.put(AmqpHeaders.DELAY, 1234L);
105+
MessageHeaders messageHeaders = new MessageHeaders(headerMap);
106+
MessageProperties amqpProperties = new MessageProperties();
107+
headerMapper.fromHeaders(messageHeaders, amqpProperties);
108+
assertThat(amqpProperties.getDelayLong()).isEqualTo(Long.valueOf(1234));
109+
110+
amqpProperties.setDelayLong(5678L);
111+
assertThat(amqpProperties.getDelayLong()).isEqualTo(Long.valueOf(5678));
112+
113+
amqpProperties.setDelayLong(null);
114+
assertThat(amqpProperties.getHeaders().containsKey(AmqpHeaders.DELAY)).isFalse();
115+
116+
amqpProperties.setDelayLong(MessageProperties.X_DELAY_MAX);
117+
assertThat(amqpProperties.getDelayLong()).isEqualTo(Long.valueOf(MessageProperties.X_DELAY_MAX));
118+
119+
assertThatThrownBy(() -> amqpProperties.setDelayLong(MessageProperties.X_DELAY_MAX + 1))
120+
.isInstanceOf(IllegalArgumentException.class)
121+
.hasMessageContaining("Delay cannot exceed");
122+
123+
}
124+
125+
98126
@Test
99127
public void fromHeadersWithContentTypeAsMediaType() {
100128
SimpleAmqpHeaderMapper headerMapper = new SimpleAmqpHeaderMapper();
101-
Map<String, Object> headerMap = new HashMap<String, Object>();
129+
Map<String, Object> headerMap = new HashMap<>();
102130

103131
headerMap.put(AmqpHeaders.CONTENT_TYPE, MimeTypeUtils.TEXT_HTML);
104132

@@ -126,7 +154,7 @@ public void toHeaders() {
126154
amqpProperties.setMessageCount(42);
127155
amqpProperties.setMessageId("test.messageId");
128156
amqpProperties.setPriority(22);
129-
amqpProperties.setReceivedDelay(1234);
157+
amqpProperties.setReceivedDelayLong(1234L);
130158
amqpProperties.setReceivedExchange("test.receivedExchange");
131159
amqpProperties.setReceivedRoutingKey("test.receivedRoutingKey");
132160
amqpProperties.setRedelivered(true);
@@ -151,7 +179,7 @@ public void toHeaders() {
151179
assertThat(headerMap.get(AmqpHeaders.EXPIRATION)).isEqualTo("test.expiration");
152180
assertThat(headerMap.get(AmqpHeaders.MESSAGE_COUNT)).isEqualTo(42);
153181
assertThat(headerMap.get(AmqpHeaders.MESSAGE_ID)).isEqualTo("test.messageId");
154-
assertThat(headerMap.get(AmqpHeaders.RECEIVED_DELAY)).isEqualTo(1234);
182+
assertThat(headerMap.get(AmqpHeaders.RECEIVED_DELAY)).isEqualTo(1234L);
155183
assertThat(headerMap.get(AmqpHeaders.RECEIVED_EXCHANGE)).isEqualTo("test.receivedExchange");
156184
assertThat(headerMap.get(AmqpHeaders.RECEIVED_ROUTING_KEY)).isEqualTo("test.receivedRoutingKey");
157185
assertThat(headerMap.get(AmqpHeaders.REPLY_TO)).isEqualTo("test.replyTo");
@@ -170,7 +198,7 @@ public void jsonTypeIdNotOverwritten() {
170198
Jackson2JsonMessageConverter converter = new Jackson2JsonMessageConverter();
171199
MessageProperties amqpProperties = new MessageProperties();
172200
converter.toMessage("123", amqpProperties);
173-
Map<String, Object> headerMap = new HashMap<String, Object>();
201+
Map<String, Object> headerMap = new HashMap<>();
174202
headerMap.put("__TypeId__", "java.lang.Integer");
175203
MessageHeaders messageHeaders = new MessageHeaders(headerMap);
176204
headerMapper.fromHeaders(messageHeaders, amqpProperties);

0 commit comments

Comments
 (0)