fix emoji encode error
diff --git a/binary.go b/binary.go
index 3352129..6ebc764 100644
--- a/binary.go
+++ b/binary.go
@@ -16,9 +16,7 @@
 
 import (
 	"io"
-)
 
-import (
 	gxbytes "github.com/dubbogo/gost/bytes"
 	perrors "github.com/pkg/errors"
 )
diff --git a/codec.go b/codec.go
index 184938c..c34dbea 100644
--- a/codec.go
+++ b/codec.go
@@ -21,9 +21,7 @@
 	"math"
 	"reflect"
 	"strings"
-)
 
-import (
 	perrors "github.com/pkg/errors"
 )
 
diff --git a/const.go b/const.go
index 6d51f67..ed3a0c8 100644
--- a/const.go
+++ b/const.go
@@ -16,11 +16,10 @@
 
 import (
 	"regexp"
-)
 
-import (
-	perrors "github.com/pkg/errors"
 	"reflect"
+
+	perrors "github.com/pkg/errors"
 )
 
 const (
diff --git a/date.go b/date.go
index 50723e0..9aada5e 100644
--- a/date.go
+++ b/date.go
@@ -17,9 +17,7 @@
 import (
 	"reflect"
 	"time"
-)
 
-import (
 	perrors "github.com/pkg/errors"
 )
 
diff --git a/date_test.go b/date_test.go
index 64e0822..c4fbe53 100644
--- a/date_test.go
+++ b/date_test.go
@@ -17,8 +17,7 @@
 import (
 	"testing"
 	"time"
-)
-import (
+
 	"github.com/stretchr/testify/assert"
 )
 
diff --git a/decode.go b/decode.go
index 4bb782d..4bdccb1 100644
--- a/decode.go
+++ b/decode.go
@@ -19,9 +19,7 @@
 	"bytes"
 	"io"
 	"reflect"
-)
 
-import (
 	perrors "github.com/pkg/errors"
 )
 
diff --git a/double.go b/double.go
index 050ee25..96074f1 100644
--- a/double.go
+++ b/double.go
@@ -17,9 +17,7 @@
 import (
 	"encoding/binary"
 	"math"
-)
 
-import (
 	perrors "github.com/pkg/errors"
 )
 
diff --git a/encode.go b/encode.go
index 59ce555..b9289b2 100644
--- a/encode.go
+++ b/encode.go
@@ -18,9 +18,7 @@
 	"reflect"
 	"time"
 	"unsafe"
-)
 
-import (
 	perrors "github.com/pkg/errors"
 )
 
diff --git a/encode_test.go b/encode_test.go
index 53e6a9f..b77c78a 100644
--- a/encode_test.go
+++ b/encode_test.go
@@ -16,6 +16,7 @@
 
 import (
 	"bytes"
+	"fmt"
 	"os/exec"
 	"testing"
 )
@@ -36,34 +37,40 @@
 }
 
 func javaDecodeValidate(method string, target interface{}) (string, error) {
-	b, e := encodeTarget(target)
-	if e != nil {
-		return "", e
+	b, err := encodeTarget(target)
+	if err != nil {
+		return "", err
 	}
 
 	genHessianJar()
 	cmd := exec.Command("java", "-jar", hessianJar, method)
 
-	stdin, _ := cmd.StdinPipe()
+	stdin, err := cmd.StdinPipe()
+	if err != nil {
+		fmt.Printf("call java error: %v", err)
+		return "", err
+	}
+
 	go func() {
-		stdin.Write(b)
-		stdin.Close()
+		_, _ = stdin.Write(b)
+		_ = stdin.Close()
 	}()
 
-	out, e := cmd.Output()
-	if e != nil {
-		return "", e
+	out, err := cmd.Output()
+	if err != nil {
+		return "", err
 	}
 	return string(out), nil
 }
 
 func testJavaDecode(t *testing.T, method string, target interface{}) {
-	r, e := javaDecodeValidate(method, target)
-	if e != nil {
-		t.Errorf("%s: encode fail with error %v", method, e)
+	result, err := javaDecodeValidate(method, target)
+	if err != nil {
+		t.Errorf("%s: encode fail with error: %v", method, err)
+		return
 	}
 
-	if r != "true" {
-		t.Errorf("%s: encode %v to bytes wrongly", method, target)
+	if result != "true" {
+		t.Errorf("%s: encode %v to bytes wrongly, result: %s", method, target, result)
 	}
 }
diff --git a/go.mod b/go.mod
index 5a38e9e..324100f 100644
--- a/go.mod
+++ b/go.mod
@@ -5,3 +5,5 @@
 	github.com/pkg/errors v0.8.1
 	github.com/stretchr/testify v1.3.0
 )
+
+go 1.13
diff --git a/hessian.go b/hessian.go
index 759293b..28008cf 100644
--- a/hessian.go
+++ b/hessian.go
@@ -18,9 +18,7 @@
 	"bufio"
 	"encoding/binary"
 	"time"
-)
 
-import (
 	perrors "github.com/pkg/errors"
 )
 
diff --git a/hessian_test.go b/hessian_test.go
index a372a77..f48b7b5 100644
--- a/hessian_test.go
+++ b/hessian_test.go
@@ -20,9 +20,7 @@
 	"reflect"
 	"testing"
 	"time"
-)
 
-import (
 	"github.com/stretchr/testify/assert"
 )
 
diff --git a/int.go b/int.go
index efee5ca..61f6652 100644
--- a/int.go
+++ b/int.go
@@ -17,9 +17,7 @@
 import (
 	"encoding/binary"
 	"io"
-)
 
-import (
 	perrors "github.com/pkg/errors"
 )
 
diff --git a/list.go b/list.go
index 4a1093f..44a3ad6 100644
--- a/list.go
+++ b/list.go
@@ -21,9 +21,7 @@
 	"strings"
 	"sync"
 	"time"
-)
 
-import (
 	perrors "github.com/pkg/errors"
 )
 
diff --git a/list_test.go b/list_test.go
index d28fc76..a835ee6 100644
--- a/list_test.go
+++ b/list_test.go
@@ -19,9 +19,7 @@
 	"reflect"
 	"testing"
 	"time"
-)
 
-import (
 	"github.com/stretchr/testify/assert"
 )
 
diff --git a/long.go b/long.go
index 6fec2fb..0509824 100644
--- a/long.go
+++ b/long.go
@@ -17,9 +17,7 @@
 import (
 	"encoding/binary"
 	"io"
-)
 
-import (
 	perrors "github.com/pkg/errors"
 )
 
diff --git a/map.go b/map.go
index 8c94112..08d176c 100644
--- a/map.go
+++ b/map.go
@@ -17,9 +17,7 @@
 import (
 	"io"
 	"reflect"
-)
 
-import (
 	perrors "github.com/pkg/errors"
 )
 
diff --git a/object.go b/object.go
index 58fe5d8..0b4e9a5 100644
--- a/object.go
+++ b/object.go
@@ -18,9 +18,7 @@
 	"io"
 	"reflect"
 	"strings"
-)
 
-import (
 	perrors "github.com/pkg/errors"
 )
 
diff --git a/pojo.go b/pojo.go
index de9dc16..0d0c4dd 100644
--- a/pojo.go
+++ b/pojo.go
@@ -20,9 +20,7 @@
 	"strings"
 	"sync"
 	"unicode"
-)
 
-import (
 	perrors "github.com/pkg/errors"
 )
 
diff --git a/ref.go b/ref.go
index a63689c..44b2b18 100644
--- a/ref.go
+++ b/ref.go
@@ -17,9 +17,7 @@
 import (
 	"reflect"
 	"unsafe"
-)
 
-import (
 	perrors "github.com/pkg/errors"
 )
 
diff --git a/ref_test.go b/ref_test.go
index 02b8e06..26f6a52 100644
--- a/ref_test.go
+++ b/ref_test.go
@@ -17,9 +17,7 @@
 import (
 	"reflect"
 	"testing"
-)
 
-import (
 	"github.com/stretchr/testify/assert"
 )
 
diff --git a/request.go b/request.go
index 968372d..2001a4b 100644
--- a/request.go
+++ b/request.go
@@ -20,9 +20,7 @@
 	"strconv"
 	"strings"
 	"time"
-)
 
-import (
 	perrors "github.com/pkg/errors"
 )
 
diff --git a/request_test.go b/request_test.go
index 9db7c56..9d54060 100644
--- a/request_test.go
+++ b/request_test.go
@@ -17,9 +17,7 @@
 import (
 	"testing"
 	"time"
-)
 
-import (
 	"github.com/stretchr/testify/assert"
 )
 
diff --git a/response.go b/response.go
index a1f68ff..a159699 100644
--- a/response.go
+++ b/response.go
@@ -20,14 +20,9 @@
 	"reflect"
 	"strconv"
 	"strings"
-)
 
-import (
-	perrors "github.com/pkg/errors"
-)
-
-import (
 	"github.com/apache/dubbo-go-hessian2/java_exception"
+	perrors "github.com/pkg/errors"
 )
 
 type Response struct {
diff --git a/response_test.go b/response_test.go
index b88cbcd..c29185a 100644
--- a/response_test.go
+++ b/response_test.go
@@ -17,8 +17,7 @@
 import (
 	"reflect"
 	"testing"
-)
-import (
+
 	"github.com/stretchr/testify/assert"
 )
 
diff --git a/serialize_test.go b/serialize_test.go
index 195a758..518230b 100644
--- a/serialize_test.go
+++ b/serialize_test.go
@@ -17,9 +17,7 @@
 import (
 	"reflect"
 	"testing"
-)
 
-import (
 	big "github.com/dubbogo/gost/math/big"
 	"github.com/stretchr/testify/assert"
 )
diff --git a/string.go b/string.go
index 60dfb6d..0520a00 100644
--- a/string.go
+++ b/string.go
@@ -15,15 +15,17 @@
 package hessian
 
 import (
+	"bufio"
 	"bytes"
+	"fmt"
 	"io"
 	"reflect"
 	"strconv"
 	"unicode/utf8"
 	"unsafe"
-)
 
-import (
+	gxbytes "github.com/dubbogo/gost/bytes"
+
 	perrors "github.com/pkg/errors"
 )
 
@@ -41,51 +43,161 @@
 	return
 }
 
+// NOTE: The length of hessian string is the number of 16-bit characters,
+// which may be different than the number of bytes.
+// String chunks may not split surrogate pairs.
+//
+// While golang support ucs-4, a rune may exceed 16-bit, which need convert to ucs-2.
+//
+// ref:
+// - https://en.wikipedia.org/wiki/UTF-16
+// - https://en.wikipedia.org/wiki/UCS-4
+func encodeUcs4Rune(b []byte, r rune) (int, int) {
+	if r >= 0x10000 && r <= 0x10FFFF {
+		t := uint32(r) - 0x10000
+		n := encodeUcs2Rune(b, t>>10+0xD800)
+		n += encodeUcs2Rune(b[n:], t&0x3FF+0xDC00)
+		return n, 2
+	}
+
+	// in fact, a rune over 0x10FFFF can't be encoded by hessian, ignore it currently
+	return utf8.EncodeRune(b, r), 1
+}
+
+func encodeUcs2Rune(b []byte, ch uint32) int {
+	if ch < 0x80 {
+		b[0] = byte(ch)
+		return 1
+	}
+
+	if ch < 0x800 {
+		b[0] = byte(0xc0 + ((ch >> 6) & 0x1f))
+		b[1] = byte(0x80 + (ch & 0x3f))
+		return 2
+	}
+
+	b[0] = byte(0xe0 + ((ch >> 12) & 0x0f))
+	b[1] = byte(0x80 + ((ch >> 6) & 0x3f))
+	b[2] = byte(0x80 + (ch & 0x3f))
+
+	return 3
+}
+
+func decodeUcs4Rune(r *bufio.Reader) (c rune, cLen, bLen int, err error) {
+	c1, n1, err1 := decodeUcs2Rune(r)
+	if err1 != nil {
+		return c1, 0, n1, err1
+	}
+
+	if c1 >= 0xD800 && c1 <= 0xDBFF {
+		c2, n2, err2 := decodeUcs2Rune(r)
+		if err2 != nil {
+			return c2, 0, n2, err2
+		}
+
+		c := (c1-0xD800)<<10 + (c2 - 0xDC00) + 0x10000
+		return c, 2, n1 + n2, nil
+	}
+
+	return c1, 1, n1, nil
+}
+
+func decodeUcs2Rune(r *bufio.Reader) (rune, int, error) {
+	ch, err := r.ReadByte()
+	if err != nil {
+		return utf8.RuneError, 1, err
+	}
+
+	if ch < 0x80 {
+		return rune(ch), 1, nil
+	}
+
+	if (ch & 0xe0) == 0xc0 {
+		ch1, err := r.ReadByte()
+		if err != nil {
+			return utf8.RuneError, 2, err
+		}
+		return rune(((uint32(ch) & 0x1f) << 6) + (uint32(ch1) & 0x3f)), 2, nil
+	}
+
+	if (ch & 0xf0) == 0xe0 {
+		ch1, err := r.ReadByte()
+		if err != nil {
+			return utf8.RuneError, 2, err
+		}
+		ch2, err := r.ReadByte()
+		if err != nil {
+			return utf8.RuneError, 3, err
+		}
+		c := ((uint32(ch) & 0x0f) << 12) + ((uint32(ch1) & 0x3f) << 6) + (uint32(ch2) & 0x3f)
+		return rune(c), 3, nil
+	}
+
+	return utf8.RuneError, 0, fmt.Errorf("bad utf-8 encoding at %x", ch)
+}
+
 // # UTF-8 encoded character string split into 64k chunks
 // ::= x52 b1 b0 <utf8-data> string  # non-final chunk
 // ::= 'S' b1 b0 <utf8-data>         # string of length 0-65535
 // ::= [x00-x1f] <utf8-data>         # string of length 0-31
 // ::= [x30-x34] <utf8-data>         # string of length 0-1023
 func encString(b []byte, v string) []byte {
-	var (
-		vLen int
-
-		vBuf = *bytes.NewBufferString(v)
-
-		vChunk = func(length int) {
-			for i := 0; i < length; i++ {
-				if r, s, err := vBuf.ReadRune(); s > 0 && err == nil {
-					// b = append(b, []byte(string(r))...)
-					b = append(b, Slice(string(r))...) // converts it to []byte in memory space of "r"
-				}
-			}
-		}
-	)
-
 	if v == "" {
 		return encByte(b, BC_STRING_DIRECT)
 	}
 
+	var (
+		byteLen = 0
+		charLen = 0
+		last    = false
+		vBuf    = *bytes.NewBufferString(v)
+
+		byteRead  = 0
+		charCount = 0
+		byteCount = 0
+	)
+
+	bufp := gxbytes.GetBytes(CHUNK_SIZE * 3)
+	buf := *bufp
+	defer gxbytes.PutBytes(bufp)
+
 	for {
-		vLen = utf8.RuneCount(vBuf.Bytes())
-		if vLen == 0 {
+		if vBuf.Len() <= 0 {
 			break
 		}
-		if vLen > CHUNK_SIZE {
-			b = encByte(b, BC_STRING_CHUNK)
-			b = encByte(b, PackUint16(uint16(CHUNK_SIZE))...)
-			vChunk(CHUNK_SIZE)
-		} else {
-			if vLen <= int(STRING_DIRECT_MAX) {
-				b = encByte(b, byte(vLen+int(BC_STRING_DIRECT)))
-			} else if vLen <= int(STRING_SHORT_MAX) {
-				b = encByte(b, byte((vLen>>8)+int(BC_STRING_SHORT)), byte(vLen))
-			} else {
-				b = encByte(b, BC_STRING)
-				b = encByte(b, PackUint16(uint16(vLen))...)
+
+		charCount = 0
+		byteCount = 0
+		for charCount <= CHUNK_SIZE {
+			r, _, err := vBuf.ReadRune()
+			if err != nil {
+				if err == io.EOF {
+					last = true
+				}
+				break
 			}
-			vChunk(vLen)
+
+			byteLen, charLen = encodeUcs4Rune(buf[byteCount:], r)
+			charCount += charLen
+			byteCount += byteLen
 		}
+
+		switch {
+		case !last && charCount >= CHUNK_SIZE:
+			b = encByte(b, BC_STRING_CHUNK)
+			b = encByte(b, PackUint16(uint16(charCount))...)
+		case charCount <= int(STRING_DIRECT_MAX):
+			b = encByte(b, byte(charCount+int(BC_STRING_DIRECT)))
+		case charCount <= STRING_SHORT_MAX:
+			b = encByte(b, byte((charCount>>8)+int(BC_STRING_SHORT)), byte(charCount))
+		default:
+			b = encByte(b, BC_STRING)
+			b = encByte(b, PackUint16(uint16(charCount))...)
+		}
+
+		b = append(b, buf[:byteCount]...)
+
+		byteRead = byteRead + byteCount
 	}
 
 	return b
@@ -136,11 +248,11 @@
 // hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2Input.java : readString
 func (d *Decoder) decString(flag int32) (string, error) {
 	var (
-		tag    byte
-		length int32
-		last   bool
-		s      string
-		r      rune
+		tag       byte
+		charTotal int32
+		last      bool
+		s         string
+		r         rune
 	)
 
 	if flag != TAG_READ {
@@ -199,12 +311,20 @@
 		if err != nil {
 			return s, perrors.WithStack(err)
 		}
-		length = l
-		runeDate := make([]rune, length)
-		for i := 0; ; {
-			if int32(i) == length {
+		charTotal = l
+		charCount := 0
+
+		runeData := make([]rune, charTotal)
+		runeIndex := 0
+
+		byteCount := 0
+		byteLen := 0
+		charLen := 0
+
+		for {
+			if int32(charCount) == charTotal {
 				if last {
-					return string(runeDate), nil
+					return string(runeData[:runeIndex]), nil
 				}
 
 				b, _ := d.readByte()
@@ -223,27 +343,32 @@
 					if err != nil {
 						return s, perrors.WithStack(err)
 					}
-					length += l
-					bs := make([]rune, length)
-					copy(bs, runeDate)
-					runeDate = bs
+					charTotal += l
+					bs := make([]rune, charTotal)
+					copy(bs, runeData)
+					runeData = bs
 
 				default:
-					return s, perrors.WithStack(err)
+					return s, perrors.New("expect string tag")
 				}
-
-			} else {
-				r, _, err = d.reader.ReadRune()
-				if err != nil {
-					return s, perrors.WithStack(err)
-				}
-				runeDate[i] = r
-				i++
 			}
+
+			r, charLen, byteLen, err = decodeUcs4Rune(d.reader)
+			if err != nil {
+				if err == io.EOF {
+					break
+				}
+				return s, perrors.WithStack(err)
+			}
+
+			runeData[runeIndex] = r
+			runeIndex++
+
+			charCount += charLen
+			byteCount += byteLen
 		}
 
-		// unreachable
-		// return string(runeDate), nil
+		return string(runeData[:runeIndex]), nil
 	}
 
 	return s, perrors.Errorf("unknown string tag %#x\n", tag)
diff --git a/string_test.go b/string_test.go
index 87de5e5..c52ae87 100644
--- a/string_test.go
+++ b/string_test.go
@@ -17,6 +17,8 @@
 import (
 	"fmt"
 	"testing"
+
+	"github.com/stretchr/testify/assert"
 )
 
 func TestEncString(t *testing.T) {
@@ -51,14 +53,19 @@
 
 	e = NewEncoder()
 	v = "我化尘埃飞扬,追寻赤裸逆翔"
-	e.Encode(v)
+	err = e.Encode(v)
+	assert.Nil(t, err)
 	if len(e.Buffer()) == 0 {
 		t.Fail()
 	}
 
 	d = NewDecoder(e.Buffer())
 	res, err = d.Decode()
-	t.Logf("decode(%v) = %v, %v\n", v, res, err)
+	assert.Nil(t, err)
+	if err != nil {
+		t.Logf("err:%s", err.Error())
+	}
+	assert.Equal(t, v, res)
 }
 
 func TestEncRune(t *testing.T) {
@@ -141,3 +148,9 @@
 	testJavaDecode(t, "argString_32", s32)
 	testJavaDecode(t, "argString_65536", s65560[:65536])
 }
+
+func TestStringEmoji(t *testing.T) {
+	s0 := "emoji🤣"
+	testDecodeFramework(t, "customReplyStringEmoji", s0)
+	testJavaDecode(t, "customArgString_emoji", s0)
+}
diff --git a/test_hessian/src/main/java/test/HessianTool.java b/test_hessian/src/main/java/test/HessianTool.java
new file mode 100644
index 0000000..3af80da
--- /dev/null
+++ b/test_hessian/src/main/java/test/HessianTool.java
@@ -0,0 +1,59 @@
+// 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.io.Hessian2Output;
+import com.caucho.hessian.io.SerializerFactory;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * @author wongoo
+ */
+public class HessianTool {
+    private static SerializerFactory serializerFactory = new SerializerFactory();
+
+    public static byte[] serialize(Object obj) {
+        ByteArrayOutputStream ops = new ByteArrayOutputStream();
+        Hessian2Output out = new Hessian2Output(ops);
+        out.setSerializerFactory(serializerFactory);
+
+        try {
+            out.writeObject(obj);
+            out.close();
+        } catch (IOException e) {
+            throw new RuntimeException("hessian error", e);
+        }
+
+        byte[] bytes = ops.toByteArray();
+        return bytes;
+    }
+
+    public static Object deserialize(byte[] bytes) {
+        ByteArrayInputStream ins = new ByteArrayInputStream(bytes);
+        Hessian2Input in = new Hessian2Input(ins);
+        in.setSerializerFactory(serializerFactory);
+
+        try {
+            Object o = in.readObject();
+            in.close();
+            return o;
+        } catch (IOException e) {
+            throw new RuntimeException("hessian error", e);
+        }
+    }
+
+}
diff --git a/test_hessian/src/main/java/test/HexTool.java b/test_hessian/src/main/java/test/HexTool.java
new file mode 100644
index 0000000..98bb4c2
--- /dev/null
+++ b/test_hessian/src/main/java/test/HexTool.java
@@ -0,0 +1,62 @@
+// 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;
+
+/**
+ * @author wongoo
+ */
+public class HexTool {
+
+    public static String byteToHex(byte b) {
+        String hex = Integer.toHexString(b & 0xFF);
+        if (hex.length() < 2) {
+            hex = "0" + hex;
+        }
+        return hex;
+    }
+
+    public static String bytesToHex(byte[] bytes) {
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < bytes.length; i++) {
+            String hex = Integer.toHexString(bytes[i] & 0xFF);
+            if (hex.length() < 2) {
+                sb.append(0);
+            }
+            sb.append(hex);
+        }
+        return sb.toString();
+    }
+
+    public static byte hexToByte(String inHex) {
+        return (byte) Integer.parseInt(inHex, 16);
+    }
+
+    public static byte[] hexToByteArray(String inHex) {
+        int hexlen = inHex.length();
+        byte[] result;
+        if (hexlen % 2 == 1) {
+            hexlen++;
+            result = new byte[(hexlen / 2)];
+            inHex = "0" + inHex;
+        } else {
+            result = new byte[(hexlen / 2)];
+        }
+        int j = 0;
+        for (int i = 0; i < hexlen; i += 2) {
+            result[j] = hexToByte(inHex.substring(i, i + 2));
+            j++;
+        }
+        return result;
+    }
+
+}
diff --git a/test_hessian/src/main/java/test/TestCustomDecode.java b/test_hessian/src/main/java/test/TestCustomDecode.java
index 5eae85f..5bafd31 100644
--- a/test_hessian/src/main/java/test/TestCustomDecode.java
+++ b/test_hessian/src/main/java/test/TestCustomDecode.java
@@ -17,16 +17,14 @@
 import com.caucho.hessian.io.Hessian2Input;
 import com.caucho.hessian.test.A0;
 import com.caucho.hessian.test.A1;
+import test.model.DateDemo;
 
-import javax.xml.crypto.Data;
 import java.io.InputStream;
-import java.lang.reflect.Array;
+import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
 import java.util.List;
-import java.math.BigDecimal;
-import test.model.DateDemo;
 
 public class TestCustomDecode {
 
@@ -49,99 +47,99 @@
     public Object customArgTypedFixedList() throws Exception {
         A0[] list = new A0[]{new A0()};
         Object o = input.readObject();
-        return Arrays.equals(list,(A0[])o);
+        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);
+        return Arrays.equals(list, (short[]) o);
     }
 
     public Object customArgTypedFixedList_short_7() throws Exception {
-        short[] list = new short[]{1,2,3,4,5,6,7};
+        short[] list = new short[]{1, 2, 3, 4, 5, 6, 7};
         Object o = input.readObject();
-        return Arrays.equals(list,(short[])o);
+        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);
+        return Arrays.equals(list, (int[]) o);
     }
 
     public Object customArgTypedFixedList_int_7() throws Exception {
-        int[] list = new int[]{1,2,3,4,5,6,7};
+        int[] list = new int[]{1, 2, 3, 4, 5, 6, 7};
         Object o = input.readObject();
-        return Arrays.equals(list,(int[])o);
+        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);
+        return Arrays.equals(list, (long[]) o);
     }
 
     public Object customArgTypedFixedList_long_7() throws Exception {
-        long[] list = new long[]{1,2,3,4,5,6,7};
+        long[] list = new long[]{1, 2, 3, 4, 5, 6, 7};
         Object o = input.readObject();
-        return Arrays.equals(list,(long[])o);
+        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);
+        return Arrays.equals(list, (float[]) o);
     }
 
     public Object customArgTypedFixedList_float_7() throws Exception {
-        float[] list = new float[]{1,2,3,4,5,6,7};
+        float[] list = new float[]{1, 2, 3, 4, 5, 6, 7};
         Object o = input.readObject();
-        return Arrays.equals(list,(float[])o);
+        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);
+        return Arrays.equals(list, (double[]) o);
     }
 
     public Object customArgTypedFixedList_double_7() throws Exception {
-        double[] list = new double[]{1,2,3,4,5,6,7};
+        double[] list = new double[]{1, 2, 3, 4, 5, 6, 7};
         Object o = input.readObject();
-        return Arrays.equals(list,(double[])o);
+        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);
+        return Arrays.equals(list, (boolean[]) o);
     }
 
     public Object customArgTypedFixedList_boolean_7() throws Exception {
-        boolean[] list = new boolean[]{true,false,true,false,true,false,true};
+        boolean[] list = new boolean[]{true, false, true, false, true, false, true};
         Object o = input.readObject();
-        return Arrays.equals(list,(boolean[])o);
+        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);
+        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);
+        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 Arrays.deepEquals(list, (int[][][]) o);
+        } catch (Exception e) {
             return e.toString();
         }
     }
@@ -149,29 +147,35 @@
     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);
+        return Arrays.deepEquals(list, (A0[][][]) o);
     }
 
     public Object customArgTypedFixedList_Test() throws Exception {
         TypedListTest t = new TypedListTest();
         Object o = input.readObject();
-        TypedListTest t2 = (TypedListTest)o;
+        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);
+        return Arrays.deepEquals(list, (Object[]) o);
     }
 
     public Object customArgTypedFixedList_Decimal() throws Exception {
         BigDecimal o = (BigDecimal) input.readObject();
-        return o.toString().equals( "100.256");
+        return o.toString().equals("100.256");
     }
 
     public Object customArgTypedFixedList_DateNull() throws Exception {
         DateDemo o = (DateDemo) input.readObject();
         return o.getDate() == null && o.getDate1() == null;
     }
+
+    public Object customArgString_emoji() throws Exception {
+        String o = (String) input.readObject();
+        String s = "emoji\uD83E\uDD23";
+        return s.equals(o);
+    }
 }
\ 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 bbe6403..fdccc15 100644
--- a/test_hessian/src/main/java/test/TestCustomReply.java
+++ b/test_hessian/src/main/java/test/TestCustomReply.java
@@ -17,13 +17,13 @@
 import com.alibaba.com.caucho.hessian.io.Hessian2Output;
 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;
 import java.util.Date;
 import java.util.HashMap;
-import java.math.BigDecimal;
-import test.model.DateDemo;
 
 public class TestCustomReply {
 
@@ -80,7 +80,7 @@
             return;
         }
         boolean hasEnd = output.writeListBegin(-1, typeMap.get(o.getClass()));
-        for (Object tmp: o) {
+        for (Object tmp : o) {
             output.writeObject(tmp);
         }
         if (hasEnd) {
@@ -95,7 +95,7 @@
             return;
         }
         boolean hasEnd = output.writeListBegin(o.length, null);
-        for (Object tmp: o) {
+        for (Object tmp : o) {
             output.writeObject(tmp);
         }
         if (hasEnd) {
@@ -110,7 +110,7 @@
             return;
         }
         boolean hasEnd = output.writeListBegin(-1, null);
-        for (Object tmp: o) {
+        for (Object tmp : o) {
             output.writeObject(tmp);
         }
         if (hasEnd) {
@@ -131,7 +131,7 @@
             return;
         }
         boolean hasEnd = output.writeListBegin(-1, "[com.caucho.hessian.test.A0");
-        for (Object tmp: o) {
+        for (Object tmp : o) {
             output.writeObject(tmp);
         }
         if (hasEnd) {
@@ -152,7 +152,7 @@
             return;
         }
         boolean hasEnd = output.writeListBegin(-1, typeMap.get(o.getClass()));
-        for (Object tmp: o) {
+        for (Object tmp : o) {
             output.writeObject(tmp);
         }
         if (hasEnd) {
@@ -173,7 +173,7 @@
             return;
         }
         boolean hasEnd = output.writeListBegin(-1, typeMap.get(o.getClass()));
-        for (Object tmp: o) {
+        for (Object tmp : o) {
             output.writeObject(tmp);
         }
         if (hasEnd) {
@@ -194,7 +194,7 @@
             return;
         }
         boolean hasEnd = output.writeListBegin(-1, typeMap.get(o.getClass()));
-        for (Object tmp: o) {
+        for (Object tmp : o) {
             output.writeObject(tmp);
         }
         if (hasEnd) {
@@ -215,7 +215,7 @@
             return;
         }
         boolean hasEnd = output.writeListBegin(-1, typeMap.get(o.getClass()));
-        for (Object tmp: o) {
+        for (Object tmp : o) {
             output.writeObject(tmp);
         }
         if (hasEnd) {
@@ -236,7 +236,7 @@
             return;
         }
         boolean hasEnd = output.writeListBegin(-1, typeMap.get(o.getClass()));
-        for (Object tmp: o) {
+        for (Object tmp : o) {
             output.writeObject(tmp);
         }
         if (hasEnd) {
@@ -251,7 +251,7 @@
             return;
         }
         boolean hasEnd = output.writeListBegin(o.length, typeMap.get(o.getClass()));
-        for (Object tmp: o) {
+        for (Object tmp : o) {
             output.writeObject(tmp);
         }
         if (hasEnd) {
@@ -266,7 +266,7 @@
             return;
         }
         boolean hasEnd = output.writeListBegin(-1, typeMap.get(o.getClass()));
-        for (Object tmp: o) {
+        for (Object tmp : o) {
             output.writeObject(tmp);
         }
         if (hasEnd) {
@@ -287,7 +287,7 @@
             return;
         }
         boolean hasEnd = output.writeListBegin(-1, typeMap.get(o.getClass()));
-        for (Object tmp: o) {
+        for (Object tmp : o) {
             output.writeObject(tmp);
         }
         if (hasEnd) {
@@ -308,7 +308,7 @@
             return;
         }
         boolean hasEnd = output.writeListBegin(-1, typeMap.get(o.getClass()));
-        for (Object tmp: o) {
+        for (Object tmp : o) {
             output.writeObject(tmp);
         }
         if (hasEnd) {
@@ -348,21 +348,28 @@
     }
 
     public void customReplyTypedFixedDateNull() throws Exception {
-        DateDemo demo = new DateDemo("zhangshan",null,null);
+        DateDemo demo = new DateDemo("zhangshan", null, null);
         output.writeObject(demo);
         output.flush();
     }
 
+    public void customReplyStringEmoji() throws Exception {
+        String s = "emoji\uD83E\uDD23";
+        output.writeObject(s);
+        output.flush();
+    }
+
 }
 
 class TypedListTest implements Serializable {
     public A0 a;
     public A0[][] list;
     public A1[][] list1;
+
     TypedListTest() {
         this.a = new A0();
-        this.list = new A0[][]{{new A0(), new A0()},{new A0(), new A0()}};
-        this.list1 = new A1[][]{{new A1(), new A1()},{new A1(), new A1()}};
+        this.list = new A0[][]{{new A0(), new A0()}, {new A0(), new A0()}};
+        this.list1 = new A1[][]{{new A1(), new A1()}, {new A1(), new A1()}};
     }
 
 }