Skip to content

Commit 3e451e6

Browse files
garyrussellartembilan
authored andcommitted
GH-1021: Fix @SendTo after error is handled
Fixes #1021 Sending the result from a `RabbitListenerErrorHandler` was broken for class-level `@RabbitListener` because the send to expression was lost. **cherry-pick to 2.1.x** * * Also capture the generic return type after the error is handled
1 parent cf030af commit 3e451e6

File tree

4 files changed

+44
-7
lines changed

4 files changed

+44
-7
lines changed

spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/adapter/DelegatingInvocableHandler.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,4 +272,14 @@ public boolean hasDefaultHandler() {
272272
return this.defaultHandler != null;
273273
}
274274

275+
@Nullable
276+
public InvocationResult getInvocationResultFor(Object result, Object inboundPayload) {
277+
InvocableHandlerMethod handler = findHandlerForPayload(inboundPayload.getClass());
278+
if (handler != null) {
279+
return new InvocationResult(result, this.handlerSendTo.get(handler),
280+
handler.getMethod().getGenericReturnType());
281+
}
282+
return null;
283+
}
284+
275285
}

spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/adapter/HandlerAdapter.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.amqp.rabbit.listener.adapter;
1818

19+
import org.springframework.lang.Nullable;
1920
import org.springframework.messaging.Message;
2021
import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
2122

@@ -94,5 +95,14 @@ public Object getBean() {
9495
}
9596
}
9697

98+
@Nullable
99+
public InvocationResult getInvocationResultFor(Object result, Object inboundPayload) {
100+
if (this.invokerHandlerMethod != null) {
101+
return new InvocationResult(result, null, this.invokerHandlerMethod.getMethod().getGenericReturnType());
102+
}
103+
else {
104+
return this.delegatingHandler.getInvocationResultFor(result, inboundPayload);
105+
}
106+
}
97107

98108
}

spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/adapter/MessagingMessageListenerAdapter.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,8 @@ public void onMessage(org.springframework.amqp.core.Message amqpMessage, Channel
149149
.build();
150150
Object errorResult = this.errorHandler.handleError(amqpMessage, message, e);
151151
if (errorResult != null) {
152-
handleResult(new InvocationResult(errorResult, null, null), amqpMessage, channel, message);
152+
handleResult(this.handlerAdapter.getInvocationResultFor(errorResult, message.getPayload()),
153+
amqpMessage, channel, message);
153154
}
154155
else {
155156
logger.trace("Error handler returned no result");

spring-rabbit/src/test/java/org/springframework/amqp/rabbit/annotation/EnableRabbitIntegrationTests.java

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,11 @@ public void multiListener() {
345345
rabbitTemplate.convertAndSend("multi.exch", "multi.rk", bar);
346346
rabbitTemplate.setReceiveTimeout(10000);
347347
assertThat(this.rabbitTemplate.receiveAndConvert("sendTo.replies")).isEqualTo("BAR: bar");
348+
bar.field = "crash";
349+
rabbitTemplate.convertAndSend("multi.exch", "multi.rk", bar);
350+
assertThat(this.rabbitTemplate.receiveAndConvert("sendTo.replies"))
351+
.isEqualTo("CRASHCRASH Test reply from error handler");
352+
bar.field = "bar";
348353
Baz baz = new Baz();
349354
baz.field = "baz";
350355
assertThat(rabbitTemplate.convertSendAndReceive("multi.exch", "multi.rk", baz)).isEqualTo("BAZ: baz");
@@ -1550,14 +1555,22 @@ public MyService myService() {
15501555

15511556
@Bean
15521557
public RabbitListenerErrorHandler alwaysBARHandler() {
1553-
return (m, sm, e) -> "BAR";
1558+
return (msg, springMsg, ex) -> "BAR";
1559+
}
1560+
1561+
@Bean
1562+
public RabbitListenerErrorHandler upcaseAndRepeatErrorHandler() {
1563+
return (msg, springMsg, ex) -> {
1564+
String payload = ((Bar) springMsg.getPayload()).field.toUpperCase();
1565+
return payload + payload + " " + ex.getCause().getMessage();
1566+
};
15541567
}
15551568

15561569
@Bean
15571570
public RabbitListenerErrorHandler throwANewException() {
1558-
return (m, sm, e) -> {
1559-
this.errorHandlerChannel = sm.getHeaders().get(AmqpHeaders.CHANNEL, Channel.class);
1560-
throw new RuntimeException("from error handler", e.getCause());
1571+
return (msg, springMsg, ex) -> {
1572+
this.errorHandlerChannel = springMsg.getHeaders().get(AmqpHeaders.CHANNEL, Channel.class);
1573+
throw new RuntimeException("from error handler", ex.getCause());
15611574
};
15621575
}
15631576

@@ -1637,7 +1650,7 @@ public TxClassLevel txClassLevel() {
16371650

16381651
@Bean
16391652
public org.springframework.amqp.core.Queue sendToReplies() {
1640-
return new org.springframework.amqp.core.Queue(sendToRepliesBean(), false, false, true);
1653+
return new org.springframework.amqp.core.Queue(sendToRepliesBean(), false, false, false);
16411654
}
16421655

16431656
@Bean
@@ -1672,12 +1685,15 @@ public DirectExchange internal() {
16721685
@RabbitListener(bindings = @QueueBinding
16731686
(value = @Queue,
16741687
exchange = @Exchange(value = "multi.exch", autoDelete = "true"),
1675-
key = "multi.rk"))
1688+
key = "multi.rk"), errorHandler = "upcaseAndRepeatErrorHandler")
16761689
static class MultiListenerBean {
16771690

16781691
@RabbitHandler
16791692
@SendTo("${foo.bar:#{sendToRepliesBean}}")
16801693
public String bar(@NonNull Bar bar) {
1694+
if (bar.field.equals("crash")) {
1695+
throw new RuntimeException("Test reply from error handler");
1696+
}
16811697
return "BAR: " + bar.field;
16821698
}
16831699

0 commit comments

Comments
 (0)