Merge pull request #97 from aliiohs/feature/AddDecimalSupport

Feature/add decimal support
diff --git a/encode.go b/encode.go
index 599830d..f5f333b 100644
--- a/encode.go
+++ b/encode.go
@@ -124,6 +124,15 @@
 		switch t.Kind() {
 		case reflect.Struct:
 			if p, ok := v.(POJO); ok {
+				var clazz string
+				vv := reflect.ValueOf(v)
+				vv = UnpackPtr(vv)
+				if vv.IsValid() {
+					clazz = p.JavaClassName()
+					if c, ok := GetSerializer(clazz); ok {
+						return c.EncObject(e, p)
+					}
+				}
 				return e.encObject(p)
 			}
 
diff --git a/go.mod b/go.mod
index 971dd66..24e71dd 100644
--- a/go.mod
+++ b/go.mod
@@ -2,6 +2,7 @@
 
 require (
 	github.com/davecgh/go-spew v1.1.1 // indirect
+	github.com/dubbogo/gost v1.1.1
 	github.com/pkg/errors v0.8.1
 	github.com/stretchr/testify v1.3.0
 )
diff --git a/go.sum b/go.sum
index b0ebc7a..dd2e8c8 100644
--- a/go.sum
+++ b/go.sum
@@ -2,6 +2,10 @@
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dubbogo/gost v1.0.1-0.20190709080436-ae4ac3e96ad1 h1:RrdI0SvwHR2DKNLJj+heaIbeb9qYig9QlniddKB6ViU=
+github.com/dubbogo/gost v1.0.1-0.20190709080436-ae4ac3e96ad1/go.mod h1:R7wZm1DrmrKGr50mBZVcg6C9ekG8aL5hP+sgWcIDwQg=
+github.com/dubbogo/gost v1.1.1 h1:JCM7vx5edPIjDA5ovJTuzEEXuw2t7xLyrlgi2mi5jHI=
+github.com/dubbogo/gost v1.1.1/go.mod h1:R7wZm1DrmrKGr50mBZVcg6C9ekG8aL5hP+sgWcIDwQg=
 github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
diff --git a/object.go b/object.go
index 5757e56..d9f3cc0 100644
--- a/object.go
+++ b/object.go
@@ -522,7 +522,9 @@
 		cls, _ = clsDef.(classInfo)
 		//add to slice
 		d.appendClsDef(cls)
-
+		if c, ok := GetSerializer(cls.javaName); ok {
+			return c.DecObject(d)
+		}
 		return d.DecodeValue()
 
 	case tag == BC_OBJECT:
diff --git a/serialize.go b/serialize.go
new file mode 100644
index 0000000..510f967
--- /dev/null
+++ b/serialize.go
@@ -0,0 +1,67 @@
+// Copyright 2016-2019 aliiohs
+//
+// Licensed 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 hessian
+
+import (
+	big "github.com/dubbogo/gost/math/big"
+)
+
+func init() {
+	RegisterPOJO(&big.Decimal{})
+	SetSerializer("java.math.BigDecimal", DecimalSerializer{})
+}
+
+type Serializer interface {
+	EncObject(*Encoder, POJO) error
+	DecObject(*Decoder) (interface{}, error)
+}
+
+var serializerMap = make(map[string]Serializer, 16)
+
+func SetSerializer(key string, codec Serializer) {
+	serializerMap[key] = codec
+}
+
+func GetSerializer(key string) (Serializer, bool) {
+	codec, ok := serializerMap[key]
+	return codec, ok
+}
+
+type DecimalSerializer struct{}
+
+func (DecimalSerializer) EncObject(e *Encoder, v POJO) error {
+	decimal, ok := v.(big.Decimal)
+	if !ok {
+		return e.encObject(v)
+	}
+	decimal.Value = decimal.String()
+	return e.encObject(decimal)
+}
+
+func (DecimalSerializer) DecObject(d *Decoder) (interface{}, error) {
+	dec, err := d.DecodeValue()
+	if err != nil {
+		return nil, err
+	}
+	result, ok := dec.(*big.Decimal)
+	if !ok {
+		panic("result type is not decimal,please check the whether the conversion is ok")
+	}
+	err = result.FromString(result.Value)
+	if err != nil {
+		return nil, err
+	}
+	return result, nil
+}
diff --git a/serialize_test.go b/serialize_test.go
new file mode 100644
index 0000000..195a758
--- /dev/null
+++ b/serialize_test.go
@@ -0,0 +1,68 @@
+// Copyright 2016-2019 aliiohs
+//
+// Licensed 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 hessian
+
+import (
+	"reflect"
+	"testing"
+)
+
+import (
+	big "github.com/dubbogo/gost/math/big"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestEncodeDecodeDecimal(t *testing.T) {
+	var dec big.Decimal
+	_ = dec.FromString("100.256")
+	e := NewEncoder()
+	err := e.Encode(dec)
+	if err != nil {
+		t.Error(err)
+		t.FailNow()
+	}
+
+	d := NewDecoder(e.buffer)
+	decObj, err := d.Decode()
+	if err != nil {
+		t.Error(err)
+		t.FailNow()
+	}
+
+	if !reflect.DeepEqual(dec.String(), decObj.(*big.Decimal).String()) {
+		t.Errorf("expect: %v, but get: %v", dec, decObj)
+	}
+}
+
+func TestDecimalGoDecode(t *testing.T) {
+	var d big.Decimal
+	_ = d.FromString("100.256")
+	d.Value = d.String()
+	doTestDecimal(t, "customReplyTypedFixedDecimal", "100.256")
+}
+
+func TestDecimalJavaDecode(t *testing.T) {
+	var d big.Decimal
+	_ = d.FromString("100.256")
+	d.Value = d.String()
+	testJavaDecode(t, "customArgTypedFixedList_Decimal", d)
+}
+
+func doTestDecimal(t *testing.T, method, content string) {
+	testDecodeFrameworkFunc(t, method, func(r interface{}) {
+		t.Logf("%#v", r)
+		assert.Equal(t, content, r.(*big.Decimal).String())
+	})
+}
diff --git a/test_hessian/src/main/java/test/TestCustomDecode.java b/test_hessian/src/main/java/test/TestCustomDecode.java
index cb38a4e..27ac4ce 100644
--- a/test_hessian/src/main/java/test/TestCustomDecode.java
+++ b/test_hessian/src/main/java/test/TestCustomDecode.java
@@ -1,166 +1,171 @@
-// Copyright 2019 Xinge Gao

-//

-// Licensed 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;

-

-import com.caucho.hessian.io.Hessian2Input;

-import com.caucho.hessian.test.A0;

-import com.caucho.hessian.test.A1;

-

-import javax.xml.crypto.Data;

-import java.io.InputStream;

-import java.lang.reflect.Array;

-import java.util.ArrayList;

-import java.util.Arrays;

-import java.util.Date;

-import java.util.List;

-

-

-public class TestCustomDecode {

-

-    private Hessian2Input input;

-

-    TestCustomDecode(InputStream is) {

-        input = new Hessian2Input(is);

-    }

-

-    public Object customArgUntypedFixedListHasNull() throws Exception {

-        List list = new ArrayList();

-        list.add(new A0());

-        list.add(new A1());

-        list.add(null);

-

-        Object o = input.readObject();

-        return list.equals(o);

-    }

-

-    public Object customArgTypedFixedList() throws Exception {

-        A0[] list = new A0[]{new A0()};

-        Object o = input.readObject();

-        return Arrays.equals(list,(A0[])o);

-    }

-

-    public Object customArgTypedFixedList_short_0() throws Exception {

-        short[] list = new short[]{};

-        Object o = input.readObject();

-        return Arrays.equals(list,(short[])o);

-    }

-

-    public Object customArgTypedFixedList_short_7() throws Exception {

-        short[] list = new short[]{1,2,3,4,5,6,7};

-        Object o = input.readObject();

-        return Arrays.equals(list,(short[])o);

-    }

-

-    public Object customArgTypedFixedList_int_0() throws Exception {

-        int[] list = new int[]{};

-        Object o = input.readObject();

-        return Arrays.equals(list,(int[])o);

-    }

-

-    public Object customArgTypedFixedList_int_7() throws Exception {

-        int[] list = new int[]{1,2,3,4,5,6,7};

-        Object o = input.readObject();

-        return Arrays.equals(list,(int[])o);

-    }

-

-    public Object customArgTypedFixedList_long_0() throws Exception {

-        long[] list = new long[]{};

-        Object o = input.readObject();

-        return Arrays.equals(list,(long[])o);

-    }

-

-    public Object customArgTypedFixedList_long_7() throws Exception {

-        long[] list = new long[]{1,2,3,4,5,6,7};

-        Object o = input.readObject();

-        return Arrays.equals(list,(long[])o);

-    }

-

-    public Object customArgTypedFixedList_float_0() throws Exception {

-        float[] list = new float[]{};

-        Object o = input.readObject();

-        return Arrays.equals(list,(float[])o);

-    }

-

-    public Object customArgTypedFixedList_float_7() throws Exception {

-        float[] list = new float[]{1,2,3,4,5,6,7};

-        Object o = input.readObject();

-        return Arrays.equals(list,(float[])o);

-    }

-

-    public Object customArgTypedFixedList_double_0() throws Exception {

-        double[] list = new double[]{};

-        Object o = input.readObject();

-        return Arrays.equals(list,(double[])o);

-    }

-

-    public Object customArgTypedFixedList_double_7() throws Exception {

-        double[] list = new double[]{1,2,3,4,5,6,7};

-        Object o = input.readObject();

-        return Arrays.equals(list,(double[])o);

-    }

-

-    public Object customArgTypedFixedList_boolean_0() throws Exception {

-        boolean[] list = new boolean[]{};

-        Object o = input.readObject();

-        return Arrays.equals(list,(boolean[])o);

-    }

-

-    public Object customArgTypedFixedList_boolean_7() throws Exception {

-        boolean[] list = new boolean[]{true,false,true,false,true,false,true};

-        Object o = input.readObject();

-        return Arrays.equals(list,(boolean[])o);

-    }

-

-    public Object customArgTypedFixedList_date_0() throws Exception {

-        Date[] list = new Date[]{};

-        Object o = input.readObject();

-        return Arrays.equals(list,(Date[])o);

-    }

-

-    public Object customArgTypedFixedList_date_3() throws Exception {

-        Date[] list = new Date[]{new Date(1560864000), new Date(1560864000), new Date(1560864000)};

-        Object o = input.readObject();

-        return Arrays.equals(list,(Date[])o);

-    }

-

-    public Object customArgTypedFixedList_arrays() throws Exception {

-        int[][][] list = new int[][][]{{{1, 2, 3}, {4, 5, 6, 7}}, {{8, 9, 10}, {11, 12, 13, 14}}};

-        try {

-            Object o = input.readObject();

-            return Arrays.deepEquals(list, (int[][][])o);

-        } catch (Exception e){

-            return e.toString();

-        }

-    }

-

-    public Object customArgTypedFixedList_A0arrays() throws Exception {

-        A0[][][] list = new A0[][][]{{{new A0(), new A0(), new A0()}, {new A0(), new A0(), new A0(), null}}, {{new A0()}, {new A0()}}};

-        Object o = input.readObject();

-        return Arrays.deepEquals(list, (A0[][][])o);

-    }

-

-    public Object customArgTypedFixedList_Test() throws Exception {

-        TypedListTest t = new TypedListTest();

-        Object o = input.readObject();

-        TypedListTest t2 = (TypedListTest)o;

-        return t.a.equals(t.a) && Arrays.deepEquals(t.list, t2.list) && Arrays.deepEquals(t.list1, t2.list1);

-    }

-

-    public Object customArgTypedFixedList_Object() throws Exception {

-        Object[] list = new Object[]{new A0()};

-        Object o = input.readObject();

-        return Arrays.deepEquals(list, (Object[])o);

-    }

+// Copyright 2019 Xinge Gao
+//
+// Licensed 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;
+
+import com.caucho.hessian.io.Hessian2Input;
+import com.caucho.hessian.test.A0;
+import com.caucho.hessian.test.A1;
+
+import javax.xml.crypto.Data;
+import java.io.InputStream;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.math.BigDecimal;
+
+public class TestCustomDecode {
+
+    private Hessian2Input input;
+
+    TestCustomDecode(InputStream is) {
+        input = new Hessian2Input(is);
+    }
+
+    public Object customArgUntypedFixedListHasNull() throws Exception {
+        List list = new ArrayList();
+        list.add(new A0());
+        list.add(new A1());
+        list.add(null);
+
+        Object o = input.readObject();
+        return list.equals(o);
+    }
+
+    public Object customArgTypedFixedList() throws Exception {
+        A0[] list = new A0[]{new A0()};
+        Object o = input.readObject();
+        return Arrays.equals(list,(A0[])o);
+    }
+
+    public Object customArgTypedFixedList_short_0() throws Exception {
+        short[] list = new short[]{};
+        Object o = input.readObject();
+        return Arrays.equals(list,(short[])o);
+    }
+
+    public Object customArgTypedFixedList_short_7() throws Exception {
+        short[] list = new short[]{1,2,3,4,5,6,7};
+        Object o = input.readObject();
+        return Arrays.equals(list,(short[])o);
+    }
+
+    public Object customArgTypedFixedList_int_0() throws Exception {
+        int[] list = new int[]{};
+        Object o = input.readObject();
+        return Arrays.equals(list,(int[])o);
+    }
+
+    public Object customArgTypedFixedList_int_7() throws Exception {
+        int[] list = new int[]{1,2,3,4,5,6,7};
+        Object o = input.readObject();
+        return Arrays.equals(list,(int[])o);
+    }
+
+    public Object customArgTypedFixedList_long_0() throws Exception {
+        long[] list = new long[]{};
+        Object o = input.readObject();
+        return Arrays.equals(list,(long[])o);
+    }
+
+    public Object customArgTypedFixedList_long_7() throws Exception {
+        long[] list = new long[]{1,2,3,4,5,6,7};
+        Object o = input.readObject();
+        return Arrays.equals(list,(long[])o);
+    }
+
+    public Object customArgTypedFixedList_float_0() throws Exception {
+        float[] list = new float[]{};
+        Object o = input.readObject();
+        return Arrays.equals(list,(float[])o);
+    }
+
+    public Object customArgTypedFixedList_float_7() throws Exception {
+        float[] list = new float[]{1,2,3,4,5,6,7};
+        Object o = input.readObject();
+        return Arrays.equals(list,(float[])o);
+    }
+
+    public Object customArgTypedFixedList_double_0() throws Exception {
+        double[] list = new double[]{};
+        Object o = input.readObject();
+        return Arrays.equals(list,(double[])o);
+    }
+
+    public Object customArgTypedFixedList_double_7() throws Exception {
+        double[] list = new double[]{1,2,3,4,5,6,7};
+        Object o = input.readObject();
+        return Arrays.equals(list,(double[])o);
+    }
+
+    public Object customArgTypedFixedList_boolean_0() throws Exception {
+        boolean[] list = new boolean[]{};
+        Object o = input.readObject();
+        return Arrays.equals(list,(boolean[])o);
+    }
+
+    public Object customArgTypedFixedList_boolean_7() throws Exception {
+        boolean[] list = new boolean[]{true,false,true,false,true,false,true};
+        Object o = input.readObject();
+        return Arrays.equals(list,(boolean[])o);
+    }
+
+    public Object customArgTypedFixedList_date_0() throws Exception {
+        Date[] list = new Date[]{};
+        Object o = input.readObject();
+        return Arrays.equals(list,(Date[])o);
+    }
+
+    public Object customArgTypedFixedList_date_3() throws Exception {
+        Date[] list = new Date[]{new Date(1560864000), new Date(1560864000), new Date(1560864000)};
+        Object o = input.readObject();
+        return Arrays.equals(list,(Date[])o);
+    }
+
+    public Object customArgTypedFixedList_arrays() throws Exception {
+        int[][][] list = new int[][][]{{{1, 2, 3}, {4, 5, 6, 7}}, {{8, 9, 10}, {11, 12, 13, 14}}};
+        try {
+            Object o = input.readObject();
+            return Arrays.deepEquals(list, (int[][][])o);
+        } catch (Exception e){
+            return e.toString();
+        }
+    }
+
+    public Object customArgTypedFixedList_A0arrays() throws Exception {
+        A0[][][] list = new A0[][][]{{{new A0(), new A0(), new A0()}, {new A0(), new A0(), new A0(), null}}, {{new A0()}, {new A0()}}};
+        Object o = input.readObject();
+        return Arrays.deepEquals(list, (A0[][][])o);
+    }
+
+    public Object customArgTypedFixedList_Test() throws Exception {
+        TypedListTest t = new TypedListTest();
+        Object o = input.readObject();
+        TypedListTest t2 = (TypedListTest)o;
+        return t.a.equals(t.a) && Arrays.deepEquals(t.list, t2.list) && Arrays.deepEquals(t.list1, t2.list1);
+    }
+
+    public Object customArgTypedFixedList_Object() throws Exception {
+        Object[] list = new Object[]{new A0()};
+        Object o = input.readObject();
+        return Arrays.deepEquals(list, (Object[])o);
+    }
+
+    public Object customArgTypedFixedList_Decimal() throws Exception {
+        BigDecimal o = (BigDecimal) input.readObject();
+        return o.toString().equals( "100.256");
+    }
 }
\ No newline at end of file
diff --git a/test_hessian/src/main/java/test/TestCustomReply.java b/test_hessian/src/main/java/test/TestCustomReply.java
index e2d17b7..21ada2a 100644
--- a/test_hessian/src/main/java/test/TestCustomReply.java
+++ b/test_hessian/src/main/java/test/TestCustomReply.java
@@ -22,7 +22,7 @@
 import java.io.Serializable;
 import java.util.Date;
 import java.util.HashMap;
-
+import java.math.BigDecimal;
 
 public class TestCustomReply {
 
@@ -340,6 +340,12 @@
         output.flush();
     }
 
+    public void customReplyTypedFixedDecimal() throws Exception {
+        BigDecimal decimal = new BigDecimal("100.256");
+        output.writeObject(decimal);
+        output.flush();
+    }
+
 }
 
 class TypedListTest implements Serializable {