Skip to content

fix: preserve generic parameter types during deserialization to fix List<Byte> → List<Integer> [3.2]#16199

Closed
uuuyuqi wants to merge 5 commits intoapache:3.2from
uuuyuqi:fix/generic-param-type-3.2
Closed

fix: preserve generic parameter types during deserialization to fix List<Byte> → List<Integer> [3.2]#16199
uuuyuqi wants to merge 5 commits intoapache:3.2from
uuuyuqi:fix/generic-param-type-3.2

Conversation

@uuuyuqi
Copy link
Copy Markdown

@uuuyuqi uuuyuqi commented Apr 9, 2026

Closes #16197

Summary

Backport of #16198 to the 3.2 branch.

When RPC methods have parameters like List<Byte>, Map<String, Byte>, or List<Short>, the provider-side deserialization incorrectly produces List<Integer> / Map<String, Integer> because the generic type information is discarded during deserialization.

This PR fixes the issue across three layers:

  • Model layer: Add getGenericParameterTypes() to MethodDescriptor (default method for backward compat) and implement it in ReflectionMethodDescriptor to expose Type[] for method parameters.
  • Protocol layer: Update DecodeableRpcInvocation.drawArgs() (Dubbo protocol) and ReflectionPackableMethod.WrapRequestUnpack (Triple protocol) to pass generic Type to the serialization framework when available.
  • Serialization layer: Fix Hessian2ObjectInput.readObject(Class, Type) to post-convert collection/map elements to the correct narrow number type (Byte, Short, Float).

No wire protocol changes needed. The fix leverages existing local reflection information on the provider side.

Changes

Layer File Change
Model MethodDescriptor.java Add default getGenericParameterTypes()
Model ReflectionMethodDescriptor.java Store and return generic parameter types
Dubbo Protocol DecodeableRpcInvocation.java Pass generic Type in drawArgs()
Triple Protocol ReflectionPackableMethod.java Pass generic Type in WrapRequestUnpack
Serialization API MultipleSerialization.java Add deserialize(url, type, clz, genericType, is) overload
Serialization API DefaultMultipleSerialization.java Implement the new overload
Serialization Impl Hessian2ObjectInput.java Post-convert collection/map elements to narrow types

Test plan

  • Unit tests for ReflectionMethodDescriptor.getGenericParameterTypes()
  • Unit tests for Hessian2ObjectInput.readObject(Class, Type) with List<Byte>, List<Short>, List<Float>, Map<String, Byte>
  • E2E tested with Dubbo protocol + hessian2: all Byte elements correctly deserialized
  • E2E tested with Triple protocol + hessian2: all Byte elements correctly deserialized
  • Verified with Arthas that new code paths are executed at runtime
  • Reproduced the bug on official Dubbo 3.3.6, confirmed the fix resolves it

Made with Cursor

uuuyuqi added 5 commits April 9, 2026 16:36
When RPC methods have parameters like List<Byte>, Map<String, Byte>,
or List<Short>, the provider-side deserialization incorrectly produces
List<Integer> / Map<String, Integer> because the generic type info
is discarded.

This fix addresses the issue across three layers:

1. Model layer: add getGenericParameterTypes() to MethodDescriptor
   (default method for backward compat) and implement it in
   ReflectionMethodDescriptor to expose Type[] for parameters.

2. Protocol layer: update DecodeableRpcInvocation.drawArgs() (Dubbo
   protocol) and ReflectionPackableMethod.WrapRequestUnpack (Triple
   protocol) to pass generic Type to the serialization framework.

3. Serialization layer: fix Hessian2ObjectInput.readObject(Class, Type)
   to post-convert collection/map elements to the correct narrow
   number type (Byte, Short, Float).

No wire protocol changes needed.

Change-Id: Ifefdd0cd9719de380ef5b3b6076e51123781cbb8
Co-developed-by: Cursor <noreply@cursor.com>
…ype)

Add NarrowNumberPojo with byte/short/float fields and List<Byte>/
Map<String, Byte> fields to verify that POJO deserialization via
readObject(Class, Type) is not affected by the generic type fix.

Change-Id: I07751b608827b03ad4ac7b02704b522751ecbea8
Co-developed-by: Cursor <noreply@cursor.com>
…ype handling

Use hessian2's built-in expectedTypes support instead of post-processing
conversion, as suggested in review.

Change-Id: I1cbb65a684f2f03aa7219826f1fa866b6d7d79cc
Co-developed-by: Cursor <noreply@cursor.com>
Hessian2Input.readObject(Class, Class...) expectedTypes mechanism
only works correctly for simple types. For complex POJO types like User,
passing the class as expectedType causes CollectionDeserializer to use
a wrong deserializer, leading to HessianProtocolException.

Change-Id: If909026ae4f9633155ffd5bd5c7b318aa77f492b
Co-developed-by: Cursor <noreply@cursor.com>
…pectedTypes filtering

Align the type filtering logic with hessian-lite's FieldDeserializer2Factory,
using isPrimitive() to cover all primitive wrapper types instead of only
narrow number types (Byte/Short/Float).

Change-Id: If4dd8f961ec3b3a8e4f2881a866f527777e7a47d
Co-developed-by: Cursor <noreply@cursor.com>
@zrlw
Copy link
Copy Markdown
Contributor

zrlw commented Apr 14, 2026

3.2 might not be maintained anymore.

@zrlw zrlw closed this Apr 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants