Skip to content
Permalink
Browse files

GH-910: Fix async return type erasure

Fixes #910

Further to the previous patch, avoid async return type erasure by using
the actual generic type of the async result, unless it is a wildcard type.
If it's a wildcard, fall back to the actual return object's type.
  • Loading branch information...
garyrussell authored and artembilan committed Feb 20, 2019
1 parent 891ba3b commit df0ee546c28681b49117b221aebff820c75bb785
@@ -17,7 +17,9 @@
package org.springframework.amqp.rabbit.listener.adapter;

import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.util.Arrays;
import java.util.function.Consumer;

@@ -344,8 +346,12 @@ else if (this.logger.isWarnEnabled()) {
}

private void asyncSuccess(InvocationResult resultArg, Message request, Channel channel, Object source, Object r) {
// Set the return type to null so the converter will use the actual returned object's class for type info
doHandleResult(new InvocationResult(r, resultArg.getSendTo(), null), request, channel, source);
Type returnType = ((ParameterizedType) resultArg.getReturnType()).getActualTypeArguments()[0];
if (returnType instanceof WildcardType) {
// Set the return type to null so the converter will use the actual returned object's class for type info
returnType = null;
}
doHandleResult(new InvocationResult(r, resultArg.getSendTo(), returnType), request, channel, source);
try {
channel.basicAck(request.getMessageProperties().getDeliveryTag(), false);
}
@@ -18,6 +18,9 @@

import static org.assertj.core.api.Assertions.assertThat;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

@@ -78,13 +81,22 @@
@Autowired
private Queue queue2;

@Autowired
private Queue queue3;

@Test
public void testAsyncListener() throws Exception {
assertThat(this.rabbitTemplate.convertSendAndReceive(this.queue1.getName(), "foo")).isEqualTo("FOO");
RabbitConverterFuture<Object> future = this.asyncTemplate.convertSendAndReceive(this.queue1.getName(), "foo");
assertThat(future.get(10, TimeUnit.SECONDS)).isEqualTo("FOO");
assertThat(this.config.typeId).isEqualTo("java.lang.String");
assertThat(this.rabbitTemplate.convertSendAndReceive(this.queue2.getName(), "foo")).isEqualTo("FOO");
assertThat(this.config.typeId).isEqualTo("java.lang.String");
List<String> foos = new ArrayList<>();
foos.add("FOO");
assertThat(this.rabbitTemplate.convertSendAndReceive(this.queue3.getName(), "foo")).isEqualTo(foos);
assertThat(this.config.typeId).isEqualTo("java.util.List");
assertThat(this.config.contentTypeId).isEqualTo("java.lang.String");
}

@Configuration
@@ -93,6 +105,8 @@ public void testAsyncListener() throws Exception {

private volatile Object typeId;

private volatile Object contentTypeId;

@Bean
public MessageConverter converter() {
return new Jackson2JsonMessageConverter();
@@ -121,6 +135,7 @@ public RabbitTemplate rabbitTemplate() {
template.setMessageConverter(converter());
template.setAfterReceivePostProcessors(m -> {
this.typeId = m.getMessageProperties().getHeaders().get("__TypeId__");
this.contentTypeId = m.getMessageProperties().getHeaders().get("__ContentTypeId__");
return m;
});
return template;
@@ -146,6 +161,11 @@ public Queue queue2() {
return new AnonymousQueue();
}

@Bean
public Queue queue3() {
return new AnonymousQueue();
}

@Bean
public Listener listener() {
return new Listener();
@@ -182,6 +202,11 @@ public Listener listener() {
}
}

@RabbitListener(id = "baz", queues = "#{queue3.name}")
public Mono<List<String>> listen3(String foo) {
return Mono.just(Collections.singletonList(foo.toUpperCase()));
}

}

}

0 comments on commit df0ee54

Please sign in to comment.
You can’t perform that action at this time.