Skip to content

fix: deserialize generic collection types with correct element types#16272

Open
EvanYao826 wants to merge 2 commits into
apache:3.3from
EvanYao826:fix/generic-collection-type-deserialization
Open

fix: deserialize generic collection types with correct element types#16272
EvanYao826 wants to merge 2 commits into
apache:3.3from
EvanYao826:fix/generic-collection-type-deserialization

Conversation

@EvanYao826
Copy link
Copy Markdown

Fixes #16197

Problem

Hessian2 deserializes all small integers as Integer, causing ClassCastException when the expected type is Byte, Short, etc.

// Consumer sends
List<Byte> byteList = List.of((byte)1, (byte)2, (byte)127);

// Provider receives
List<Integer> byteList = List.of(1, 2, 127); // ClassCastException!

Root cause: Dubbo passes only the erased Class (e.g., List.class) to the serialization framework during request deserialization, discarding the generic Type (e.g., List<Byte>). Hessian2 has no way to know the expected element type.

Fix

In Hessian2ObjectInput.readObjectOfType(), after deserializing with the erased class, check if the declared type is a ParameterizedType. If so, convert collection/map elements to match the declared generic type arguments.

Changes

  • Hessian2ObjectInput.java: Added convertGenericType() method that handles:

    • Collection types (List, Set) with element type conversion
    • Map types with key/value type conversion
    • Numeric type narrowing (Byte, Short, Float, Long, Double, Integer)
    • Both boxed and primitive number types
  • ReflectionMethodDescriptor.java: Added getGenericParameterTypes() method to expose generic type information

  • DecodeableRpcInvocation.java: Pass generic Type instead of erased Class to deserialization

  • Hessian2SerializationTest.java: Added comprehensive tests for:

    • List<Byte>, List<Short>, List<Float>, List<Long>, List<Double>
    • Map<String, Byte>, Map<String, Short>
    • Mixed type collections

Hessian2 deserializes all small integers as Integer, causing ClassCastException
when the expected type is Byte, Short, etc. This happens because Dubbo passes
only the erased Class (e.g., List.class) to the serialization framework,
discarding the generic Type (e.g., List<Byte>).

Fix: After deserialization, convert collection/map elements to match the
declared generic type arguments. Handles:
- Collection types (List, Set) with element type conversion
- Map types with key/value type conversion
- Numeric type narrowing (Byte, Short, Float, Long, Double, Integer)
- Both boxed and primitive number types

Fixes apache#16197
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented May 17, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 36.95%. Comparing base (3dbba26) to head (217ba35).

❗ There is a different number of reports uploaded between BASE (3dbba26) and HEAD (217ba35). Click for more details.

HEAD has 14 uploads less than BASE
Flag BASE (3dbba26) HEAD (217ba35)
samples-tests-java8 2 1
samples-tests-java21 2 1
integration-tests-java8 2 1
integration-tests-java21 2 1
unit-tests-java8 2 0
unit-tests-java25 2 0
unit-tests-java11 2 0
unit-tests-java17 2 0
unit-tests-java21 2 0
Additional details and impacted files
@@              Coverage Diff              @@
##                3.3   #16272       +/-   ##
=============================================
- Coverage     60.85%   36.95%   -23.91%     
+ Complexity    11779    11761       -18     
=============================================
  Files          1953     1952        -1     
  Lines         89186    89234       +48     
  Branches      13454    13395       -59     
=============================================
- Hits          54277    32974    -21303     
- Misses        29353    51663    +22310     
+ Partials       5556     4597      -959     
Flag Coverage Δ
integration-tests-java21 32.11% <ø> (-0.06%) ⬇️
integration-tests-java8 32.24% <ø> (-0.01%) ⬇️
samples-tests-java21 32.11% <ø> (-0.12%) ⬇️
samples-tests-java8 29.79% <ø> (-0.11%) ⬇️
unit-tests-java11 ?
unit-tests-java17 ?
unit-tests-java21 ?
unit-tests-java25 ?
unit-tests-java8 ?

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

[Bug] List<Byte>, List<Short>, Map<String, Byte> deserialized as List<Integer>, Map<String, Integer> on provider side

2 participants