uuuyuqi commented on PR #16198: URL: https://github.com/apache/dubbo/pull/16198#issuecomment-4219646137
@oxsean Thanks for the review! Here is the complete reproduction demo: **Demo repo**: https://github.com/uuuyuqi/dubbo3-list-byte-bug-demo Clone, start Nacos, run `mvn spring-boot:run` for provider & consumer, then `curl http://localhost:8082/testByte`. With Dubbo 3.3.6, all `Byte` elements become `Integer` on the provider side. ### Root cause explained The issue is specific to **hessian2 serialization** with narrow number types (`Byte`, `Short`, `Float`) inside collections/maps. It is **not** about generic calls or `PojoUtils` — this happens with normal strongly-typed RPC calls. Here is why: 1. **Hessian2 does not preserve the concrete type for small integers during serialization.** When hessian2 serializes a `Byte` value like `(byte) 1`, it writes it as a compact integer (single-byte encoding `0x91`). There is no type tag distinguishing `Byte` from `Integer` — it's just a number in the wire format. This is by design in the hessian2 protocol for compactness. 2. **During deserialization, hessian2 reads this compact integer and produces `Integer` by default**, because it has no information about the target element type. The call chain is: ``` DecodeableRpcInvocation.drawArgs() → in.readObject(List.class) // only raw Class, no generic info → hessian2 deserializes the list → reads each element as Integer // no way to know it should be Byte ``` 3. **The generic type information IS available** via `Method.getGenericParameterTypes()` on the provider side (local reflection, no wire transmission needed), but Dubbo never passes it to the serialization layer. The `ObjectInput.readObject(Class, Type)` API already exists in Dubbo's serialization interface but was never utilized in the deserialization path. This fix simply connects the existing dots: - `ReflectionMethodDescriptor` already calls `method.getParameterTypes()` → now also calls `method.getGenericParameterTypes()` - `DecodeableRpcInvocation.drawArgs()` already calls `in.readObject(Class)` → now calls `in.readObject(Class, Type)` when generic info is available - `Hessian2ObjectInput.readObject(Class, Type)` already exists but ignored the `Type` param → now uses it to post-convert narrow number types No changes to the wire protocol, no impact on non-generic parameters (the `Type` equals the raw `Class` for non-parameterized types, so the original code path is used). -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
