object.go (402 lines of code) (raw):

/* * 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 ( "reflect" "strings" "sync" ) 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 interface{}) error { var ( i int idx int num int err error clsDef *ClassInfo ) pojo, isPojo := v.(POJO) // get none pojo JavaClassName var nonePojoJavaName string if !isPojo { s, ok := loadPOJORegistry(v) if !ok { return perrors.Errorf("non-pojo obj %s has not being registered before!", typeof(v)) } nonePojoJavaName = s.javaName } 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 isPojo && pojo.JavaClassName() == e.classInfoList[i].javaName || !isPojo && nonePojoJavaName == e.classInfoList[i].javaName { idx = i break } } var ok bool if idx == -1 { idx, ok = checkPOJORegistry(v) if !ok { if reflect.TypeOf(v).Implements(javaEnumType) { idx = RegisterJavaEnum(v.(POJOEnum)) } else if isPojo { idx = RegisterPOJO(pojo) } else { return perrors.Errorf("non-pojo obj %s has not being registered before!", typeof(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 } structs := []reflect.Value{vv} for len(structs) > 0 { vv := structs[0] vvt := vv.Type() num = vv.NumField() for i = 0; i < num; i++ { tf := vvt.Field(i) // skip unexported anonymous field if tf.PkgPath != "" { continue } // skip ignored field if tag, _ := tf.Tag.Lookup(tagIdentifier); tag == `-` { continue } field := vv.Field(i) if tf.Anonymous && field.Kind() == reflect.Struct { structs = append(structs, field) continue } 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()) } } structs = structs[1:] } return nil } // EncodeMapClass encode a map as object, which MUST contains a key _class and its value is the target class name. func (e *Encoder) EncodeMapClass(m map[string]interface{}) error { clsName, ok := m[ClassKey] if !ok { return perrors.New("no _class key map") } className, ok := clsName.(string) if !ok { return perrors.Errorf("expect string class name, but get %v", reflect.TypeOf(clsName)) } return e.EncodeMapAsClass(className, m) } // EncodeMapAsClass encode a map as object of given class name. func (e *Encoder) EncodeMapAsClass(className string, m map[string]interface{}) error { idx := e.classIndex(className) if idx == -1 { var clsDef *ClassInfo s, ok := getStructInfo(className) if ok { clsDef = pojoRegistry.classInfoList[s.index] } else { var err error clsDef, err = buildMapClassDef(className, m) if err != nil { return err } } idx = len(e.classInfoList) e.classInfoList = append(e.classInfoList, clsDef) e.buffer = append(e.buffer, clsDef.buffer...) } return e.encodeMapAsIndexedClass(idx, m) } // EncodeMapAsObject encode a map as the given class defined object. // Sometimes a class may not being registered in hessian, but it can be decoded from serialized data, // and the ClassInfo can be found in Decoder by calling Decoder.FindClassInfo. func (e *Encoder) EncodeMapAsObject(clsDef *ClassInfo, m map[string]interface{}) error { idx := e.classIndex(clsDef.javaName) if idx == -1 { idx = len(e.classInfoList) e.classInfoList = append(e.classInfoList, clsDef) if len(clsDef.buffer) == 0 { clsDef.initDefBuffer() } e.buffer = append(e.buffer, clsDef.buffer...) } return e.encodeMapAsIndexedClass(idx, m) } // encodeMapAsIndexedClass encode a map as the defined class at the given index in the encoder class list. func (e *Encoder) encodeMapAsIndexedClass(idx int, m map[string]interface{}) error { // 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)) } cls := e.classInfoList[idx] var err error for i := 0; i < len(cls.fieldNameList); i++ { fieldName := cls.fieldNameList[i] if err = e.Encode(m[fieldName]); err != nil { return perrors.Wrapf(err, "failed to encode field: %s, %+v", fieldName, m[fieldName]) } } 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 } type fieldInfo struct { indexes []int field *reflect.StructField } // map[rType][fieldName]indexes var fieldIndexCache sync.Map func findFieldWithCache(name string, typ reflect.Type) ([]int, *reflect.StructField, error) { typCache, _ := fieldIndexCache.Load(typ) if typCache == nil { typCache = &sync.Map{} fieldIndexCache.Store(typ, typCache) } iindexes, existCache := typCache.(*sync.Map).Load(name) if existCache && iindexes != nil { finfo := iindexes.(*fieldInfo) var err error if len(finfo.indexes) == 0 { err = perrors.Errorf("failed to find field %s", name) } return finfo.indexes, finfo.field, err } indexes, field, err := findField(name, typ) typCache.(*sync.Map).Store(name, &fieldInfo{indexes: indexes, field: field}) return indexes, field, err } // findField find structField in rType // // return // // indexes []int // field reflect.StructField // err error func findField(name string, typ reflect.Type) ([]int, *reflect.StructField, error) { for i := 0; i < typ.NumField(); i++ { // matching tag first, then lowerCamelCase, SameCase, lowerCase typField := typ.Field(i) tagVal, hasTag := typField.Tag.Lookup(tagIdentifier) fieldName := typField.Name if hasTag && tagVal == name || fieldName == name || lowerCamelCase(fieldName) == name || strings.ToLower(fieldName) == name { return []int{i}, &typField, nil } if typField.Anonymous && typField.Type.Kind() == reflect.Struct { next, field, _ := findField(name, typField.Type) if len(next) > 0 { indexes := []int{i} indexes = append(indexes, next...) return indexes, field, nil } } } return []int{}, nil, 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, fieldStruct, err := findFieldWithCache(fieldName, typ) if err != nil { d.DecodeValue() continue } // skip unexported anonymous field if fieldStruct.PkgPath != "" { continue } field := vv.FieldByIndex(index) if err = d.decToDest(field); err != nil { return nil, perrors.Wrapf(err, "decInstance->DecodeValue: %s", fieldName) } } // 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 { // exception if s, ok = checkAndGetException(cls); ok { return s.typ, cls, nil } if !d.isSkip && d.Strict { 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) (interface{}, 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) enumVal := PackPtr(reflect.ValueOf(enumValue).Convert(info.typ)).Interface() d.appendRefs(enumVal) return enumVal, nil } // skip this object func (d *Decoder) skip(cls *ClassInfo) error { fieldLen := len(cls.fieldNameList) if fieldLen < 1 { return nil } for i := 0; i < fieldLen; i++ { // skip class fields. if _, err := d.DecodeValue(); err != nil { return err } } return nil } 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, decErr := d.decClassDef() if decErr != nil { return nil, perrors.Wrap(decErr, "decObject->decClassDef byte double") } cls, _ = clsDef.(*ClassInfo) // add to slice d.appendClsDef(cls) 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 { if d.isSkip { return nil, d.skip(cls) } return d.decClassToMap(cls) } if typ.Implements(javaEnumType) { return d.decEnum(cls.javaName, TAG_READ) } if c, ok := GetSerializer(cls.javaName); ok { return c.DecObject(d, typ, cls) } 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 { if d.isSkip { return nil, d.skip(cls) } return d.decClassToMap(cls) } if typ.Implements(javaEnumType) { return d.decEnum(cls.javaName, TAG_READ) } if c, ok := GetSerializer(cls.javaName); ok { return c.DecObject(d, typ, cls) } return d.decInstance(typ, cls) default: return nil, perrors.Errorf("decObject illegal object type tag:%+v", tag) } } func (d *Decoder) decClassToMap(cls *ClassInfo) (interface{}, error) { vMap := make(map[string]interface{}, len(cls.fieldNameList)) vMap[ClassKey] = cls.javaName d.appendRefs(vMap) for i := 0; i < len(cls.fieldNameList); i++ { fieldName := cls.fieldNameList[i] fieldValue, decErr := d.DecodeValue() if decErr != nil { return nil, perrors.Wrapf(decErr, "decClassToMap -> decode field name:%s", fieldName) } vMap[fieldName] = EnsureRawAny(fieldValue) } return vMap, nil }