commit | f8682e1eb9f1965da066b01454a2e94d750711ba | [log] [tgz] |
---|---|---|
author | 望哥 <gelnyang@163.com> | Mon Jun 15 09:07:14 2020 +0800 |
committer | GitHub <noreply@github.com> | Mon Jun 15 09:07:14 2020 +0800 |
tree | 72f4eacb28e9a473b38e9956a6a38b8272d810ce | |
parent | e026b32f47d548e1d8051ac769364aa67678df3f [diff] |
merge for the release of v1.6.0 (#195) * add license checker (#175) * add release note for v1.5.0 (#178) Co-authored-by: Xin.Zh <dragoncharlie@foxmail.com> * Imp: cache in reflection (#179) * benchmark result * use cache in findField * encode benchmark * call field() once * remove version * fix import sync * cache in registerPOJO * add json bench result * prune unneccessary rtype.Field(index) * cache comment * rename cache * switch to if * remove return value name * findFieldWithCache * remove if check when fieldStruct is nil Co-authored-by: 望哥 <gelnyang@163.com> * update dependency * rename serialize arg name * Create .asf.yaml * 优化hessian解码string性能,提升54% * optimize code. * optimize code. * fix code review. * optimize codes. * optimize cods. * optimize code. * update license * go.sum * ci go version * testify -> 1.4.0 * testcase * travis.yml * decode value before reflect find * setvalue * decode nilPtr to nilPtr * fix get attachment lost nil key * manually import package * add ToMapStringString unit test * rename test function name with issue * setmap * support for decode emoji. * refactor code * add unit test. * add unit tests. * refactor tests. * Update travis/main.sh (#200) - Remove duplicate key 'webhooks' - Key 'matrix' is an alias for `jobs`, using `jobs` - Specify the os and dist explicitly * Mod: modify * Code format (#199) * .gitignore * code clean * code clean * remove length check * Fix: comments * Fix: format package * Fix #181: float32 accuracy issue (#196) * Fix #181: float32 accuracy issue * Fix go fmt failure * Add the unit test case for Issue181 * Add encFloat32 in double.go to encode float32 type - Call encFloat32 to encode float32 while encoding - Add unit test case to test float32 encoding * Improve encFloat32 of double.go * Fix git fmt failure * add release note for v1.6.0 (#202) * add release note for v1.5.1 * add release note for v1.5.1 * add notice * update notice * =fix release note for v1.6.0 Co-authored-by: Joe Zou <joezou@apache.org> Co-authored-by: Xin.Zh <dragoncharlie@foxmail.com> Co-authored-by: huiren <zhrlnt@gmail.com> Co-authored-by: Huang YunKun <htynkn@gmail.com> Co-authored-by: zonghaishang <yiji@apache.org> Co-authored-by: fangyincheng <fangyc666@gmail.com> Co-authored-by: champly <champly@outlook.com> Co-authored-by: wilson chen <willson.chenwx@gmail.com> Co-authored-by: fangyincheng <fangyincheng@sina.com> Co-authored-by: gaoxinge <gaoxx5@gmail.com>
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 |
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 hessian
tag.
Example:
type MyUser struct { UserFullName string `hessian:"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 MyUser
is 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|
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:
type MyUser struct { MobilePhone string `hessian:"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
You can use hessian.SetTagIdentifier
to customize tag-identifier of hessian, which takes effect to both encoder and decoder.
Example:
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 MyUser
is 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-hessian2
supports inheritance struct, but the following situations should be avoided.
The following struct C
have 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
}