加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
object.go 15.12 KB
一键复制 编辑 原始数据 按行查看 历史
老马 提交于 2019-12-14 11:02 . first
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
/*
* 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 (
"io"
"reflect"
"strings"
)
import (
perrors "github.com/pkg/errors"
)
// get @v go struct name
func typeof(v interface{}) string {
return reflect.TypeOf(v).String()
}
/////////////////////////////////////////
// map/object
/////////////////////////////////////////
//class-def ::= 'C' string int string* // mandatory type string, the number of fields, and the field names.
//object ::= 'O' int value* // class-def id, value list
// ::= [x60-x6f] value* // class-def id, value list
//
//Object serialization
//
//class Car {
// String color;
// String model;
//}
//
//out.writeObject(new Car("red", "corvette"));
//out.writeObject(new Car("green", "civic"));
//
//---
//
//C # object definition (#0)
// x0b example.Car # type is example.Car
// x92 # two fields
// x05 color # color field name
// x05 model # model field name
//
//O # object def (long form)
// x90 # object definition #0
// x03 red # color field value
// x08 corvette # model field value
//
//x60 # object def #0 (short form)
// x05 green # color field value
// x05 civic # model field value
//
//enum Color {
// RED,
// GREEN,
// BLUE,
//}
//
//out.writeObject(Color.RED);
//out.writeObject(Color.GREEN);
//out.writeObject(Color.BLUE);
//out.writeObject(Color.GREEN);
//
//---
//
//C # class definition #0
// x0b example.Color # type is example.Color
// x91 # one field
// x04 name # enumeration field is "name"
//
//x60 # object #0 (class def #0)
// x03 RED # RED value
//
//x60 # object #1 (class def #0)
// x90 # object definition ref #0
// x05 GREEN # GREEN value
//
//x60 # object #2 (class def #0)
// x04 BLUE # BLUE value
//
//x51 x91 # object ref #1, i.e. Color.GREEN
func (e *Encoder) encObject(v POJO) error {
var (
ok bool
i int
idx int
num int
err error
clsDef classInfo
)
vv := reflect.ValueOf(v)
// check ref
if n, ok := e.checkRefMap(vv); ok {
e.buffer = encRef(e.buffer, n)
return nil
}
vv = UnpackPtr(vv)
// check nil pointer
if !vv.IsValid() {
e.buffer = encNull(e.buffer)
return nil
}
// write object definition
idx = -1
for i = range e.classInfoList {
if v.JavaClassName() == e.classInfoList[i].javaName {
idx = i
break
}
}
if idx == -1 {
idx, ok = checkPOJORegistry(typeof(v))
if !ok {
if reflect.TypeOf(v).Implements(javaEnumType) {
idx = RegisterJavaEnum(v.(POJOEnum))
} else {
idx = RegisterPOJO(v)
}
}
_, clsDef, err = getStructDefByIndex(idx)
if err != nil {
return perrors.WithStack(err)
}
idx = len(e.classInfoList)
e.classInfoList = append(e.classInfoList, clsDef)
e.buffer = append(e.buffer, clsDef.buffer...)
}
// write object instance
if byte(idx) <= OBJECT_DIRECT_MAX {
e.buffer = encByte(e.buffer, byte(idx)+BC_OBJECT_DIRECT)
} else {
e.buffer = encByte(e.buffer, BC_OBJECT)
e.buffer = encInt32(e.buffer, int32(idx))
}
if reflect.TypeOf(v).Implements(javaEnumType) {
e.buffer = encString(e.buffer, v.(POJOEnum).String())
return nil
}
num = vv.NumField()
for i = 0; i < num; i++ {
// skip unexported anonymous field
if vv.Type().Field(i).PkgPath != "" {
continue
}
field := vv.Field(i)
if err = e.Encode(field.Interface()); err != nil {
fieldName := field.Type().String()
return perrors.Wrapf(err, "failed to encode field: %s, %+v", fieldName, field.Interface())
}
}
return nil
}
/////////////////////////////////////////
// Object
/////////////////////////////////////////
//class-def ::= 'C' string int string* // mandatory type string, the number of fields, and the field names.
//object ::= 'O' int value* // class-def id, value list
// ::= [x60-x6f] value* // class-def id, value list
//
//Object serialization
//
//class Car {
// String color;
// String model;
//}
//
//out.writeObject(new Car("red", "corvette"));
//out.writeObject(new Car("green", "civic"));
//
//---
//
//C # object definition (#0)
// x0b example.Car # type is example.Car
// x92 # two fields
// x05 color # color field name
// x05 model # model field name
//
//O # object def (long form)
// x90 # object definition #0
// x03 red # color field value
// x08 corvette # model field value
//
//x60 # object def #0 (short form)
// x05 green # color field value
// x05 civic # model field value
//
//
//
//
//
//enum Color {
// RED,
// GREEN,
// BLUE,
//}
//
//out.writeObject(Color.RED);
//out.writeObject(Color.GREEN);
//out.writeObject(Color.BLUE);
//out.writeObject(Color.GREEN);
//
//---
//
//C # class definition #0
// x0b example.Color # type is example.Color
// x91 # one field
// x04 name # enumeration field is "name"
//
//x60 # object #0 (class def #0)
// x03 RED # RED value
//
//x60 # object #1 (class def #0)
// x90 # object definition ref #0
// x05 GREEN # GREEN value
//
//x60 # object #2 (class def #0)
// x04 BLUE # BLUE value
//
//x51 x91 # object ref #1, i.e. Color.GREEN
func (d *Decoder) decClassDef() (interface{}, error) {
var (
err error
clsName string
fieldNum int32
fieldName string
fieldList []string
)
clsName, err = d.decString(TAG_READ)
if err != nil {
return nil, perrors.WithStack(err)
}
fieldNum, err = d.decInt32(TAG_READ)
if err != nil {
return nil, perrors.WithStack(err)
}
fieldList = make([]string, fieldNum)
for i := 0; i < int(fieldNum); i++ {
fieldName, err = d.decString(TAG_READ)
if err != nil {
return nil, perrors.Wrapf(err, "decClassDef->decString, field num:%d, index:%d", fieldNum, i)
}
fieldList[i] = fieldName
}
return classInfo{javaName: clsName, fieldNameList: fieldList}, nil
}
func findField(name string, typ reflect.Type) (int, error) {
for i := 0; i < typ.NumField(); i++ {
// matching tag first, then lowerCamelCase, SameCase, lowerCase
if val, has := typ.Field(i).Tag.Lookup(tagIdentifier); has && strings.Compare(val, name) == 0 {
return i, nil
}
fieldName := typ.Field(i).Name
switch {
case strings.Compare(lowerCamelCase(fieldName), name) == 0:
return i, nil
case strings.Compare(fieldName, name) == 0:
return i, nil
case strings.Compare(strings.ToLower(fieldName), name) == 0:
return i, nil
}
}
return 0, perrors.Errorf("failed to find field %s", name)
}
func (d *Decoder) decInstance(typ reflect.Type, cls classInfo) (interface{}, error) {
if typ.Kind() != reflect.Struct {
return nil, perrors.Errorf("wrong type expect Struct but get:%s", typ.String())
}
vRef := reflect.New(typ)
// add pointer ref so that ref the same object
d.appendRefs(vRef.Interface())
vv := vRef.Elem()
for i := 0; i < len(cls.fieldNameList); i++ {
fieldName := cls.fieldNameList[i]
index, err := findField(fieldName, typ)
if err != nil {
return nil, perrors.Errorf("can not find field %s", fieldName)
}
// skip unexported anonymous field
if vv.Type().Field(index).PkgPath != "" {
continue
}
field := vv.Field(index)
if !field.CanSet() {
return nil, perrors.Errorf("decInstance CanSet false for field %s", fieldName)
}
// get field type from type object, not do that from value
fldTyp := UnpackPtrType(field.Type())
// unpack pointer to enable value setting
fldRawValue := UnpackPtrValue(field)
kind := fldTyp.Kind()
switch kind {
case reflect.String:
str, err := d.decString(TAG_READ)
if err != nil {
return nil, perrors.Wrapf(err, "decInstance->ReadString: %s", fieldName)
}
fldRawValue.SetString(str)
case reflect.Int32, reflect.Int16, reflect.Int8:
num, err := d.decInt32(TAG_READ)
if err != nil {
// java enum
if fldRawValue.Type().Implements(javaEnumType) {
d.unreadByte() // Enum parsing, decInt64 above has read a byte, so you need to return a byte here
s, err := d.DecodeValue()
if err != nil {
return nil, perrors.Wrapf(err, "decInstance->decObject field name:%s", fieldName)
}
enumValue, _ := s.(JavaEnum)
num = int32(enumValue)
} else {
return nil, perrors.Wrapf(err, "decInstance->decInt32, field name:%s", fieldName)
}
}
fldRawValue.SetInt(int64(num))
case reflect.Uint16, reflect.Uint8:
num, err := d.decInt32(TAG_READ)
if err != nil {
return nil, perrors.Wrapf(err, "decInstance->decInt32, field name:%s", fieldName)
}
fldRawValue.SetUint(uint64(num))
case reflect.Uint, reflect.Int, reflect.Int64:
num, err := d.decInt64(TAG_READ)
if err != nil {
if fldTyp.Implements(javaEnumType) {
d.unreadByte() // Enum parsing, decInt64 above has read a byte, so you need to return a byte here
s, err := d.Decode()
if err != nil {
return nil, perrors.Wrapf(err, "decInstance->decObject field name:%s", fieldName)
}
enumValue, _ := s.(JavaEnum)
num = int64(enumValue)
} else {
return nil, perrors.Wrapf(err, "decInstance->decInt64 field name:%s", fieldName)
}
}
fldRawValue.SetInt(num)
case reflect.Uint32, reflect.Uint64:
num, err := d.decInt64(TAG_READ)
if err != nil {
return nil, perrors.Wrapf(err, "decInstance->decInt64, field name:%s", fieldName)
}
fldRawValue.SetUint(uint64(num))
case reflect.Bool:
b, err := d.Decode()
if err != nil {
return nil, perrors.Wrapf(err, "decInstance->Decode field name:%s", fieldName)
}
v, ok := b.(bool)
if !ok {
return nil, perrors.Wrapf(err, "value convert to bool failed, field name:%s", fieldName)
}
if fldRawValue.Kind() == reflect.Ptr && fldRawValue.CanSet() {
if b != nil {
field.Set(reflect.ValueOf(&v))
}
} else if fldRawValue.Kind() != reflect.Ptr {
fldRawValue.SetBool(v)
}
case reflect.Float32, reflect.Float64:
num, err := d.decDouble(TAG_READ)
if err != nil {
return nil, perrors.Wrapf(err, "decInstance->decDouble field name:%s", fieldName)
}
fldRawValue.SetFloat(num.(float64))
case reflect.Map:
// decode map should use the original field value for correct value setting
err := d.decMapByValue(field)
if err != nil {
return nil, perrors.Wrapf(err, "decInstance->decMapByValue field name: %s", fieldName)
}
case reflect.Slice, reflect.Array:
m, err := d.decList(TAG_READ)
if err != nil {
if err == io.EOF {
break
}
return nil, perrors.WithStack(err)
}
// set slice separately
err = SetSlice(fldRawValue, m)
if err != nil {
return nil, err
}
case reflect.Struct, reflect.Interface:
var (
err error
s interface{}
)
typ := UnpackPtrType(fldRawValue.Type())
if typ.String() == "time.Time" {
s, err = d.decDate(TAG_READ)
if err != nil {
return nil, perrors.WithStack(err)
}
SetValue(fldRawValue, EnsurePackValue(s))
} else {
s, err = d.decObject(TAG_READ)
if err != nil {
return nil, perrors.WithStack(err)
}
if s != nil {
// set value which accepting pointers
SetValue(fldRawValue, EnsurePackValue(s))
}
}
default:
return nil, perrors.Errorf("unknown struct member type: %v %v", kind, typ.Name()+"."+typ.Field(index).Name)
}
} // end for
return vRef.Interface(), nil
}
func (d *Decoder) appendClsDef(cd classInfo) {
d.classInfoList = append(d.classInfoList, cd)
}
func (d *Decoder) getStructDefByIndex(idx int) (reflect.Type, classInfo, error) {
var (
ok bool
cls classInfo
s structInfo
err error
)
if len(d.classInfoList) <= idx || idx < 0 {
return nil, cls, perrors.Errorf("illegal class index @idx %d", idx)
}
cls = d.classInfoList[idx]
s, ok = getStructInfo(cls.javaName)
if !ok {
if !d.isSkip {
err = perrors.Errorf("can not find go type name %s in registry", cls.javaName)
}
return nil, cls, err
}
return s.typ, cls, nil
}
func (d *Decoder) decEnum(javaName string, flag int32) (JavaEnum, error) {
var (
err error
enumName string
ok bool
info structInfo
enumValue JavaEnum
)
enumName, err = d.decString(TAG_READ) // java enum class member is "name"
if err != nil {
return InvalidJavaEnum, perrors.Wrap(err, "decString for decJavaEnum")
}
info, ok = getStructInfo(javaName)
if !ok {
return InvalidJavaEnum, perrors.Errorf("getStructInfo(javaName:%s) = false", javaName)
}
enumValue = info.inst.(POJOEnum).EnumValue(enumName)
d.appendRefs(enumValue)
return enumValue, nil
}
// skip this object
func (d *Decoder) skip(cls classInfo) error {
if len(cls.fieldNameList) < 1 {
return nil
}
_, err := d.DecodeValue()
return err
}
func (d *Decoder) decObject(flag int32) (interface{}, error) {
var (
tag byte
idx int32
err error
typ reflect.Type
cls classInfo
)
if flag != TAG_READ {
tag = byte(flag)
} else {
tag, _ = d.readByte()
}
switch {
case tag == BC_NULL:
return nil, nil
case tag == BC_REF:
return d.decRef(int32(tag))
case tag == BC_OBJECT_DEF:
clsDef, err := d.decClassDef()
if err != nil {
return nil, perrors.Wrap(err, "decObject->decClassDef byte double")
}
cls, _ = clsDef.(classInfo)
//add to slice
d.appendClsDef(cls)
if c, ok := GetSerializer(cls.javaName); ok {
return c.DecObject(d)
}
return d.DecodeValue()
case tag == BC_OBJECT:
idx, err = d.decInt32(TAG_READ)
if err != nil {
return nil, err
}
typ, cls, err = d.getStructDefByIndex(int(idx))
if err != nil {
return nil, err
}
if typ == nil {
return nil, d.skip(cls)
}
if typ.Implements(javaEnumType) {
return d.decEnum(cls.javaName, TAG_READ)
}
return d.decInstance(typ, cls)
case BC_OBJECT_DIRECT <= tag && tag <= (BC_OBJECT_DIRECT+OBJECT_DIRECT_MAX):
typ, cls, err = d.getStructDefByIndex(int(tag - BC_OBJECT_DIRECT))
if err != nil {
return nil, err
}
if typ == nil {
return nil, d.skip(cls)
}
if typ.Implements(javaEnumType) {
return d.decEnum(cls.javaName, TAG_READ)
}
return d.decInstance(typ, cls)
default:
return nil, perrors.Errorf("decObject illegal object type tag:%+v", tag)
}
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化