Skip to content

Commit 380b964

Browse files
profhenryolegz
authored andcommitted
GH-1296: Fixed consumer with generics regression
Signed-off-by: Jan Henrik Wiesner <github@profhenry.de> Resolves #1297
1 parent c230b2e commit 380b964

2 files changed

Lines changed: 69 additions & 23 deletions

File tree

spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionTypeUtils.java

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -390,31 +390,33 @@ public static Type getInputType(Type functionType) {
390390

391391
ResolvableType resolvableFunctionType = ResolvableType.forType(functionType);
392392

393-
ResolvableType resolvableInputType = resolvableFunctionType.as(resolvableFunctionType.getRawClass());
394-
395-
if (resolvableInputType.getType() instanceof ParameterizedType) {
396-
return resolvableInputType.getGeneric(0).getType();
393+
if (FunctionTypeUtils.isFunction(functionType)) {
394+
return extractInputType(resolvableFunctionType.as(Function.class).getGeneric(0));
397395
}
398-
else {
399-
// will try another way. See GH-1251
400-
if (FunctionTypeUtils.isFunction(functionType)) {
401-
resolvableInputType = resolvableFunctionType.as(Function.class);
402-
}
403-
else {
404-
if (KotlinDetector.isKotlinPresent() && Function1.class.isAssignableFrom(getRawType(functionType))) { // Kotlin
405-
return ResolvableType.forType(getImmediateGenericType(functionType, 1)).getType();
406-
}
407-
else {
408-
resolvableInputType = resolvableFunctionType.as(Consumer.class);
409-
}
410-
}
411-
if (resolvableInputType.getType() instanceof ParameterizedType) {
412-
return resolvableInputType.getGeneric(0).getType();
413-
}
414-
else {
415-
return Object.class;
416-
}
396+
if (FunctionTypeUtils.isConsumer(functionType)) {
397+
return extractInputType(resolvableFunctionType.as(Consumer.class).getGeneric(0));
398+
}
399+
if (KotlinDetector.isKotlinPresent() && Function1.class.isAssignableFrom(getRawType(functionType))) { // Kotlin
400+
return ResolvableType.forType(getImmediateGenericType(functionType, 1)).getType();
417401
}
402+
403+
// no consumer or function
404+
// might be one of the other supported types (as asserted in first line of method)
405+
// for example FunctionRegistration or IntConsumer
406+
407+
// unclear what the contract is in such a case
408+
// maybe returning null here might be "more" correct
409+
return Object.class;
410+
}
411+
412+
private static Type extractInputType(ResolvableType resolvableInputType) {
413+
if (resolvableInputType.getType() instanceof TypeVariable) {
414+
// In case the input type is a type variable (e.g. as in GH-1251) we need to resolve the type
415+
// For the case that the type is unbound Object.class is used
416+
return resolvableInputType.resolve(Object.class);
417+
}
418+
419+
return resolvableInputType.getType();
418420
}
419421

420422
@SuppressWarnings("rawtypes")

spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/FunctionTypeUtilsTests.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646

4747
import org.springframework.core.ParameterizedTypeReference;
4848
import org.springframework.messaging.Message;
49+
import org.springframework.util.ReflectionUtils;
4950

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

@@ -63,6 +64,24 @@ public void testDiscoverFunctionalMethod() throws Exception {
6364
assertThat(method.getName()).isEqualTo("accept");
6465
}
6566

67+
private Type getBeanType(Class<?> configurationClass, String beanMethodName) {
68+
return ReflectionUtils.findMethod(configurationClass, beanMethodName).getGenericReturnType();
69+
}
70+
71+
@Test
72+
public void testInputType() {
73+
Type type;
74+
Type inputType;
75+
76+
type = getBeanType(Gh1251Configuration.class, "consumer2");
77+
inputType = FunctionTypeUtils.getInputType(type);
78+
assertThat(inputType).isEqualTo(String.class);
79+
80+
type = getBeanType(Gh1251Configuration.class, "consumer3");
81+
inputType = FunctionTypeUtils.getInputType(type);
82+
assertThat(inputType).isEqualTo(String.class);
83+
}
84+
6685
@Test
6786
public void testFunctionTypeFrom() throws Exception {
6887
Type type = FunctionTypeUtils.discoverFunctionTypeFromClass(SimpleConsumer.class);
@@ -288,6 +307,31 @@ public void accept(Flux<Message<String>> messageFlux) {
288307
}
289308
}
290309

310+
static class Gh1251Configuration {
311+
312+
Gh1251Consumer2<Integer> consumer2() {
313+
return new Gh1251Consumer2<Integer>();
314+
}
315+
316+
Gh1251Consumer3<String> consumer3() {
317+
return new Gh1251Consumer3<>();
318+
}
319+
}
320+
321+
static class Gh1251Consumer2<E> implements Consumer<String> {
322+
323+
@Override
324+
public void accept(String message) {
325+
}
326+
}
327+
328+
static class Gh1251Consumer3<E> implements Consumer<E> {
329+
330+
@Override
331+
public void accept(E message) {
332+
}
333+
}
334+
291335
public interface ReactiveFunction<S, T> extends Function<Flux<S>, Flux<T>> {
292336

293337
}

0 commit comments

Comments
 (0)