apache/dubbo-go-hessian2

Lost Java Map Class Name

zhengzepeng opened this issue · 1 comments

Java Code:

public class JavaDict extends HashMap<Object, Object> {
    ....
}

And i define:

type JavaDict map[string]interface{}

func (dict JavaDict) JavaClassName() string {
	return "xxxx.JavaDict"
}

So, when if first use java to encode the JavaDict Object , i get the []byte, and i use the dubbo-go-hessian2 to decode the []byte, everything is ok, i can the the JavaDict in go, but if i want to encode the JavaDict in go, it lost the classname, so i can not use the java to decode it.

dubbo-go-hessian2 use the map type to encode the JavaDict, so the map is BC_MAP_UNTYPED:

func (e *Encoder) encMap(m interface{}) error {
	var (
		err   error
		k     interface{}
		typ   reflect.Type
		value reflect.Value
		keys  []reflect.Value
	)

	value = reflect.ValueOf(m)

	// check ref
	if n, ok := e.checkRefMap(value); ok {
		e.buffer = encRef(e.buffer, n)
		return nil
	}

	// check whether it should encode the map as class.
	if mm, ok := m.(map[string]interface{}); ok {
		if _, ok = mm[ClassKey]; ok {
			return e.EncodeMapClass(mm)
		}
	}

	value = UnpackPtrValue(value)
	// check nil map
	if value.Kind() == reflect.Ptr && !value.Elem().IsValid() {
		e.buffer = EncNull(e.buffer)
		return nil
	}

	keys = value.MapKeys()

	e.buffer = encByte(e.buffer, BC_MAP_UNTYPED)
	if len(keys) > 0 {
		typ = value.Type().Key()
		for i := 0; i < len(keys); i++ {
			k, err = getMapKey(keys[i], typ)
			if err != nil {
				return perrors.Wrapf(err, "getMapKey(idx:%d, key:%+v)", i, keys[i])
			}
			if err = e.Encode(k); err != nil {
				return perrors.Wrapf(err, "failed to encode map key(idx:%d, key:%+v)", i, keys[i])
			}
			entryValueObj := value.MapIndex(keys[i]).Interface()
			if err = e.Encode(entryValueObj); err != nil {
				return perrors.Wrapf(err, "failed to encode map value(idx:%d, key:%+v, value:%+v)", i, k, entryValueObj)
			}
		}
	}

	e.buffer = encByte(e.buffer, BC_END)

	return nil
}

may be like that:

func (e *Encoder) encMap(m interface{}) error {
	var (
		err   error
		k     interface{}
		typ   reflect.Type
		value reflect.Value
		keys  []reflect.Value
	)

	value = reflect.ValueOf(m)

	// check ref
	if n, ok := e.checkRefMap(value); ok {
		e.buffer = encRef(e.buffer, n)
		return nil
	}

	// check whether it should encode the map as class.
	if mm, ok := m.(map[string]interface{}); ok {
		if _, ok = mm[ClassKey]; ok {
			return e.EncodeMapClass(mm)
		}
	}

	value = UnpackPtrValue(value)
	// check nil map
	if value.Kind() == reflect.Ptr && !value.Elem().IsValid() {
		e.buffer = EncNull(e.buffer)
		return nil
	}

	// if pojo, write class name first
	if p, ok := m.(POJO); ok {
		e.buffer = encByte(e.buffer, BC_MAP)
		e.buffer = encString(e.buffer, p.JavaClassName())
	} else {
		e.buffer = encByte(e.buffer, BC_MAP_UNTYPED)
	}

	keys = value.MapKeys()

	if len(keys) > 0 {
		typ = value.Type().Key()
		for i := 0; i < len(keys); i++ {
			k, err = getMapKey(keys[i], typ)
			if err != nil {
				return perrors.Wrapf(err, "getMapKey(idx:%d, key:%+v)", i, keys[i])
			}
			if err = e.Encode(k); err != nil {
				return perrors.Wrapf(err, "failed to encode map key(idx:%d, key:%+v)", i, keys[i])
			}
			entryValueObj := value.MapIndex(keys[i]).Interface()
			if err = e.Encode(entryValueObj); err != nil {
				return perrors.Wrapf(err, "failed to encode map value(idx:%d, key:%+v, value:%+v)", i, k, entryValueObj)
			}
		}
	}

	e.buffer = encByte(e.buffer, BC_END)

	return nil
}

So if m is POJO, write the classname first?

ok,I'll deal with it