caucho hessian2 implementation in Go for [apache/dubbo-go](https://github.com/apache/dubbo-go) which is compatible with [dubbo-hessian-lite](https://github.com/apache/dubbo-hessian-lite)
Notice: When decoding, the java version of hessian will default skip and ignore non-exist fields. From the version of v1.6.0 , dubbo-go-hessian2 will skip non-exist fields too, while that before v1.6.0 will return errors.
It's a golang hessian library used by Apache/dubbo-go.
There is a big performance improvement, and some bugs fix for v1.6.0, thanks to micln, pantianying, zonghaishang, willson-chen, champly.
Cross languages message definition should be careful, the following situations should be avoided:
So we can maintain a cross language type mapping:
| hessian type | java type | golang type | | --- | --- | --- | | null | null | nil | | binary | byte[] | []byte | | boolean | boolean | bool | | date | java.util.Date | time.Time | | double | double | float64 | | int | int | int32 | | long | long | int64 | | string | java.lang.String | string | | list | java.util.List | slice | | map | java.util.Map | map | | object | custom define object | custom define struct| | OTHER COMMON USING TYPE | | | | big decimal | java.math.BigDecimal | github.com/dubbogo/gost/math/big/Decimal | | big integer | java.math.BigInteger | github.com/dubbogo/gost/math/big/Integer | | date | java.sql.Date | github.com/apache/dubbo-go-hessian2/javasqltime/Date | | date | java.sql.Time | github.com/apache/dubbo-go-hessian2/javasqltime/Time | | date | all java8 sdk time | github.com/apache/dubbo-go-hessian2/java8_time |
type Circular struct { Value Previous *Circular Next *Circular }type Value struct { Num int }
func (Circular) JavaClassName() string { return "com.company.Circular" }
c := &Circular{} c.Num = 12345 c.Previous = c c.Next = c
e := NewEncoder() err := e.Encode(c) if err != nil { panic(err) }
bytes := e.Buffer()
decodedObject, err := NewDecoder(bytes).Decode() if err != nil { panic(err) } circular, ok := obj.(*Circular) // ...
Hessian encoder default converts filed names of struct to lower camelcase, but you can customize it using
hessiantag.
Example: ``
go type MyUser struct { UserFullName stringhessian:"userfullname"` FamilyPhoneNumber string // default convert to => familyPhoneNumber }
func (MyUser) JavaClassName() string { return "com.company.myuser" }
user := &MyUser{ UserFullName: "username", FamilyPhoneNumber: "010-12345678", }
e := hessian.NewEncoder() err := e.Encode(user) if err != nil { panic(err) } ```
The encoded bytes of the struct
MyUseris as following:
text 00000000 43 12 63 6f 6d 2e 63 6f 6d 70 61 6e 79 2e 6d 79 |C.com.company.my| 00000010 75 73 65 72 92 0e 75 73 65 72 5f 66 75 6c 6c 5f |user..user_full_| 00000020 6e 61 6d 65 11 66 61 6d 69 6c 79 50 68 6f 6e 65 |name.familyPhone| 00000030 4e 75 6d 62 65 72 60 08 75 73 65 72 6e 61 6d 65 |Number`.username| 00000040 0c 30 31 30 2d 31 32 33 34 35 36 37 38 |.010-12345678|
Hessian decoder finds the correct target field though comparing all filed names of struct one by one until matching.
The following example shows the order of the matching rules: ``
go type MyUser struct { MobilePhone stringhessian:"mobile-phone"` }
// You must define the tag of struct for lookup filed form encoded binary bytes, in this case: // 00000000 43 12 63 6f 6d 2e 63 6f 6d 70 61 6e 79 2e 6d 79 |C.com.company.my| // 00000010 75 73 65 72 91 0c 6d 6f 62 69 6c 65 2d 70 68 6f |user..mobile-pho| // 00000020 6e 65 60 0b 31 37 36 31 32 33 34 31 32 33 34 |ne`.17612341234| // // mobile-phone(tag lookup) => mobilePhone(lowerCameCase) => MobilePhone(SameCase) => mobilephone(lowercase) // ^ will matched
type MyUser struct { MobilePhone string }
// The following encoded binary bytes will be hit automatically: // // 00000000 43 12 63 6f 6d 2e 63 6f 6d 70 61 6e 79 2e 6d 79 |C.com.company.my| // 00000010 75 73 65 72 91 0b 6d 6f 62 69 6c 65 50 68 6f 6e |user..mobilePhon| // 00000020 65 60 0b 31 37 36 31 32 33 34 31 32 33 34 |e
.17612341234| // // mobile-phone(tag lookup) => mobilePhone(lowerCameCase) => MobilePhone(SameCase) => mobilephone(lowercase) // ^ will matched // // 00000000 43 12 63 6f 6d 2e 63 6f 6d 70 61 6e 79 2e 6d 79 |C.com.company.my| // 00000010 75 73 65 72 91 0b 4d 6f 62 69 6c 65 50 68 6f 6e |user..MobilePhon| // 00000020 65 60 0b 31 37 36 31 32 33 34 31 32 33 34 |e.17612341234| // // mobile-phone(tag lookup) => mobilePhone(lowerCameCase) => MobilePhone(SameCase) => mobilephone(lowercase) // ^ will matched // // 00000000 43 12 63 6f 6d 2e 63 6f 6d 70 61 6e 79 2e 6d 79 |C.com.company.my| // 00000010 75 73 65 72 91 0b 6d 6f 62 69 6c 65 70 68 6f 6e |user..mobilephon| // 00000020 65 60 0b 31 37 36 31 32 33 34 31 32 33 34 |e`.17612341234| // // mobile-phone(tag lookup) => mobilePhone(lowerCameCase) => MobilePhone(SameCase) => mobilephone(lowercase) // ^ will matched
hessian.SetTagIdentifier
You can use
hessian.SetTagIdentifier
to customize tag-identifier of hessian, which takes effect to both encoder and decoder.Example:
```go hessian.SetTagIdentifier("json")
type MyUser struct { UserFullName string
json:"user_full_name"
FamilyPhoneNumber string // default convert to => familyPhoneNumber }func (MyUser) JavaClassName() string { return "com.company.myuser" }
user := &MyUser{ UserFullName: "username", FamilyPhoneNumber: "010-12345678", }
e := hessian.NewEncoder() err := e.Encode(user) if err != nil { panic(err) }
The encoded bytes of the struct
MyUseris as following:
00000000 43 12 63 6f 6d 2e 63 6f 6d 70 61 6e 79 2e 6d 79 |C.com.company.my| 00000010 75 73 65 72 92 0e 75 73 65 72 5f 66 75 6c 6c 5f |user..user_full_| 00000020 6e 61 6d 65 11 66 61 6d 69 6c 79 50 68 6f 6e 65 |name.familyPhone| 00000030 4e 75 6d 62 65 72 60 08 75 73 65 72 6e 61 6d 65 |Number`.username| 00000040 0c 30 31 30 2d 31 32 33 34 35 36 37 38 |.010-12345678|
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:
//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{}) }
go-hessian2supports inheritance struct, but the following situations should be avoided.
The following struct
Chave inherited field
Name(default from the first parent), but it's confused in logic.
type A struct { Name string } type B struct { Name string } type C struct { A B }
The following definition is valid for golang syntax, but the parent will be nil when create a new Dog, like
dog := Dog{}, which will not happen in java inheritance, and is also not supported by
go-hessian2.
type Dog struct { *Animal }