Giter Site home page Giter Site logo

apache / dubbo-go-hessian2 Goto Github PK

View Code? Open in Web Editor NEW
206.0 52.0 111.0 766 KB

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)

License: Apache License 2.0

Go 83.94% Java 15.70% Makefile 0.16% Shell 0.20%
dubbogo dubbo-go dubbo dubbox hessian hessian2 caucho apache-dubbo-go dubbo-hessian-lite dubbo-hessian

dubbo-go-hessian2's Introduction

dubbo-go-hessian2

Build Status codecov GoDoc Go Report Card license


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.

Feature List

hessian type mapping between Java and Go

Cross languages message definition should be careful, the following situations should be avoided:

  • define object that only exists in a special language
  • using various java exceptions (using error code/message instead)

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
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/java_sql_time/Date
date java.sql.Time github.com/apache/dubbo-go-hessian2/java_sql_time/Time
date all java8 sdk time github.com/apache/dubbo-go-hessian2/java8_time
Integer java.lang.Integer *int32
Byte java.lang.Byte *byte
Short java.lang.Short *int16
Boolean java.lang.Boolean *bool
Long java.lang.Long *int64
Float java.lang.Float *float32
Double java.lang.Double *float64
Character java.lang.Character *hessian.Rune
OTHER COMMON USING TYPE

reference

Basic Usage Examples

Encode To Bytes

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()

Decode From Bytes

decodedObject, err := NewDecoder(bytes).Decode()
if err != nil {
    panic(err)
}
circular, ok := obj.(*Circular)
// ...

Customize Usage Examples

Encoding filed name

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|

Decoding filed name

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

Encoding param name

When a Java method declares an argument as a parent class, it actually hope receives a subclass, You can specify the encoding type of the parameter separately.

java-server
public abstract class User {
}

public class MyUser extends User implements Serializable {

    private String userFullName;

    private String familyPhoneNumber;
}

public interface UserProvider {
    String GetUser(User user);
}

public class UserProviderImpl implements UserProvider {
    public UserProviderImpl() {
    }
    
    public String GetUser(User user) {
        MyUser myUser=(MyUser)user;
        return myUser.getUserFullName();
    }
}
go-client
type MyUser struct {
    UserFullName      string   `hessian:"userFullName"`
    FamilyPhoneNumber string   // default convert to => familyPhoneNumber
}

func (m *MyUser) JavaClassName() string {
    return "com.company.MyUser"
}

func (m *MyUser) JavaParamName() string {
    return "com.company.User"
}

type UserProvider struct {
    GetUser func(ctx context.Context, user *MyUser) (string, error) `dubbo:"GetUser"`
}

Set method Alias

When the Go client calls the Java server, the first letter of the method is converted to lowercase by default,you can use the dubbo tag to set method alias.

type UserProvider struct {
    GetUser func(ctx context.Context) (*User, error) `dubbo:"GetUser"`
}

hessian.SetTagIdentifier

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|

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:

//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.

  • Avoid fields with the same name in multiple parent struct

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
}
  • Avoid inheritance for a pointer of struct

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
}

Strict Mode

Default, hessian2 will decode an object to map if it's not being registered. If you don't want that, change the decoder to strict mode as following, and it will return error when meeting unregistered object.

e := hessian.NewDecoder(bytes)
e.Strict = true // set to strict mode, default is false

// or 
e := hessian.NewStrictDecoder(bytes)

Tools

tools/gen-go-enum

A tool for generate hessian2 java enum define golang code. Read more details.

dubbo-go-hessian2's People

Contributors

ahaostudy avatar alexstocks avatar aliiohs avatar binbin0325 avatar cch123 avatar champly avatar cloverstd avatar comdd avatar cvictory avatar dependabot[bot] avatar fangyincheng avatar gaoxinge avatar ice-summer-bug avatar laurencelizhixin avatar lujjjh avatar micln avatar pantianying avatar sdttttt avatar shenchao861129 avatar skyao avatar tiltwind avatar tylitianrui avatar u0x01 avatar willson-chen avatar wongoo avatar xujianhai666 avatar ygrylls avatar zhangymperson avatar zonghaishang avatar zouyx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dubbo-go-hessian2's Issues

Add: mapping go *bool to java Boolean

What would you like to be added:
mapping go *bool to java Boolean

  • codec support between java Boolean null and go *bool nil

Why is this needed:

  • Boolean is used widely in java

[Improvement] returned a reflect.value when decoding

https://github.com/dubbogo/hessian2/blob/57ac2e777dc6d853bdcf74b5c697b6a98a728be9/object.go#L305
https://github.com/dubbogo/hessian2/blob/57ac2e777dc6d853bdcf74b5c697b6a98a728be9/object.go#L440
that lines should return vRef.Interface() of value itself instead vRef of reflect.value.

Its effect user decoding what he want, eg:
I registered a POJO named MyUser, when I decode a hessian should return a MyUser type struct to me, but I must doing type assertion twice now for getting type of MyUser:

	RegisterPOJO(new(MyUser))

	d := hessian.NewDecoder(b)
	res, err := d.Decode()
	if err != nil {
		panic(err)
	}

	t.Logf("decode => %+v %v", res.(reflect.Value).Interface(), err)

	user := res.(reflect.Value).Interface().(*MyUser)

Its should using like this for normal user:

	RegisterPOJO(new(MyUser))

	d := hessian.NewDecoder(b)
	res, err := d.Decode()
	if err != nil {
		panic(err)
	}

	t.Logf("decode => %+v %v", res, err)

	user := res.(*MyUser)

多级指针反序列化bug

What happened:
type Demo{
Name ***string
}
当目标为多级指针时会出现序列化错误,当前已暂时修复部分类型。具体解决方案未出。
What you expected to happen:

How to reproduce it (as minimally and precisely as possible):

Anything else we need to know?:

Add: mapping go *int to java Integer

What would you like to be added:
mapping go *int to java Integer

  • codec support between java Integer null and go *int nil

Why is this needed:

  • Integer is used widely in java

go serialization & java unserialization issue

What happened:

1.serialization failed when I try to unserialize go class with inheritance
2.lose attribute when I try to unserialize java class with implement

What you expected to happen:

Serialize between java and go for all type

How to reproduce it (as minimally and precisely as possible):
Q1.
`package main

import (
"fmt"
"github.com/apache/dubbo-go-hessian2"
"os"
)

type BasketballPlayer struct {
Skill string
}

type Demo struct {
BasketballPlayer //不支持
Team string
Name string
Number int
Description []string
Teammate map[string]string
}

func (d Demo) JavaClassName() string {
return "app.pojo.Demo"
}

func main() {
file, err := os.OpenFile("F:\serialization\serializedResult", os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
panic(err)
}
defer file.Close()

t := Demo{
    Team:        "Lakers",
    Name:        "LebornJames",
    Number:      23,
    Description: []string{"61 points", "3 champions"},
    Teammate:    map[string]string{"3": "wade", "2": "irving"},
}
e := hessian.NewEncoder()
err = e.Encode(t)
if err != nil {
    panic(err)
}

_, err = file.Write(e.Buffer())
if err != nil {
    panic(err)
}
fmt.Println("serialize done!")

}
`
I was told "panic: failed to encode field: main.BasketballPlayer, {Skill:}: struct type not Support! main.BasketballPlayer[{}] is not a instance of POJO!" when I try to dubug this

Q2.
java code:
Association.java
`package app.pojo;

import java.io.Serializable;

public interface Association {
String associationName = "NBA";
}
`

BasketballPlayer.java
`package app.pojo;

import java.io.Serializable;

public class BasketballPlayer implements Serializable {
public static final long serialVersionUID = 1L;
private String skill = "jump shot";

}
`

Demo.java
`package app.pojo;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

import lombok.Data;

@DaTa
public class Demo extends BasketballPlayer implements Serializable,Association {
private static final long serialVersionUID = 1L;
public String skill;
private String team;
private String name;
private int number;
private List description;
private Map<String, String> teammate;

@Override
public String toString() {
    return "Demo{" +
            "skill=" + skill +
            "' team='" + team +
            "' name='" + name +
            "', number=" + number +
            "', description='" + description +
            "', teammate='" + teammate +
            "', association='" + associationName +"'}";
}

}
**App.java**package app;

import java.io.ByteArrayOutputStream;

import com.caucho.hessian.io.Hessian2Output;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import app.pojo.Demo;

public class App {
public static void main(String[] args) {
Demo demo = new Demo();
demo.setTeam("Lakers");
demo.setName("kobeBryant");
demo.setNumber(24);
List list = new ArrayList();
list.add("81 points");
list.add("5 champions");
demo.setDescription(list);
Map map = new HashMap();
map.put("34","O'Neal");
map.put("16", "Gasol");
demo.setTeammate(map);
try {
byte[] data = App.serialize(demo);
FileOutputStream os =new FileOutputStream(new File("F:\serialization\serializedResult"));
System.out.println(data.length);
os.write(data);
os.close();
System.out.println("done");
} catch (Exception e) {
e.printStackTrace();
}
}

public static byte[] serialize(Object obj){
    ByteArrayOutputStream byteArrayOutputStream = null;
    Hessian2Output hessianOutput = null;
    try {
        byteArrayOutputStream = new ByteArrayOutputStream();
        // Hessian的序列化输出
        hessianOutput = new Hessian2Output(byteArrayOutputStream);
        hessianOutput.writeObject(obj);
        hessianOutput.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return byteArrayOutputStream.toByteArray();
}

}

`

go code

`package main

import (
"fmt"
"github.com/apache/dubbo-go-hessian2"
"io/ioutil"
"os"
)

type Demo struct {
Skill string
Team string
Name string
Number int
Description []string
Teammate map[string] string
AssociationName string
}

func (d Demo) JavaClassName() string {
return "app.pojo.Demo"
}

func main() {
file, err := os.Open("F:\serialization\serializedResult")
if err != nil {
panic(err)
}
defer file.Close()

t := Demo{}
e := hessian.NewEncoder()
e.Encode(t)
if err != nil {
   panic(err)
}

bytes, _ := ioutil.ReadAll(file)
decodedObject, err := hessian.NewDecoder(bytes).Decode()
if err != nil {
    panic(err)
}

d, ok := decodedObject.(*Demo)
if !ok {
    panic("fail")
}
fmt.Printf("%v\n", *d)

}`

result:

API server listening at: 127.0.0.1:50036
{jump shot Lakers kobeBryant 24 [81 points 5 champions] map[16:Gasol 34:O'Neal] }

it lose association='NBA' (didn't happen when I try to unserialize with java)

Anything else we need to know?:

Any solution to fix that problem

can't decode null java date

What happened:
link to: apache/dubbo-go#105

What you expected to happen:
enable to decode null java date object

How to reproduce it (as minimally and precisely as possible):

Anything else we need to know?:

关于对 Java Collection 的支持

与 Java 对接业务中(尤其指对接已有 Java 端)可能遇到 Java 端出于某些原因需要接收非 List 类型集合的情况,如 Set 等。
可以考虑加入对 Java Collection 的序列化与反序列化支持。

Java 端 hessian 序列化非 List 类型集合是序列化成 fixed-length type list 的形式,集合的类型被写在 type 中的一部分。见 com.caucho.hessian.io.CollectionSerializer .

模仿 Java 序列化的方式目前可以通过 go-hessian 的 Serializer 扩展加一个 JavaCollection 接口的形式提供序列化集合的功能(代码见下方),但接收 Java 端集合的情况下,所有集合(被序列化为 fixed-length type list)都会因为头部是 list ('v' 或者 0x70 - 0x77)被 declist 方法反序列化为切片而无法经过 Serializer 提供的反序列化方法(decode.go#line 199 ),可能无法满足两端对象一一对应的业务需求。(即:可以满足发送特定Collection的需求,但无法还原)

可能的解决方案:

对 decode 进行一定的修改,使反序列化对象为 list 的时候,type 也作为选择 dec 方法的依据,
从而让特定 Collection 的反序列化经过 Java Collection 的反序列化器

↓ 一种基于 Serializer 扩展的序列化方案(不包含反序列化)

type JavaCollectionObject interface {
	Get() []interface{}
	JavaClassName() string
}

func init() {
	hessian.SetSerializer("java.util.HashSet", JavaCollectionSerializer{})
}

type JavaCollectionSerializer struct {
}

func (JavaCollectionSerializer) EncObject(e *hessian.Encoder, vv hessian.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 *hessian.Decoder) (interface{}, error) {
	//For collections are coded as lists instead of objects, so the dec method will never be invoked
	return nil, nil
}

func writeCollectionBegin(length int, typeName string, e *hessian.Encoder) error {
	var err error
	if length <= int(hessian.LIST_DIRECT_MAX) {
		e.Append([]byte{hessian.BC_LIST_DIRECT + byte(length)})
		err = e.Encode(typeName)
		if err != nil {
			return err
		}
	} else {
		e.Append([]byte{hessian.BC_LIST_FIXED})
		err = e.Encode(typeName)
		if err != nil {
			return err
		}
		err = e.Encode(int32(length))
		if err != nil {
			return nil
		}
	}
	return nil
} 

Bug: 各种包装类型零值问题

What happened:
主要问题:Integer类型null转golang中的int类型报错

可能会出现的其他问题:
基础包装类型0值都可能出现无法接收的情况
基本类型 包装类型
Byte
Integer null值
Short
Long
Float
Double
Boolean
Character
String null值

How to reproduce it (as minimally and precisely as possible):
在golang中专门设置一套可以接收0值得基础类型

Anything else we need to know?:
对于java中的复杂类型,golang接收或多或少会出现一些问题。要么不能接收,要么部分接收(如Date类型null值不能被golang中的time.Time接收)

decode时,忽略go结构不存在字段。

What would you like to be added:
目前只能decode和hessian.RegisterPOJO注入的结构完全一致的字段,如果java bean多字段就会报错。
希望可以忽略无法匹配的字段,与json序列化使用方式保持一致。
Why is this needed*:
java服务升级时经常会改动(特别是增加)bean的属性字段,目前的状况是go必须同样升级,这样显然是难以接受的。

关于map的解析

What happened:

hessian的map解析有两种情况,typeduntyped,问题出在typed的情况。如图:红框所在发生illegal class index @idx %d错误
image

What you expected to happen:

调试之后发现,在第一次得到某个type的时候(如图1:),如果不存在该类型会使用untyped方式继续解析map内容(如图2)。但是如果是map有嵌套或者数组情况,会导致能解析第一个,但是第二个开始就找不到index对应的类型了。如果支持typed map,我们是否应该限制必须注册类型,而不是默认处理为untyped。
image
图1
image
图2

How to reproduce it (as minimally and precisely as possible):

重现可以添加如下的java测试代码:
image

Anything else we need to know?:
另外,下图应该是一个bug,TAG_READ应该换为变量tag
image

decode failed when invoke to java server ,and return specially

What happened:
image

decode failed when invoke to java server ,and return specially
success for only JSONObject,success for only JSONArray
but fail with both JSONObject and JSONArray

What you expected to happen:
fix this bug
How to reproduce it (as minimally and precisely as possible):

this is the demo to Reproduction problem:
hessainTest in
https://github.com/pantianying/dubbo-go/blob/hessain_decode_fail/examples/general/dubbo/go-client/app/client.go

getTest in
https://github.com/pantianying/dubbo-go/blob/hessain_decode_fail/examples/general/dubbo/java-server/src/main/java/com/ikurento/user/UserProviderImpl.java

Anything else we need to know?:
this is hessain log:
image

HessianCodec包头长度检查异常

func (h *HessianCodec) ReadHeader(header *DubboHeader) error {

var err error

if h.reader.Size() < HEADER_LENGTH {
	return ErrHeaderNotEnough
}
buf, err := h.reader.Peek(HEADER_LENGTH)
if err != nil { // this is impossible
	return perrors.WithStack(err)
}
...

这一段会检查长度是否大于包头长度。由下面这段调用。

// Unmarshal ...
func (p *DubboPackage) Unmarshal(buf *bytes.Buffer, opts ...interface{}) error {
codec := hessian.NewHessianCodec(bufio.NewReaderSize(buf, buf.Len()))

// read header
err := codec.ReadHeader(&p.Header)

但是在bufio.NewReaderSize(buf, buf.Len())中

func NewReaderSize(rd io.Reader, size int) *Reader {
// Is it already a Reader?
b, ok := rd.(*Reader)
if ok && len(b.buf) >= size {
return b
}
if size < minReadBufferSize {
size = minReadBufferSize
}
r := new(Reader)
r.reset(make([]byte, size), rd)
return r
}

这里创建出的reader长度永远大于16.导致包头分包时,解包异常。

about Generic$invoke

抱歉英文不好,就用中文了。以上是对泛化调用的需求记录;

目标:实现goclient to javaserver 的泛化调用

以下是实现的探讨,我入门java不到一个月,肯定会有不对的地方,欢迎指出,也希望有java老鸟帮忙看看,十分感谢。

所谓泛化调用是指客户端拿不到服务端的具体类的情况(在go的客户端表现为没有写死的providerserver接口和pojo定义),java的dubbo框架已经有了这个功能,这个功能对于dubbo接口网关类服务的实现是必不可少的。

看了源码我自我以为的java的实现:
java provider端有这样一个interface
image
所有的客户端都调用该接口的$invoke进行访问,将原来的方法、参数、类型都作为请求参数
(我自己测试过,确实能够调通,但由于hessian2的这个问题,没有进入下一步的测试)
如图
image

客户端在没有注册pojo是如何解析返回的数据的。看了源码,invoke方法会将pojo转换成map返回,map中的所有元素都是基本类型,java客户端直接解析map即可,所以目前来看,如果hessain2能够支持不定深度map、数组的解析,应该就可以支持泛化调用。

StringBuilder & StringBuffer 使用string接收会报错

**err info**
2019-07-20T14:57:43.620+0800	WARN	{client:TCP_CLIENT:2:10.0.75.1:51904<->10.0.75.1:20880}, [session.handleTCPPackage] = len{0}, error:unknown string tag 0x43

java-server

  • WrapUser
    private String str1;
    private StringBuilder strBuilder2; //test
    private StringBuffer strBuffer3; //test
    private BigDecimal bigdecimalNum4;
    private Date time5;
	public WrapUser WrapTypeInspect() { 
		// WrapUser(String id, BigDecimal fracNum, Integer age, Date time)
		/*
		 * String id BigDecimal Integer Date
		 */
		WrapUser wrapRes = new WrapUser(null, null, null, null, null);
		wrapRes.setStr1("No.6546432");
		//wrapRes.setStrBuilder2(new StringBuilder("StringBuilder Test"));
		//wrapRes.setStrBuffer3(new StringBuffer("StringBuffer Test"));
		wrapRes.setBigdecimalNum4(new BigDecimal("123.456"));
		wrapRes.setTime5(new Date());
		return wrapRes;
	}

  • 给null值时,string可以正常接收
    response result: {No.6546432 null null {3 3 3 false [123 456000000 0 0 0 0 0 0 0] 123.456} 2019-07-20 15:06:13.364 +0800 CST}
    image

  • 给值时报错
    2019-07-20T15:10:38.257+0800 ERROR pkg.Unmarshal(ss:&{name:client endPoint:0xc000154100 Connection:0xc0003f6000 listener:0xc000340048 reader:0xc000340040 writer:0xc000340040 rQ:0xc00015aae0 wQ:0xc00015ab40 maxMsgLen:10240 tPool: period:5000000000 wait:1000000000 once:{m:{state:0 sema:0} done:0} done:0xc00014a1e0 attrs:0xc00016a4a0 grNum:2 lock:{w:{state:0 sema:0} writerSem:0 readerSem:0 readerCount:0 readerWait:0}}, len(@DaTa):231) = error:unknown string tag 0x43

image

flat anonymons fields

What would you like to be added:

  • flat anonymons fields
  • ignore field with tag hessian:"-"

Why is this needed:

Fix: bugs of apache/dubbo-hesisan-lite v3.2.7

What happened:
The latest dubbo-hessian-lite has released which fixed some bugs as the following picture.

image

The bug 1,3,4 may be related with dubbo-go-hessian2. If so we should fixed them too.

What you expected to happen:

Hope our big boss @zonghaishang check them exist in dubbo-go-hessian2 or not. If indeed exist, pls fix them.

Todo: fix the problems of v1.4

What would you like to be added:

1 the import block of java_exception_test.go should be splitted;
2 pls add remark for Response and EnsureResponse in response.go;

支持解码dubbo服务调用attachment

背景

在service mesh场景中,使用hessian-go作为序列化框架,需要解析dubbo请求body中的attachment(里面包含group)。因为attachment在body中方法参数字节的后面,所以需要先解析dubbo请求中的参数类型和参数值,然后才能去解析到attachemt。

What happened:

目前发现解析attachment之前,先解析方法的参数类型和参数值报错了。类似参数类型解析不到go对应的类型:can not find go type name com.raycloud.notify.api.domain.StopNotifyJob in registry.

因为请求的参数类型,是java应用发到service mesh的,因此service mesh无法提前注册StopNotifyJob类型,并且也无法知道它的类型。

What you expected to happen:

类似java的hessian序列化行为,如果反序列化类型找不到(比如是class类型),可以降级为hashmap(对应golang里面的map或者sync.Map). 这样参数解析完之后,也能解析到attachment。

How to reproduce it (as minimally and precisely as possible):

这个是真实线上java(dubbo 2.4.9)调用mesh的二进制字节流:

bytes := []byte{
	0xda, 0xbb, 0xc2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c,
	0x00, 0x00, 0x01, 0xfb, 0x05, 0x32, 0x2e, 0x36, 0x2e, 0x32, 0x30, 0x30, 0x63, 0x6f, 0x6d, 0x2e,
	0x72, 0x61, 0x79, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x2e,
	0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69,
	0x66, 0x79, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x0e, 0x32, 0x2e, 0x30,
	0x2e, 0x31, 0x2d, 0x76, 0x70, 0x63, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x0d, 0x73, 0x74, 0x6f, 0x70,
	0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x4a, 0x6f, 0x62, 0x30, 0x2e, 0x4c, 0x63, 0x6f, 0x6d, 0x2f,
	0x72, 0x61, 0x79, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x2f,
	0x61, 0x70, 0x69, 0x2f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x53, 0x74, 0x6f, 0x70, 0x4e,
	0x6f, 0x74, 0x69, 0x66, 0x79, 0x4a, 0x6f, 0x62, 0x3b, 0x43, 0x30, 0x2c, 0x63, 0x6f, 0x6d, 0x2e,
	0x72, 0x61, 0x79, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x2e,
	0x61, 0x70, 0x69, 0x2e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x4e,
	0x6f, 0x74, 0x69, 0x66, 0x79, 0x4a, 0x6f, 0x62, 0x98, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
	0x06, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x04, 0x6e, 0x69, 0x63, 0x6b, 0x04, 0x74, 0x79, 0x70,
	0x65, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x06, 0x61, 0x70, 0x70,
	0x4b, 0x65, 0x79, 0x05, 0x61, 0x70, 0x70, 0x49, 0x64, 0x08, 0x74, 0x61, 0x6f, 0x62, 0x61, 0x6f,
	0x49, 0x64, 0x60, 0x01, 0x31, 0x01, 0x31, 0x01, 0x31, 0x01, 0x31, 0x01, 0x31, 0x01, 0x31, 0x91,
	0xe1, 0x48, 0x05, 0x61, 0x2e, 0x73, 0x2e, 0x75, 0x0a, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x74,
	0x65, 0x73, 0x74, 0x05, 0x61, 0x2e, 0x73, 0x2e, 0x74, 0x10, 0x35, 0x33, 0x35, 0x36, 0x32, 0x35,
	0x38, 0x38, 0x39, 0x38, 0x37, 0x37, 0x31, 0x33, 0x31, 0x34, 0x05, 0x61, 0x2e, 0x73, 0x2e, 0x64,
	0x10, 0x6b, 0x65, 0x66, 0x75, 0x2e, 0x6b, 0x75, 0x61, 0x69, 0x6d, 0x61, 0x69, 0x2e, 0x63, 0x6f,
	0x6d, 0x04, 0x70, 0x61, 0x74, 0x68, 0x30, 0x30, 0x63, 0x6f, 0x6d, 0x2e, 0x72, 0x61, 0x79, 0x63,
	0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x2e, 0x61, 0x70, 0x69, 0x2e,
	0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x4a, 0x6f,
	0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x64, 0x75, 0x62, 0x62, 0x6f, 0x41, 0x70,
	0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x14, 0x63, 0x6f, 0x6d, 0x2d, 0x72, 0x61,
	0x79, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2d, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2d, 0x78, 0x09, 0x69,
	0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x30, 0x30, 0x63, 0x6f, 0x6d, 0x2e, 0x72, 0x61,
	0x79, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x2e, 0x61, 0x70,
	0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79,
	0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
	0x6f, 0x6e, 0x0e, 0x32, 0x2e, 0x30, 0x2e, 0x31, 0x2d, 0x76, 0x70, 0x63, 0x2d, 0x74, 0x65, 0x73,
	0x74, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x04, 0x35, 0x30, 0x30, 0x30, 0x5a,

}

在用这个库解码dubbo时,遇到类似以下错误:
image

Anything else we need to know?:

这里附上线上抓包的二进制:

dubbo.pcap.zip

request.go中的PackRequest方法

args, ok := params.([]interface{}) if !ok { return nil, jerrors.Errorf("@params is not of type: []interface{}") }
这样判断要求传入的params必须这样赋值:body:=[]interface{}{}
如果 body:=[]string{}这样赋值会无法通过这段代码的检查

Go 1.11

Imp: support attachments

In dubbo protocol, attachments need to be supported. And calling method of hessian will be changed in this improvement.

  • Maybe, it could be applyed to define a Request and Response.

add feature: 当byte反序列化成object时,使用tag查找属性

如果定义的struct的属性不是以大写的英文开头,比如:

type TestObjectStruct struct {
	_value int
}

func (*TestObjectStruct) JavaClassName() string {
	return "com.caucho.hessian.test.TestObject"
}

那么在反序列化的时候,可能会遇到值绑定不上属性的情形:

https://github.com/dubbogo/hessian2/blob/develop/object.go#L299-L301

所以是不是可以使用tag查找属性,然后把值绑定到属性上:

type TestObjectStruct struct {
	Value int `hessian:"_value"`
}

func (*TestObjectStruct) JavaClassName() string {
	return "com.caucho.hessian.test.TestObject"
}

bool pointer

What would you like to be added:
support bool pointer

Why is this needed:
user maybe use pointer to bool like *bool as a struct field, but now, it won't work well.

java Exception class

What would you like to be added:

 Can it support Java exception classes?

Why is this needed:

When dubbo-go's returns an exception, java need decode as Throwable.

java code:

Object obj = in.readObject();
if (obj instanceof Throwable == false)
     throw new IOException("Response data error, expect Throwable, but get " + obj);
setException((Throwable) obj);
setAttachments((Map<String, String>) in.readObject(Map.class));

Rft: DubboHeader的一些问题

https://github.com/dubbogo/hessian2/blob/c7d89af14ba3916b66ae09c99f0066d3a3016018/hessian.go#L36-L46

What would you like to be added:

  • 类型问题
    • DubboHeader中的byte, int, PackageType都是平台相关的类型,希望能改成uint8, uint32, uint64
    • DubboHeader中的int64是有符号的,希望能改成uint64
  • Dubbo的报文头如下
    DubboHeader
    希望能使用类似如下类似的表示(格式和顺序与官方的报文头一致):
type DubboHeader struct {
	MagicNumber uint16
	Flat        uint8  // contain Type and SerialID  
	Status      uint8
	InvokeId    uint64
	BodyLength  uint32
}

Why is this needed:

  • 保持类型的平台无关,代码可以更加鲁棒
  • 如果保证DubboHeader与官方的报文头在格式和顺序上的一致,那么可使用如下方式读写DubboHeader:
package main

import {
	"binary"
	"fmt"
}

func main() {
	reader := ... // initialize io.Reader
	writer := ... // initialize io.Writer

	header := DubboHeader{}

	// read
	binary.Read(reader, binary.BigEndian, &header)
	fmt.Println(header.MagicNumber, header.Flat, header.Status, header.InvokeIdheader.BodyLength)

	// write
	binary.Write(writer, binary.BigEndian, &header)
}
  • 上述改动的问题是:改动比较大,很有可能要改动上游的代码,比如dubbo-go

反序列化咨询

看起来要求golang的struct必须实现JavaClassName方法。 什么时候在golang中注册javaClassName到struct结构体之间的关联关系?

当golang中反序列化时,在哪里去查javaClassName对应的struct结构体信息

Java Exception class supplement

Explain

  • Your files should be in the java_exception folder, and named in format of [exception name].go. Reference java_exception.go
  • Test should be in the java_exception_test.go. Reference java_exception_test.go
  • Please reply the number to represent your work, thanks.
  • Welcome to add more exceptions to issue.

1

  • RuntimeException
  • IncompleteAnnotationException
  • AnnotationTypeMismatchException
  • NegativeArraySizeException
  • UnsupportedOperationException
  • ArithmeticException

2

  • IllegalMonitorStateException
  • ArrayStoreException
  • IllegalStateException
  • ClassCastException
  • UncheckedIOException
  • EnumConstantNotPresentException

3

  • NullPointerException
  • TypeNotPresentException
  • UndeclaredThrowableException
  • MalformedParametersException
  • WrongMethodTypeException
  • MalformedParameterizedTypeException

4

  • SecurityException
  • IllegalArgumentException
  • IllegalThreadStateException
  • NumberFormatException
  • IndexOutOfBoundsException
  • ArrayIndexOutOfBoundsException
  • StringIndexOutOfBoundsException

5

  • IllegalClassFormatException
  • ReflectiveOperationException
  • InvocationTargetException
  • NoSuchMethodException
  • NoSuchFieldException
  • IllegalAccessException
  • ClassNotFoundException
  • InstantiationException

6

  • CloneNotSupportedException
  • UnmodifiableClassException
  • InterruptedException
  • LambdaConversionException
  • IOException
  • InterruptedIOException

7

  • UncheckedIOException
  • FileNotFoundException
  • EOFException
  • SyncFailedException
  • ObjectStreamException
  • WriteAbortedException
  • InvalidObjectException
  • StreamCorruptedException
  • InvalidClassException
  • OptionalDataException
  • NotActiveException
  • NotSerializableException
  • UTFDataFormatException

8

  • DateTimeException

  • UnsupportedTemporalTypeException

  • ZoneRulesException

  • DateTimeParseException

  • FormatterClosedException

  • CancellationException

  • UnknownFormatConversionException

  • UnknownFormatFlagsException

  • IllegalFormatFlagsException

  • IllegalFormatPrecisionException

  • IllegalFormatCodePointException

  • MissingFormatArgumentException

  • MissingFormatWidthException

9

  • IllegalFormatWidthException
  • IllegalFormatConversionException
  • DuplicateFormatFlagsException
  • MissingResourceException
  • ConcurrentModificationException
  • RejectedExecutionException
  • CompletionException
  • EmptyStackException
  • IllformedLocaleException
  • NoSuchElementException
  • InputMismatchException
  • ExecutionException
  • InvalidPreferencesFormatException
  • TimeoutException
  • BackingStoreException
  • DataFormatException
  • BrokenBarrierException
  • TooManyListenersException
  • InvalidPropertiesFormatException
  • ZipException
  • JarException

序列化数组时报no this type name

What happened:序列化数组时报no this type name

//code
package t_test

import (
	hessian "github.com/dubbogo/hessian2"
	"testing"
)

type aaa struct {
	aaa  string
}

func TestHessian(t *testing.T) {

	info := []aaa{{aaa:"vvv"}}

	encoder := hessian.NewEncoder()
	err := encoder.Encode(info)
	if err!=nil{
		t.Error(err)
	}

}
// result
=== RUN   TestHessian
--- FAIL: TestHessian (0.00s)
    hessian_test.go:19: no this type name: t_test.aaa
FAIL

Process finished with exit code 1
// go mod require
github.com/dubbogo/hessian2 v1.2.4

Imp: hessian2 should handle all errors of encode and decode

What would you like to be added:
improve hessian2 error handling

Why is this needed:
If you don't handle these errors, it will cause errors to appear in the upper application, will occur some unforeseen, weird problems. Which is hard to trace reason.

eg:
https://github.com/dubbogo/hessian2/blob/c432dcada9eab283abc851c7f65760f18a0377c6/request.go#L172
https://github.com/dubbogo/hessian2/blob/c432dcada9eab283abc851c7f65760f18a0377c6/request.go#L173
https://github.com/dubbogo/hessian2/blob/c432dcada9eab283abc851c7f65760f18a0377c6/request.go#L174
https://github.com/dubbogo/hessian2/blob/c432dcada9eab283abc851c7f65760f18a0377c6/request.go#L175

Use go reflection in JIT way

What would you like to be added:

Add cache for go reflection in this package.

Why is this needed:

To make this lib more efficiency.

go []string to java []string

What would you like to be added:

image

image

golang数据结构中的[]string被java识别为java.util.ArrayList。后来发现是该版本hessaingolang只支持无类型list。导致图二java抛出异常。

Why is this needed:
实际使用中数据结构不可控,需要支持。以上图二的代码为com.alibaba.dubbo.rpc.filter.GenericFilter的源码,也无法修改。

some issues needed to fix for v1.5.0

What would you like to be added:

  1. appendix in LICENSE

  2. update the dependency libs with them latest version in go.mod:

  • github.com/dubbogo/gost v1.8.0
  • github.com/pkg/errors v0.9.1
  • github.com/stretchr/testify v1.5.1
  1. add comment for public struct/functions in
  • java_collection.go
  • request.go
  • serialize.go

反序列化出错

当反序列化一个对象的时候,发生错误。但是同样的请求用java反序列化正常。
相关代码

type TriggerParam struct {
	JobId                 int
	ExecutorHandler       string
	ExecutorParams        string
	ExecutorBlockStrategy string
	ExecutorTimeout       int
	LogId                 int
	LogDateTim            int
	GlueType              string
	GlueSource            string
	GlueUpdatetime        int
	BroadcastIndex        int
	BroadcastTotal        int
}

func (TriggerParam) JavaClassName() string {
	return "com.xxl.job.core.biz.model.TriggerParam"
}

type XxlRpcRequest struct {
	RequestId        string
	CreateMillisTime int
	AccessToken      string
	ClassName        string
	MethodName       string
	ParameterTypes   []java_exception.Class
	Parameters       []interface{}
	Version          string
}

func (XxlRpcRequest) JavaClassName() string {
	return "com.xxl.rpc.remoting.net.params.XxlRpcRequest"
}

func TestSerializerFile(t *testing.T) {

	RegisterPOJO(XxlRpcRequest{})
	RegisterPOJO(TriggerParam{})
	f, _ := os.Open("test.dat")
	bt, _ := ioutil.ReadAll(f)
	_ = f.Close()
	for e := range bt {
		fmt.Printf("0x%x ", bt[e])
	}
	fmt.Println()
	fmt.Println(string(bt))
	d := NewDecoder(bt)
	res, err := d.Decode()
	if err != nil {
		t.Errorf("Decode() = %+v", err)
	}
	resJson, _ := json.Marshal(res)
	t.Logf("decode = %v, %v\n", string(resJson), err)
}

二进制文件:https://github.com/sniperking1234/dubbo-go-hessian2/blob/xxl-job/test.dat
解析的时候报错
image
用java反序列化的结果:
image

Java's Extends and Go's Embed: Java 继承与 Go 嵌入字段

本文描述 dubbo-go-hessian2 如何处理 Java 中的继承。

为便于描述,下文会用一些特定的名词:

  • hessian 表示 Java 版本的 hessian 库
  • go-hessian2 用来指当前库。

Java 继承

Hessian 在序列化继承时,会将父类的属性展开到子类里(效果等同于把这些字段定义在子类里)。也就是说,在 hessian 的编码里,我们无法区分出这个字段是来自当前的类还是父类。所以我们做的工作就是把这些字段一一映射到 Go 的 struct 里。

Go 嵌入字段(匿名字段)

在 Go 里是没有继承这一概念的,但一般的,我们用匿名字段的方式来达到类似继承的字段复用效果。这是我们必须面临的问题,因此我们特别的支持了如下这种情况

Java Go
image image

由于上面提到的原因,我们其实无法识别这个 name 字段是父类的还是子类的,所以对于这个 Java 类,下面这段 Go 定义也是可以识别的。

type Dog struct {
	Name string
}

一般情况下,这些足够使用了。因此对于一些复杂的情况,我们并未完全处理。

暂不支持的情况

Go 里多个匿名字段拥有同样的字段名

type A struct { Name string }
type B struct { Name string }
type C struct {
	A
	B
}

这个结构体 C 有两个叫 Name 的字段,在 Go 官方的 json 库里会把两个都忽略掉。但 go-hessian2 并没有做类似的工作。因为无论怎么处理,都会让人难以理解,开发者应该避免使用这样的用法。如果因为一些失误确实定义了重复的字段,可以使用 hessian:"-" 来忽略其中一个( json 库也支持这样处理)

指针类型的匿名字段

type Dog struct {
	*Animal
}

尽管 Go 里可以这样定义结构体。但是Java 里的父类是不可能为空的,hessian 协议当然也不支持。所以 go-hessian2 也不支持这样的继承。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.