apache/dubbo-go-hessian2

golang 作为 provider 返回范型类型时 java consumer 解析应答数据报错

marsmay opened this issue · 7 comments

dubbo-go-hessian2 版本 v1.9.4-0.20210917102639-74a8ece5f3cb;

项目主技术栈 java,dubbo 接口统一返回范型定义 com.xxx.common.Result:

public class Result <T> implements java.io.Serializable {
    private java.lang.String code;
    private java.lang.String message;
    private T data;
}
public interface MerchantFacade {
  Result<[]Merchant> List(String lang, Long page);
  Result<Merchant> Detail(Long merchantId, String lang, Long page);
}

golang 作为 provider 时,如下方式可正常工作:

type Merchant struct {
    //商户ID
    Id int64

    //商户名称
    Name string
}

func (Merchant) JavaClassName() string {
    return "com.xxx.common.app.voucher.provider.dto.Merchant"
}

type MerchantResponse struct {
    Code    string
    Message string
    Data    *Merchant
}

func (MerchantResponse) JavaClassName() string {
    return "com.xxx.common.Result"
}

type MerchantListResponse struct {
    Code    string
    Message string
    Data    []*Merchant
}

func (MerchantListResponse) JavaClassName() string {
    return "com.xxx.common.Result"
}

func init() {
    hessian.RegisterPOJO(&Merchant{})
    hessian.RegisterPOJO(&MerchantResponse{})
    hessian.RegisterPOJO(&MerchantListResponse{})
}
type MerchantProvider struct{}

func (p *MerchantProvider) Reference() string {
    return "MerchantProvider"
}

func (p *MerchantProvider) List(ctx context.Context, lang string, page int64) (rsp *protocol.MerchantListResponse, err error) {
    ...
}

func (p *MerchantProvider) Detail(ctx context.Context, merchantId int64, lang string, page int64) (rsp *protocol.MerchantResponse, err error) {
    ...
}

var Merchant = &MerchantProvider{}

func init() {
    config.SetProviderService(Merchant)
}

java 作为 consumer 可正常调用和解析数据;
当 golang 作为 consumer 时,为了方便解析返回数据,定义了一个范型结构体:

type Result struct {
    Code    string
    Message string
    Data    interface{}
}

func (Result) JavaClassName() string {
    return "com.xxx.common.Result"
}

func init() {
    hessian.RegisterPOJO(&Result{})
}

目前 golang 同时启动 provider 和 consumer 后,golang consumer 可以正常调用 java provider 并解析数据;
但 java consumer 调用 golang provider 会数据解析报错;

尝试将将 golang provider 的返回数据类型更换成 Result 范型,java consumer 依然无法解析;
目前解决方案是 golang provider 返回使用非范型的结构,每个接口定义不同 JavaClassName 的 response,修改后 java consumer 调用正常,golang consumer 调用范型返返回的 java provider 也正常;

期望 golang provider 的接口返回值为范型 Result 时,java consumer 可以正常调用并解析应答;

@marsmay 之前的版本可以吗?

@marsmay 之前的版本可以吗?

之前的版本是指 dubbo-go-hessian2 之前的版本么?

你试试统一用

type MerchantResponse struct {
    Code    string
    Message string
    Data    interface{}
}

func (MerchantResponse) JavaClassName() string {
    return "com.xxx.common.Result"
}

再通过反射处理Data

func req() {
res, err := api.List()

switch unpackType(reflect.TypeOf(res)) {
case reflect.Slice:
  if res0, ok := res.([]interface{}); ok {
    for _, v := range res0 {
      item := decode(v)
    }
  }
default:
  item := decode(res)
}
}

func decode(o interface{}) *Merchant {
  resJson, err := json.Marshal(o)
  result := &Merchant{}
  _ =  json.Unmarshal(resJson, result)
  return result
}

@marsmay

你试试统一用

type MerchantResponse struct {
    Code    string
    Message string
    Data    interface{}
}

func (MerchantResponse) JavaClassName() string {
    return "com.xxx.common.Result"
}

再通过反射处理Data

golang consumer 用这个是没问题的,golang 这边我再类型判定一下就可以了。
但是 golang provider 用这个范型不行,java 那边解析不出来,你是说让 java 那边再反射处理么?
这个恐怕不行,他们那边统一处理的,用的 org.apache.dubbo.config.annotation.DubboReference,恐怕是没办法做也不想做这样的特殊处理的。

@ChangedenCZD 我感觉可能是遇到了你之前提的 #1454 这个问题,哎,现在要 java 调用方修改比较困难,实在不行只能我改 golang provider 的返回了,不用范型返回就行。golang consumer 调 java provider 还是可以用范型的。

@ChangedenCZD 我感觉可能是遇到了你之前提的 #1454 这个问题,哎,现在要 java 调用方修改比较困难,实在不行只能我改 golang provider 的返回了,不用范型返回就行。golang consumer 调 java provider 还是可以用范型的。

应该是能解决的,我过几天有空重现一下你的问题,理论上java不用改

@ChangedenCZD 我更新到 1.9.4 正式版,已经没有问题了,之前使用的是 v1.9.4-0.20210917102639-74a8ece5f3cb;
十分感谢,看到 1.9.4 的 release log 意识到可能已经解决了,就试试了,现在没问题了。