resolve conflict in readme
diff --git a/README.md b/README.md
index 349777b..8f96e36 100644
--- a/README.md
+++ b/README.md
@@ -222,6 +222,40 @@
00000040 0c 30 31 30 2d 31 32 33 34 35 36 37 38 |.010-12345678|
```
+#### Using Java collections
+By default, the output of Hessian Java impl of a Java collection like java.util.HashSet will be decoded as `[]interface{}` in `go-hessian2`.
+To apply the one-to-one mapping relationship between certain Java collection class and your Go struct, examples are as follows:
+
+```go
+//use HashSet as example
+//define your struct, which should implements hessian.JavaCollectionObject
+type JavaHashSet struct {
+ value []interface{}
+}
+
+//get the inside slice value
+func (j *JavaHashSet) Get() []interface{} {
+ return j.value
+}
+
+//set the inside slice value
+func (j *JavaHashSet) Set(v []interface{}) {
+ j.value = v
+}
+
+//should be the same as the class name of the Java collection
+func (j *JavaHashSet) JavaClassName() string {
+ return "java.util.HashSet"
+}
+
+func init() {
+ //register your struct so that hessian can recognized it when encoding and decoding
+ SetCollectionSerialize(&JavaHashSet{})
+}
+```
+
+
+
## Notice for inheritance
`go-hessian2` supports inheritance struct, but the following situations should be avoided.
diff --git a/java_collection.go b/java_collection.go
new file mode 100644
index 0000000..93ed4e6
--- /dev/null
+++ b/java_collection.go
@@ -0,0 +1,139 @@
+/*
+ * 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 hessian
+
+import (
+ perrors "github.com/pkg/errors"
+ "reflect"
+)
+
+type JavaCollectionObject interface {
+ Get() []interface{}
+ Set([]interface{})
+ JavaClassName() string
+}
+
+var collectionTypeMap = make(map[string]reflect.Type, 16)
+
+func SetCollectionSerialize(collection JavaCollectionObject) {
+ name := collection.JavaClassName()
+ v := reflect.ValueOf(collection)
+ var typ reflect.Type
+ switch v.Kind() {
+ case reflect.Struct:
+ typ = v.Type()
+ case reflect.Ptr:
+ typ = v.Elem().Type()
+ default:
+ typ = reflect.TypeOf(collection)
+ }
+ SetSerializer(name, JavaCollectionSerializer{})
+ RegisterPOJO(collection)
+ collectionTypeMap[name] = typ
+}
+
+func getCollectionSerialize(name string) reflect.Type {
+ return collectionTypeMap[name]
+}
+
+func isCollectionSerialize(name string) bool {
+ return getCollectionSerialize(name) != nil
+}
+
+type JavaCollectionSerializer struct {
+}
+
+func (JavaCollectionSerializer) EncObject(e *Encoder, vv POJO) error {
+ var (
+ err error
+ )
+ v, ok := vv.(JavaCollectionObject)
+ if !ok {
+ return perrors.New("can not be converted into java collection object")
+ }
+ collectionName := v.JavaClassName()
+ if collectionName == "" {
+ return perrors.New("collection name empty")
+ }
+ list := v.Get()
+ length := len(list)
+ typeName := v.JavaClassName()
+ err = writeCollectionBegin(length, typeName, e)
+ if err != nil {
+ return err
+ }
+ for i := 0; i < length; i++ {
+ if err = e.Encode(list[i]); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (JavaCollectionSerializer) DecObject(d *Decoder, typ reflect.Type, cls classInfo) (interface{}, error) {
+ //for the java impl of hessian encode collections as list, which will not be decoded as object in go impl, this method should not be called
+ return nil, perrors.New("unexpected collection decode call")
+}
+
+func (d *Decoder) decodeCollection(length int, listTyp string) (interface{}, error) {
+ typ := getCollectionSerialize(listTyp)
+ if typ == nil {
+ return nil, perrors.New("no collection deserialize set as " + listTyp)
+ }
+ v := reflect.New(typ).Interface()
+ collcetionV, ok := v.(JavaCollectionObject)
+ if !ok {
+ return nil, perrors.New("collection deserialize err " + listTyp)
+ }
+ list, err := d.readTypedListValue(length, "", false)
+ if err != nil {
+ return nil, err
+ }
+ listInterface, err := EnsureInterface(list, nil)
+ if err != nil {
+ return nil, err
+ }
+ listV, listOk := listInterface.([]interface{})
+ if !listOk {
+ return nil, perrors.New("collection deserialize err " + listTyp)
+ }
+ collcetionV.Set(listV)
+ return collcetionV, nil
+}
+
+func writeCollectionBegin(length int, typeName string, e *Encoder) error {
+ var err error
+ if length <= int(LIST_DIRECT_MAX) {
+ e.Append([]byte{BC_LIST_DIRECT + byte(length)})
+ err = e.Encode(typeName)
+ if err != nil {
+ return err
+ }
+ } else {
+ e.Append([]byte{BC_LIST_FIXED})
+ err = e.Encode(typeName)
+ if err != nil {
+ return err
+ }
+ err = e.Encode(int32(length))
+ if err != nil {
+ return nil
+ }
+ }
+ return nil
+}
diff --git a/java_collection_test.go b/java_collection_test.go
new file mode 100644
index 0000000..875eb9b
--- /dev/null
+++ b/java_collection_test.go
@@ -0,0 +1,58 @@
+/*
+ * 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 hessian
+
+import (
+ "testing"
+)
+
+func init() {
+ SetCollectionSerialize(&JavaHashSet{})
+}
+
+type JavaHashSet struct {
+ value []interface{}
+}
+
+func (j *JavaHashSet) Get() []interface{} {
+ return j.value
+}
+
+func (j *JavaHashSet) Set(v []interface{}) {
+ j.value = v
+}
+
+func (j *JavaHashSet) JavaClassName() string {
+ return "java.util.HashSet"
+}
+
+func TestListJavaCollectionEncode(t *testing.T) {
+ inside := make([]interface{}, 2)
+ inside[0] = int32(0)
+ inside[1] = int32(1)
+ hashSet := JavaHashSet{value: inside}
+ testJavaDecode(t, "customArgTypedFixedList_HashSet", &hashSet)
+}
+
+func TestListJavaCollectionDecode(t *testing.T) {
+ inside := make([]interface{}, 2)
+ inside[0] = int32(0)
+ inside[1] = int32(1)
+ hashSet := JavaHashSet{value: inside}
+ testDecodeFramework(t, "customReplyTypedFixedList_HashSet", &hashSet)
+}
diff --git a/list.go b/list.go
index bd330c9..34c8aec 100644
--- a/list.go
+++ b/list.go
@@ -311,7 +311,13 @@
} else {
return nil, perrors.Errorf("error typed list tag: 0x%x", tag)
}
+ if isCollectionSerialize(listTyp) {
+ return d.decodeCollection(length, listTyp)
+ }
+ return d.readTypedListValue(length, listTyp, isVariableArr)
+}
+func (d *Decoder) readTypedListValue(length int, listTyp string, isVariableArr bool) (interface{}, error) {
// return when no element
if length < 0 {
return nil, nil
diff --git a/test_hessian/src/main/java/test/TestCustomDecode.java b/test_hessian/src/main/java/test/TestCustomDecode.java
index f06fc99..e2394f5 100644
--- a/test_hessian/src/main/java/test/TestCustomDecode.java
+++ b/test_hessian/src/main/java/test/TestCustomDecode.java
@@ -23,10 +23,8 @@
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
+import java.util.*;
+
import test.model.DateDemo;
@@ -201,4 +199,9 @@
String o = (String) input.readObject();
return TestString.getEmojiTestString().equals(o);
}
+
+ public Object customArgTypedFixedList_HashSet() throws Exception {
+ HashSet o = (HashSet) input.readObject();
+ return o.contains(0) && o.contains(1);
+ }
}
\ 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 a907150..813d7eb 100644
--- a/test_hessian/src/main/java/test/TestCustomReply.java
+++ b/test_hessian/src/main/java/test/TestCustomReply.java
@@ -26,6 +26,9 @@
import java.math.BigInteger;
import java.util.Date;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
import test.model.DateDemo;
@@ -437,6 +440,22 @@
output.writeObject(dog);
output.flush();
}
+
+ public void customReplyTypedFixedList_HashSet() throws Exception {
+ Set<Integer> set = new HashSet<>();
+ set.add(0);
+ set.add(1);
+ output.writeObject(set);
+ output.flush();
+ }
+
+ public void customReplyTypedFixedList_HashSetCustomObject() throws Exception {
+ Set<Object> set = new HashSet<>();
+ set.add(new BigInteger("1234"));
+ set.add(new BigDecimal("123.4"));
+ output.writeObject(set);
+ output.flush();
+ }
}
interface Leg {