Merge pull request #229 from wongoo/fix-223

Fix decoding error for map in map
diff --git a/map.go b/map.go
index feec8fa..dc7a21b 100644
--- a/map.go
+++ b/map.go
@@ -268,9 +268,13 @@
 				if !ok {
 					return nil, perrors.Errorf("the type of map key must be string, but get %v", k)
 				}
-				fieldValue = instValue.FieldByName(fieldName)
-				if fieldValue.IsValid() {
-					fieldValue.Set(EnsureRawValue(v))
+				if instValue.Kind() == reflect.Map {
+					instValue.SetMapIndex(reflect.ValueOf(k), EnsureRawValue(v))
+				} else {
+					fieldValue = instValue.FieldByName(fieldName)
+					if fieldValue.IsValid() {
+						fieldValue.Set(EnsureRawValue(v))
+					}
 				}
 			}
 			_, err = d.readByte()
@@ -280,6 +284,9 @@
 			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()
diff --git a/map_test.go b/map_test.go
index e349f7b..b63827d 100644
--- a/map_test.go
+++ b/map_test.go
@@ -96,3 +96,14 @@
 	testJavaDecode(t, "argUntypedMap_1", map[interface{}]interface{}{"a": int32(0)})
 	testJavaDecode(t, "argUntypedMap_2", map[interface{}]interface{}{int32(0): "a", int32(1): "b"})
 }
+
+func TestCustomMap(t *testing.T) {
+	testDecodeFramework(t, "customReplyMap", map[interface{}]interface{}{"a": int32(1), "b": int32(2)})
+
+	mapInMap := map[interface{}]interface{}{
+		"obj1": map[interface{}]interface{}{"a": int32(1)},
+		"obj2": map[interface{}]interface{}{"b": int32(2)},
+	}
+	testDecodeFramework(t, "customReplyMapInMap", mapInMap)
+	testDecodeFramework(t, "customReplyMapInMapJsonObject", mapInMap)
+}
diff --git a/pojo.go b/pojo.go
index bf11633..8ed2e42 100644
--- a/pojo.go
+++ b/pojo.go
@@ -115,17 +115,22 @@
 
 // RegisterPOJO Register a POJO instance. The return value is -1 if @o has been registered.
 func RegisterPOJO(o POJO) int {
+	return RegisterPOJOMapping(o.JavaClassName(), o)
+}
+
+// RegisterPOJOMapping Register a POJO instance. The return value is -1 if @o has been registered.
+func RegisterPOJOMapping(javaClassName string, o interface{}) int {
 	// # definition for an object (compact map)
 	// class-def  ::= 'C' string int string*
 	pojoRegistry.Lock()
 	defer pojoRegistry.Unlock()
 
-	if goName, ok := pojoRegistry.j2g[o.JavaClassName()]; ok {
+	if goName, ok := pojoRegistry.j2g[javaClassName]; ok {
 		return pojoRegistry.registry[goName].index
 	}
 
 	// JavaClassName shouldn't equal to goName
-	if _, ok := pojoRegistry.registry[o.JavaClassName()]; ok {
+	if _, ok := pojoRegistry.registry[javaClassName]; ok {
 		return -1
 	}
 
@@ -140,7 +145,7 @@
 	structInfo.typ = obtainValueType(o)
 
 	structInfo.goName = structInfo.typ.String()
-	structInfo.javaName = o.JavaClassName()
+	structInfo.javaName = javaClassName
 	structInfo.inst = o
 	pojoRegistry.j2g[structInfo.javaName] = structInfo.goName
 	registerTypeName(structInfo.goName, structInfo.javaName)
@@ -149,37 +154,37 @@
 	nextStruct := []reflect.Type{structInfo.typ}
 	for len(nextStruct) > 0 {
 		current := nextStruct[0]
+		if current.Kind() == reflect.Struct {
+			for i := 0; i < current.NumField(); i++ {
+				// skip unexported anonymous filed
+				if current.Field(i).PkgPath != "" {
+					continue
+				}
 
-		for i := 0; i < current.NumField(); i++ {
+				structField := current.Field(i)
 
-			// skip unexported anonymous filed
-			if current.Field(i).PkgPath != "" {
-				continue
+				// skip ignored field
+				tagVal, hasTag := structField.Tag.Lookup(tagIdentifier)
+				if tagVal == `-` {
+					continue
+				}
+
+				// flat anonymous field
+				if structField.Anonymous && structField.Type.Kind() == reflect.Struct {
+					nextStruct = append(nextStruct, structField.Type)
+					continue
+				}
+
+				var fieldName string
+				if hasTag {
+					fieldName = tagVal
+				} else {
+					fieldName = lowerCamelCase(structField.Name)
+				}
+
+				fieldList = append(fieldList, fieldName)
+				bBody = encString(bBody, fieldName)
 			}
-
-			structField := current.Field(i)
-
-			// skip ignored field
-			tagVal, hasTag := structField.Tag.Lookup(tagIdentifier)
-			if tagVal == `-` {
-				continue
-			}
-
-			// flat anonymous field
-			if structField.Anonymous && structField.Type.Kind() == reflect.Struct {
-				nextStruct = append(nextStruct, structField.Type)
-				continue
-			}
-
-			var fieldName string
-			if hasTag {
-				fieldName = tagVal
-			} else {
-				fieldName = lowerCamelCase(structField.Name)
-			}
-
-			fieldList = append(fieldList, fieldName)
-			bBody = encString(bBody, fieldName)
 		}
 
 		nextStruct = nextStruct[1:]
@@ -235,7 +240,7 @@
 	return -1
 }
 
-func obtainValueType(o POJO) reflect.Type {
+func obtainValueType(o interface{}) reflect.Type {
 	v := reflect.ValueOf(o)
 	switch v.Kind() {
 	case reflect.Struct:
@@ -385,6 +390,10 @@
 		return nil
 	}
 
+	if s.typ.Kind() == reflect.Map {
+		return reflect.MakeMap(s.typ).Interface()
+	}
+
 	return reflect.New(s.typ).Interface()
 }
 
diff --git a/test_hessian/pom.xml b/test_hessian/pom.xml
index acd9188..a4db3f1 100644
--- a/test_hessian/pom.xml
+++ b/test_hessian/pom.xml
@@ -48,6 +48,11 @@
             <version>2.6.5</version>
         </dependency>
         <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.70</version>
+        </dependency>
+        <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <version>4.13</version>
diff --git a/test_hessian/src/main/java/test/TestCustomReply.java b/test_hessian/src/main/java/test/TestCustomReply.java
index 12fc411..62e3ea6 100644
--- a/test_hessian/src/main/java/test/TestCustomReply.java
+++ b/test_hessian/src/main/java/test/TestCustomReply.java
@@ -18,8 +18,12 @@
 package test;
 
 import com.alibaba.com.caucho.hessian.io.Hessian2Output;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.caucho.hessian.test.A0;
 import com.caucho.hessian.test.A1;
+import test.model.DateDemo;
+
 import java.io.OutputStream;
 import java.io.Serializable;
 import java.math.BigDecimal;
@@ -27,17 +31,16 @@
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 
-import test.model.DateDemo;
-
 
 public class TestCustomReply {
 
     private Hessian2Output output;
     private HashMap<Class<?>, String> typeMap;
 
-    TestCustomReply(OutputStream os) {
+    public TestCustomReply(OutputStream os) {
         output = new Hessian2Output(os);
 
         typeMap = new HashMap<>();
@@ -355,32 +358,32 @@
     }
 
     public void customReplyTypedFixedList_BigInteger() throws Exception {
-        BigInteger[] integers = new BigInteger[] { 
-            new BigInteger("1234"), 
-            new BigInteger("12347890"), 
-            new BigInteger("123478901234"), 
-            new BigInteger("1234789012345678"), 
-            new BigInteger("123478901234567890"), 
-            new BigInteger("1234789012345678901234"), 
-            new BigInteger("12347890123456789012345678"), 
-            new BigInteger("123478901234567890123456781234"), 
-            new BigInteger("1234789012345678901234567812345678"), 
-            new BigInteger("12347890123456789012345678123456781234"), 
-            new BigInteger("-12347890123456789012345678123456781234"), 
-            new BigInteger("0"), 
+        BigInteger[] integers = new BigInteger[]{
+                new BigInteger("1234"),
+                new BigInteger("12347890"),
+                new BigInteger("123478901234"),
+                new BigInteger("1234789012345678"),
+                new BigInteger("123478901234567890"),
+                new BigInteger("1234789012345678901234"),
+                new BigInteger("12347890123456789012345678"),
+                new BigInteger("123478901234567890123456781234"),
+                new BigInteger("1234789012345678901234567812345678"),
+                new BigInteger("12347890123456789012345678123456781234"),
+                new BigInteger("-12347890123456789012345678123456781234"),
+                new BigInteger("0"),
         };
         output.writeObject(integers);
         output.flush();
     }
 
     public void customReplyTypedFixedList_CustomObject() throws Exception {
-        Object[] objects = new Object[] {
-            new BigInteger("1234"),
-            new BigInteger("-12347890"),
-            new BigInteger("0"),
-            new BigDecimal("123.4"),
-            new BigDecimal("-123.45"),
-            new BigDecimal("0"),
+        Object[] objects = new Object[]{
+                new BigInteger("1234"),
+                new BigInteger("-12347890"),
+                new BigInteger("0"),
+                new BigDecimal("123.4"),
+                new BigDecimal("-123.45"),
+                new BigDecimal("0"),
         };
         output.writeObject(objects);
         output.flush();
@@ -473,6 +476,37 @@
         output.writeObject(set);
         output.flush();
     }
+
+    public void customReplyMap() throws Exception {
+        Map<String, Object> map = new HashMap<String, Object>(4);
+        map.put("a", 1);
+        map.put("b", 2);
+        output.writeObject(map);
+        output.flush();
+    }
+
+    public Map<String, Object> mapInMap() throws Exception {
+        Map<String, Object> map1 = new HashMap<String, Object>();
+        map1.put("a", 1);
+        Map<String, Object> map2 = new HashMap<String, Object>();
+        map2.put("b", 2);
+
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("obj1", map1);
+        map.put("obj2", map2);
+        return map;
+    }
+
+    public void customReplyMapInMap() throws Exception {
+        output.writeObject(mapInMap());
+        output.flush();
+    }
+
+    public void customReplyMapInMapJsonObject() throws Exception {
+        JSONObject json = JSON.parseObject(JSON.toJSONString(mapInMap()));
+        output.writeObject(json);
+        output.flush();
+    }
 }
 
 interface Leg {