Repository: apache/dubbo-go-hessian2 (go)

Issue:
两个Map结构不同但值为nil时，decode  will panic
<!-- Please use this template while reporting a bug and provide as much info as possible. Not doing so may result in your bug not being addressed in a timely manner. Thanks!

-->


**What happened**:
两个Map结构不同但值为nil时，decode  will panic
**What you expected to happen**:
返回空Map
**How to reproduce it (as minimally and precisely as possible)**:
```
type UserInfo struct {
	Name    string
	Address map[string]string
	Family  map[string]int
}

func (UserInfo) JavaClassName() string {
	return "com.test.ReqInfo"
}

func TestIssueCase(t *testing.T) {
	req := &UserInfo{
		Name:    "test",
		Address: nil,
		Family:  nil,
	}

	hessian.RegisterPOJO(req)

	encoder := hessian.NewEncoder()
	err := encoder.Encode(req)
	if err != nil {
		t.Error(err)
		return
	}

	enBuf := encoder.Buffer()

	decoder := hessian.NewDecoder(enBuf)
	deReq, err := decoder.Decode()
	assert.Nil(t, err)

	t.Log(deReq)

	assert.True(t, reflect.DeepEqual(req, deReq))
}

```
```
=== RUN   TestIssueCase
--- FAIL: TestIssueCase (0.00s)
panic: reflect.Set: value of type map[string]string is not assignable to type map[string]int [recovered]
	panic: reflect.Set: value of type map[string]string is not assignable to type map[string]int
```
**Anything else we need to know?**:


Pull request description:
fix issue 356 that ref to wrong type of map for nil value
<!--  Thanks for sending a pull request! 
-->

**What this PR does**:

fix issue #356 that ref to wrong type of map for nil value

**Which issue(s) this PR fixes**:
Fixes #356

**Special notes for your reviewer**:
None

**Does this PR introduce a user-facing change?**:
```release-note
fix issue #356 that ref to wrong type of map for nil value
```

Patch:
diff --git a/map.go b/map.go
index 1336756..f005324 100644
--- a/map.go
+++ b/map.go
@@ -117,7 +117,7 @@ func (e *Encoder) encMap(m interface{}) error {
 
 	value = UnpackPtrValue(value)
 	// check nil map
-	if value.Kind() == reflect.Ptr && !value.Elem().IsValid() {
+	if value.IsNil() || (value.Kind() == reflect.Ptr && !value.Elem().IsValid()) {
 		e.buffer = EncNull(e.buffer)
 		return nil
 	}
diff --git a/ref.go b/ref.go
index f892601..0767ca0 100644
--- a/ref.go
+++ b/ref.go
@@ -29,6 +29,9 @@ import (
 // Empty slice is not nil, but the addresses of all empty slice are the same.
 var _emptySliceAddr = unsafe.Pointer(reflect.ValueOf([]interface{}{}).Pointer())
 
+// The addresses of all nil map are the same.
+var _nilMapAddr = unsafe.Pointer(reflect.ValueOf(map[interface{}]interface{}(nil)).Pointer())
+
 // used to ref object,list,map
 type _refElem struct {
 	// record the kind of target, objects are the same only if the address and kind are the same
@@ -127,20 +130,22 @@ func (e *Encoder) checkRefMap(v reflect.Value) (int, bool) {
 		}
 	}
 
-	if addr != _emptySliceAddr {
-		if elem, ok := e.refMap[addr]; ok {
-			if elem.kind == kind {
-				// If kind is not struct, just return the index. Otherwise,
-				// check whether the types are same, because the different
-				// empty struct may share the same address and kind.
-				if elem.kind != reflect.Struct {
-					return elem.index, ok
-				} else if elem.tp == tp {
-					return elem.index, ok
-				}
+	if addr == _emptySliceAddr || addr == _nilMapAddr {
+		return 0, false
+	}
+
+	if elem, ok := e.refMap[addr]; ok {
+		if elem.kind == kind {
+			// If kind is not struct, just return the index. Otherwise,
+			// check whether the types are same, because the different
+			// empty struct may share the same address and kind.
+			if elem.kind != reflect.Struct {
+				return elem.index, ok
+			} else if elem.tp == tp {
+				return elem.index, ok
 			}
-			return 0, false
 		}
+		return 0, false
 	}
 
 	n := len(e.refMap)


Test patch:
diff --git a/testcases/issue356/issue356_test.go b/testcases/issue356/issue356_test.go
new file mode 100644
index 0000000..d6175d5
--- /dev/null
+++ b/testcases/issue356/issue356_test.go
@@ -0,0 +1,68 @@
+/*
+ * 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 issue356
+
+import (
+	"reflect"
+	"testing"
+)
+
+import (
+	hessian "github.com/apache/dubbo-go-hessian2"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+type UserInfo struct {
+	Name    string
+	Address map[string]string
+	Family  map[string]int
+}
+
+func (UserInfo) JavaClassName() string {
+	return "com.test.UserInfo"
+}
+
+func TestIssue356Case(t *testing.T) {
+	info := &UserInfo{
+		Name:    "test",
+		Address: nil,
+		Family:  nil,
+	}
+
+	hessian.RegisterPOJO(info)
+
+	encoder := hessian.NewEncoder()
+	err := encoder.Encode(info)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+
+	enBuf := encoder.Buffer()
+
+	decoder := hessian.NewDecoder(enBuf)
+	dec, err := decoder.Decode()
+	assert.Nil(t, err)
+
+	t.Log(dec)
+
+	assert.True(t, reflect.DeepEqual(info, dec))
+}