Hessian2 跨语言类型排查
分析 Dubbo-go 与 Java 服务互调时的整数参数和 Hessian2 枚举类型问题。
Hessian2 跨语言类型排查
Issue:dubbo-go 调用问题。
复现环境与问题
- Java Server:Dubbo v3.0.14。
- Go Client:Dubbo-go v3.1.1。
- Dubbo 协议,Nacos v2.1.2。
Go 客户端无法调用 Java 服务。在调试并复现后,问题定位到 QueryDataSource 的参数类型。
整数类型匹配
原来的客户端字段声明:
QueryDataSource func(ctx context.Context, id int) (*DataSource, error) `dubbo:"queryDataSource"`
Java 的 int 固定为 32 位,Go 的 int 与平台有关,不能仅凭名字相同就认为跨语言映射相同。对应 Java int 的参数改用明确的 int32:
QueryDataSource func(ctx context.Context, id int32) (*DataSource, error) `dubbo:"queryDataSource"`
Go 的 int / uint 与平台有关;int8、int16、int32、int64 及相应固定宽度的无符号类型,宽度由类型名确定。这里是针对该调用签名提出的修改,不应把所有参数都统一替换成 int32。
Java 枚举如何表示
原定义直接把 Java 枚举映射为字符串:
Type string `hessian:"type"` // Mapped from Java enum
可以使用 dubbo-go-hessian2 枚举生成工具,保留 Java 类名、枚举名称和注册信息。下面是一份生成代码示例:
package enum
import (
"strconv"
)
import (
hessian "github.com/apache/dubbo-go-hessian2"
)
const (
TestColorEnumRed TestColorEnum = iota
TestColorEnumBlue
TestColorEnumYellow
)
var _TestColorEnumValues = map[TestColorEnum]string{
TestColorEnumRed: "RED",
TestColorEnumBlue: "BLUE",
TestColorEnumYellow: "YELLOW",
}
var _TestColorEnumEntities = map[string]TestColorEnum{
"RED": TestColorEnumRed,
"BLUE": TestColorEnumBlue,
"YELLOW": TestColorEnumYellow,
}
type TestColorEnum hessian.JavaEnum
func (e TestColorEnum) JavaClassName() string {
return "com.test.enums.TestColorEnum"
}
func (e TestColorEnum) String() string {
if v, ok := _TestColorEnumValues[e]; ok {
return v
}
return strconv.Itoa(int(e))
}
func (e TestColorEnum) EnumValue(s string) hessian.JavaEnum {
if v, ok := _TestColorEnumEntities[s]; ok {
return hessian.JavaEnum(v)
}
return hessian.InvalidJavaEnum
}
func NewTestColorEnum(s string) TestColorEnum {
if v, ok := _TestColorEnumEntities[s]; ok {
return v
}
return TestColorEnum(hessian.InvalidJavaEnum)
}
func init() {
for v := range _TestColorEnumValues {
hessian.RegisterJavaEnum(v)
}
}
关键在这几个位置:
TestColorEnum基于hessian.JavaEnum定义枚举值。- 两张 map 维护 Go 值与 Java 名称之间的双向映射。
JavaClassName()提供完整 Java 类名。String()输出枚举名称,未知值则输出数值字符串。EnumValue()返回hessian.JavaEnum,NewTestColorEnum()返回具体类型;未知名称对应无效枚举值。init()调用RegisterJavaEnum完成注册。
跨语言调用不仅要对齐值,也要对齐方法签名与序列化类型信息。