Repository navigation
[Bug] Async wildcard and generic-array return types fail reflection and produce incorrect payload metadata #16501
Description
Pre-check
- I am sure that all the content I provide is in English.
Search before asking
- I had searched in the issues and found no similar issues.
Apache Dubbo Component
Java SDK (apache/dubbo)
Dubbo Version
Apache Dubbo source: 3.3.7-SNAPSHOT, branch 3.3, commit ae809de2fc81b408194240965eb20bf27e6971df.
Windows, OpenJDK 21, Maven 3.6.3.
Verification used an isolated Maven/JUnit harness: eight relevant implementation/interface files were copied byte-for-byte from this commit, with released Dubbo 3.3.6 artifacts supplying supporting dependencies. The paths under review were compiled from the current source, not taken from those dependency jars. This is not a full current-branch reactor build or a networked RPC deployment.
Steps to reproduce this issue
Legal asynchronous return signatures containing a wildcard or a generic array throw ClassCastException in ReflectUtils.getReturnTypes. ReflectionMethodDescriptor catches the exception but then records CompletableFuture itself as the response type, losing the actual payload type. A plain CompletableFuture control succeeds.
Executed JUnit Jupiter reproducer:
import java.lang.reflect.Type;
import java.util.concurrent.CompletableFuture;
import org.apache.dubbo.common.utils.ReflectUtils;
import org.apache.dubbo.rpc.model.ReflectionMethodDescriptor;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class AsyncReturnTypesTest {
interface Api<T> {
CompletableFuture<String> plain();
CompletableFuture<? extends CharSequence> wildcard();
CompletableFuture<T[]> array();
}
@Test void plainControl() throws Exception {
assertEquals(String.class,
ReflectUtils.getReturnTypes(Api.class.getMethod("plain"))[0]);
}
@Test void wildcardMustNotThrow() {
Type[] result = assertDoesNotThrow(() ->
ReflectUtils.getReturnTypes(Api.class.getMethod("wildcard")));
assertEquals(CharSequence.class, result[0]);
}
@Test void genericArrayMustNotThrow() {
Type[] result = assertDoesNotThrow(() ->
ReflectUtils.getReturnTypes(Api.class.getMethod("array")));
assertEquals(Object[].class, result[0]);
}
@Test void descriptorMustNotUseFutureAsPayloadType() throws Exception {
ReflectionMethodDescriptor descriptor =
new ReflectionMethodDescriptor(Api.class.getMethod("wildcard"));
assertEquals(CharSequence.class, descriptor.getReturnTypes()[0]);
}
}What you expected to happen
Resolve the raw payload class/bounds without casting arbitrary java.lang.reflect.Type instances to Class; preserve the generic payload type where possible. For these signatures the raw types are CharSequence and Object[]. The descriptor should not silently substitute CompletableFuture for the payload.
Observed results:
WildcardTypeImpl cannot be cast to java.lang.Class
at ReflectUtils.getReturnTypes(ReflectUtils.java:1188)
GenericArrayTypeImpl cannot be cast to java.lang.Class
at ReflectUtils.getReturnTypes(ReflectUtils.java:1188)
wildcard descriptor response: class java.util.concurrent.CompletableFuture
expected: <java.lang.CharSequence> but was: <java.util.concurrent.CompletableFuture>
The plain CompletableFuture control passed. Three regressions failed as shown above.
Anything else
Root-cause locations: ReflectUtils.getReturnTypes and ReflectionMethodDescriptor constructor. The fallback branch assumes a Future type argument is a Class when it is neither ParameterizedType nor TypeVariable; WildcardType and GenericArrayType also occur in ordinary Java signatures.
These are src/main/java implementations used for RPC method metadata, not test utilities. I verified the reflection/descriptor path only; a complete exported service and wire deserialization scenario was not tested.
Searched getReturnTypes, WildcardType/Future and GenericArrayType/Future reports. #7040 covered the older direct TypeVariable case; the current code handles that case, while the wildcard/generic-array cases above still fail. A possible fix is recursive raw-type resolution with explicit handling for wildcard bounds and generic arrays, with regression coverage for both and the plain Future control.
Do you have a (mini) reproduction demo?
- Yes, I have a minimal reproduction demo to help resolve this issue more effectively!
Are you willing to submit a pull request to fix on your own?
- Yes I am willing to submit a pull request on my own!
Code of Conduct
- I agree to follow this project's Code of Conduct
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsTodo
Activity