Merge pull request #261 from wongoo/fix-259
Fix map decode error issue #259
diff --git a/decode.go b/decode.go
index b916703..00b8461 100644
--- a/decode.go
+++ b/decode.go
@@ -33,7 +33,6 @@
reader *bufio.Reader
refs []interface{}
// record type refs, both list and map need it
- // todo: map
typeRefs *TypeRefs
classInfoList []*classInfo
isSkip bool
@@ -162,36 +161,52 @@
}
// read the type of data, used to decode list or map
-func (d *Decoder) decType() (string, error) {
+func (d *Decoder) decMapType() (reflect.Type, error) {
var (
- err error
- arr [1]byte
- buf []byte
- tag byte
- idx int32
- typ reflect.Type
+ err error
+ arr [1]byte
+ buf []byte
+ tag byte
+ idx int32
+ typ reflect.Type
+ typName string
)
buf = arr[:1]
if _, err = io.ReadFull(d.reader, buf); err != nil {
- return "", perrors.WithStack(err)
+ return nil, perrors.WithStack(err)
}
tag = buf[0]
if (tag >= BC_STRING_DIRECT && tag <= STRING_DIRECT_MAX) ||
(tag >= 0x30 && tag <= 0x33) || (tag == BC_STRING) || (tag == BC_STRING_CHUNK) {
- return d.decString(int32(tag))
+ typName, err = d.decString(int32(tag))
+ if err != nil {
+ return nil, perrors.WithStack(err)
+ }
+
+ info, ok := getStructInfo(typName)
+ if ok {
+ typ = info.typ
+ } else {
+ typ = reflect.TypeOf(map[interface{}]interface{}{})
+ }
+
+ // add to type map
+ d.typeRefs.appendTypeRefs(typName, typ)
+
+ return typ, nil
}
if idx, err = d.decInt32(int32(tag)); err != nil {
- return "", perrors.WithStack(err)
+ return nil, perrors.WithStack(err)
}
- typ, _, err = d.getStructDefByIndex(int(idx))
- if err == nil {
- return typ.String(), nil
+ typ = d.typeRefs.Get(int(idx))
+ if typ == nil {
+ return nil, perrors.Errorf("the type ref index %d is out of range", idx)
}
- return "", err
+ return typ, err
}
// Decode parse hessian data, and ensure the reflection value unpacked
diff --git a/decode_test.go b/decode_test.go
index 3c4dd95..0e57f45 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -110,7 +110,7 @@
func testDecodeJavaData(t *testing.T, method, className string, skip bool, expected interface{}) {
r, e := decodeJavaResponse(method, className, skip)
if e != nil {
- t.Errorf("%s: decode fail with error %v", method, e)
+ t.Errorf("%s: decode fail with error: %v", method, e)
return
}
diff --git a/map.go b/map.go
index 0d83d4e..d43b915 100644
--- a/map.go
+++ b/map.go
@@ -217,13 +217,12 @@
return nil
}
-// TODO to decode ref object in map
+// decode map object
func (d *Decoder) decMap(flag int32) (interface{}, error) {
var (
err error
tag byte
ok bool
- t string
m map[interface{}]interface{}
k interface{}
v interface{}
@@ -231,6 +230,7 @@
instValue reflect.Value
fieldName string
fieldValue reflect.Value
+ typ reflect.Type
)
if flag != TAG_READ {
@@ -245,67 +245,48 @@
case tag == BC_REF:
return d.decRef(int32(tag))
case tag == BC_MAP:
- if t, err = d.decType(); err != nil {
+ if typ, err = d.decMapType(); err != nil {
return nil, err
}
- _, ok = checkPOJORegistry(t)
- if ok {
- inst = createInstance(t)
- instValue = reflect.ValueOf(inst)
- d.appendRefs(inst)
- for d.peekByte() != BC_END {
- k, err = d.Decode()
- if err != nil {
- return nil, err
- }
- v, err = d.Decode()
- if err != nil {
- return nil, err
- }
+ if typ.Kind() == reflect.Map {
+ instValue = reflect.MakeMap(typ)
+ } else {
+ instValue = reflect.New(typ).Elem()
+ }
+ inst = instValue.Interface()
+
+ d.appendRefs(inst)
+
+ for d.peekByte() != BC_END {
+ k, err = d.Decode()
+ if err != nil {
+ return nil, err
+ }
+ v, err = d.Decode()
+ if err != nil {
+ return nil, err
+ }
+
+ if typ.Kind() == reflect.Map {
+ instValue.SetMapIndex(reflect.ValueOf(k), EnsureRawValue(v))
+ } else {
fieldName, ok = k.(string)
if !ok {
return nil, perrors.Errorf("the type of map key must be string, but get %v", k)
}
- if instValue.Kind() == reflect.Map {
- instValue.SetMapIndex(reflect.ValueOf(k), EnsureRawValue(v))
- } else {
- fieldValue = instValue.FieldByName(fieldName)
- if fieldValue.IsValid() {
- fieldValue.Set(EnsureRawValue(v))
- }
+ fieldValue = instValue.FieldByName(fieldName)
+ if fieldValue.IsValid() {
+ fieldValue.Set(EnsureRawValue(v))
}
}
- _, err = d.ReadByte()
- if err != nil {
- return nil, perrors.WithStack(err)
- }
- return inst, nil
- } else {
- m = make(map[interface{}]interface{})
- classIndex := RegisterPOJOMapping(t, m)
- d.appendClsDef(pojoRegistry.classInfoList[classIndex])
-
- d.appendRefs(m)
- for d.peekByte() != BC_END {
- k, err = d.Decode()
- if err != nil {
- return nil, err
- }
- v, err = d.Decode()
- if err != nil {
- return nil, err
- }
- m[k] = v
- }
- _, err = d.ReadByte()
- if err != nil {
- return nil, perrors.WithStack(err)
- }
- return m, nil
}
-
+ _, err = d.ReadByte()
+ if err != nil {
+ return nil, perrors.WithStack(err)
+ }
+ return inst, nil
case tag == BC_MAP_UNTYPED:
m = make(map[interface{}]interface{})
d.appendRefs(m)
diff --git a/map_test.go b/map_test.go
index 3a84aef..e80fbe6 100644
--- a/map_test.go
+++ b/map_test.go
@@ -21,6 +21,10 @@
"testing"
)
+import (
+ big "github.com/dubbogo/gost/math/big"
+)
+
func TestEncUntypedMap(t *testing.T) {
var (
m map[interface{}]interface{}
@@ -106,4 +110,20 @@
}
testDecodeFramework(t, "customReplyMapInMap", mapInMap)
testDecodeFramework(t, "customReplyMapInMapJsonObject", mapInMap)
+
+ b3 := &big.Decimal{}
+ _ = b3.FromString("33.33")
+ b3.Value = "33.33"
+
+ b5 := &big.Decimal{}
+ _ = b5.FromString("55.55")
+ b5.Value = "55.55"
+
+ multipleTypeMap := map[interface{}]interface{}{
+ "m1": map[interface{}]interface{}{"a": int32(1), "b": int32(2)},
+ "m2": map[interface{}]interface{}{int64(3): "c", int64(4): "d"},
+ "m3": map[interface{}]interface{}{int32(3): b3, int32(5): b5},
+ }
+
+ testDecodeFramework(t, "customReplyMultipleTypeMap", multipleTypeMap)
}
diff --git a/serialize_test.go b/serialize_test.go
index 4d602c5..4ba4148 100644
--- a/serialize_test.go
+++ b/serialize_test.go
@@ -165,6 +165,23 @@
}
}
+func TestCustomReplyObjectJsonObjectBigDecimalDecode(t *testing.T) {
+ decimal := &big.Decimal{}
+ _ = decimal.FromString("100")
+
+ out, err := decodeJavaResponse(`customReplyObjectJsonObjectBigDecimal`, ``, false)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ res := out.(map[interface{}]interface{})
+ assert.Equal(t, 1, len(res))
+
+ dec := res["test_BigDecimal"].(*big.Decimal)
+ assert.Equal(t, decimal.String(), dec.String())
+}
+
func TestObjectListGoDecode(t *testing.T) {
data := []string{
"1234",
diff --git a/test_hessian/src/main/java/test/TestCustomReply.java b/test_hessian/src/main/java/test/TestCustomReply.java
index be212ac..1f99785 100644
--- a/test_hessian/src/main/java/test/TestCustomReply.java
+++ b/test_hessian/src/main/java/test/TestCustomReply.java
@@ -419,6 +419,14 @@
output.flush();
}
+ public void customReplyObjectJsonObjectBigDecimal() throws Exception {
+ JSONObject t = new JSONObject();
+ BigDecimal decimal = new BigDecimal("100");
+ t.put("test_BigDecimal",decimal);
+ output.writeObject(t);
+ output.flush();
+ }
+
public void customReplyTypedFixedDateNull() throws Exception {
DateDemo demo = new DateDemo("zhangshan", null, null);
output.writeObject(demo);
@@ -492,6 +500,25 @@
output.flush();
}
+ public void customReplyMultipleTypeMap() throws Exception {
+ Map<String, Integer> map1 = new HashMap<String, Integer>(4);
+ map1.put("a", 1);
+ map1.put("b", 2);
+ Map<Long, String> map2 = new HashMap<Long, String>(4);
+ map2.put(3L, "c");
+ map2.put(4L, "d");
+ Map<Integer, BigDecimal> map3 = new HashMap<Integer, BigDecimal>(4);
+ map3.put(5,new BigDecimal("55.55"));
+ map3.put(3,new BigDecimal("33.33"));
+ Map<String, Object> map = new HashMap<String, Object>(4);
+ map.put("m1", map1);
+ map.put("m2", map2);
+ map.put("m3", map3);
+
+ output.writeObject(map);
+ output.flush();
+ }
+
public Map<String, Object> mapInMap() throws Exception {
Map<String, Object> map1 = new HashMap<String, Object>();
map1.put("a", 1);
@@ -567,3 +594,4 @@
public String name;
public Integer age;
}
+