diff --git a/list.go b/list.go index c3c761ce..da0ca392 100644 --- a/list.go +++ b/list.go @@ -332,20 +332,28 @@ func (d *Decoder) readTypedListValue(length int, listTyp string, isVariableArr b aryValue reflect.Value arrType reflect.Type ) + t, err := strconv.Atoi(listTyp) if err == nil { + // find the ref list type arrType = d.typeRefs.Get(t) + if arrType == nil { + return nil, perrors.Errorf("can't find ref list type at index %d", t) + } + aryValue = reflect.MakeSlice(arrType, length, length) } else { + // try to find the registered list type arrType = getListType(listTyp) + if arrType != nil { + aryValue = reflect.MakeSlice(arrType, length, length) + d.typeRefs.appendTypeRefs(listTyp, arrType) + } else { + // using default generic list type if not found registered + aryValue = reflect.ValueOf(make([]interface{}, length, length)) + d.typeRefs.appendTypeRefs(listTyp, aryValue.Type()) + } } - if arrType != nil { - aryValue = reflect.MakeSlice(arrType, length, length) - d.typeRefs.appendTypeRefs(arrType.String(), arrType) - } else { - aryValue = reflect.ValueOf(make([]interface{}, length, length)) - d.typeRefs.appendTypeRefs(strings.Replace(listTyp, "[", "", -1), aryValue.Type()) - } holder := d.appendRefs(aryValue) for j := 0; j < length || isVariableArr; j++ { it, err := d.DecodeValue() diff --git a/list_test.go b/list_test.go index 0e96ae69..65783669 100644 --- a/list_test.go +++ b/list_test.go @@ -70,6 +70,22 @@ func TestEncList(t *testing.T) { assert.True(t, reflect.DeepEqual(res, list_2)) } +func TestListRefSelf(t *testing.T) { + RegisterPOJOs(new(A0), new(A1)) + + r, e := decodeJavaResponse("customReplyTypedFixedListRefSelf", "", true) + if e != nil { + t.Errorf("%s: decode fail with error: %v", "customReplyTypedFixedListRefSelf", e) + return + } + + res := r.([]Object) + assert.Equal(t, 3, len(res)) + assert.Equal(t, new(A0), res[0]) + assert.Equal(t, new(A1), res[1]) + assert.Equal(t, res, res[2]) +} + func TestList(t *testing.T) { RegisterPOJOs(new(A0), new(A1), new(TypedListTest)) diff --git a/map.go b/map.go index d43b915a..64227bf3 100644 --- a/map.go +++ b/map.go @@ -226,7 +226,6 @@ func (d *Decoder) decMap(flag int32) (interface{}, error) { m map[interface{}]interface{} k interface{} v interface{} - inst interface{} instValue reflect.Value fieldName string fieldValue reflect.Value @@ -255,9 +254,7 @@ func (d *Decoder) decMap(flag int32) (interface{}, error) { instValue = reflect.New(typ).Elem() } - inst = instValue.Interface() - - d.appendRefs(inst) + d.appendRefs(instValue) for d.peekByte() != BC_END { k, err = d.Decode() @@ -286,7 +283,7 @@ func (d *Decoder) decMap(flag int32) (interface{}, error) { if err != nil { return nil, perrors.WithStack(err) } - return inst, nil + return instValue.Interface(), 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 e80fbe6b..5fc08552 100644 --- a/map_test.go +++ b/map_test.go @@ -23,6 +23,7 @@ import ( import ( big "github.com/dubbogo/gost/math/big" + "github.com/stretchr/testify/assert" ) func TestEncUntypedMap(t *testing.T) { @@ -101,6 +102,23 @@ func TestMapEncode(t *testing.T) { testJavaDecode(t, "argUntypedMap_2", map[interface{}]interface{}{int32(0): "a", int32(1): "b"}) } +func TestCustomMapRefMap(t *testing.T) { + r, e := decodeJavaResponse("customReplyMapRefMap", "", true) + if e != nil { + t.Errorf("%s: decode fail with error: %v", "customReplyMapRefMap", e) + return + } + res := r.(map[interface{}]interface{}) + assert.Equal(t, int32(1), res["a"]) + assert.Equal(t, int32(2), res["b"]) + assert.Equal(t, res, res["self"]) +} + +type customMapObject struct { + Int int32 + S string +} + func TestCustomMap(t *testing.T) { testDecodeFramework(t, "customReplyMap", map[interface{}]interface{}{"a": int32(1), "b": int32(2)}) @@ -126,4 +144,29 @@ func TestCustomMap(t *testing.T) { } testDecodeFramework(t, "customReplyMultipleTypeMap", multipleTypeMap) + + RegisterPOJOMapping("test.model.CustomMap", &customMapObject{}) + + listMapListMap := []interface{}{ + + map[interface{}]interface{}{ + "a": int32(1), + "b": int32(2), + "items": []interface{}{ + b5, + "hello", + int32(123), + customMapObject{ + Int: 456, + S: "string", + }, + }, + }, + customMapObject{ + Int: 789, + S: "string2", + }, + } + + testDecodeFramework(t, "customReplyListMapListMap", listMapListMap) } diff --git a/test_hessian/src/main/java/test/TestCustomReply.java b/test_hessian/src/main/java/test/TestCustomReply.java index d4c6d134..a3fa27cd 100644 --- a/test_hessian/src/main/java/test/TestCustomReply.java +++ b/test_hessian/src/main/java/test/TestCustomReply.java @@ -24,15 +24,18 @@ import com.caucho.hessian.test.A1; import test.generic.BusinessData; import test.generic.Response; +import test.model.CustomMap; import test.model.DateDemo; import java.io.OutputStream; import java.io.Serializable; import java.math.BigDecimal; import java.math.BigInteger; +import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -87,6 +90,13 @@ public void customReplyTypedFixedListHasNull() throws Exception { output.flush(); } + public void customReplyTypedFixedListRefSelf() throws Exception { + Object[] o = new Object[]{new A0(), new A1(), null}; + o[2] = o; + output.writeObject(o); + output.flush(); + } + public void customReplyTypedVariableListHasNull() throws Exception { Object[] o = new Object[]{new A0(), new A1(), null}; if (output.addRef(o)) { @@ -501,6 +511,16 @@ public void customReplyMap() throws Exception { output.flush(); } + public void customReplyMapRefMap() throws Exception { + Map map = new HashMap(4); + map.put("a", 1); + map.put("b", 2); + map.put("self", map); + + output.writeObject(map); + output.flush(); + } + public void customReplyMultipleTypeMap() throws Exception { Map map1 = new HashMap(4); map1.put("a", 1); @@ -520,6 +540,37 @@ public void customReplyMultipleTypeMap() throws Exception { output.flush(); } + public void customReplyListMapListMap() throws Exception { + List list = new ArrayList<>(); + + Map listMap1 = new HashMap(4); + listMap1.put("a", 1); + listMap1.put("b", 2); + + List items = new ArrayList<>(); + items.add(new BigDecimal("55.55")); + items.add("hello"); + items.add(123); + + CustomMap innerMap = new CustomMap(); + innerMap.put("Int", 456); + innerMap.put("S", "string"); + items.add(innerMap); + + listMap1.put("items",items); + + list.add(listMap1); + + CustomMap listMap2 = new CustomMap(); + listMap2.put("Int", 789); + listMap2.put("S", "string2"); + + list.add(listMap2); + + output.writeObject(list); + output.flush(); + } + public Map mapInMap() throws Exception { Map map1 = new HashMap(); map1.put("a", 1); diff --git a/test_hessian/src/main/java/test/model/CustomMap.java b/test_hessian/src/main/java/test/model/CustomMap.java new file mode 100644 index 00000000..7887d980 --- /dev/null +++ b/test_hessian/src/main/java/test/model/CustomMap.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package test.model; + +import java.util.HashMap; + +public class CustomMap extends HashMap { +}