/// <summary> /// Constructor. /// </summary> /// <param name="type">Type.</param> /// <param name="typeId">Type ID.</param> /// <param name="typeName">Type name.</param> /// <param name="userType">User type flag.</param> /// <param name="nameMapper">Name converter.</param> /// <param name="idMapper">Mapper.</param> /// <param name="serializer">Serializer.</param> /// <param name="keepDeserialized">Whether to cache deserialized value in IBinaryObject</param> /// <param name="affKeyFieldName">Affinity field key name.</param> /// <param name="isEnum">Enum flag.</param> /// <param name="isRegistered">Registered flag.</param> public BinaryFullTypeDescriptor( Type type, int typeId, string typeName, bool userType, IBinaryNameMapper nameMapper, IBinaryIdMapper idMapper, IBinarySerializerInternal serializer, bool keepDeserialized, string affKeyFieldName, bool isEnum, bool isRegistered = true) { _type = type; _typeId = typeId; _typeName = typeName; _userType = userType; _nameMapper = nameMapper; _idMapper = idMapper; _serializer = serializer; _keepDeserialized = keepDeserialized; _affKeyFieldName = affKeyFieldName; _isEnum = isEnum; _isRegistered = isRegistered; _schema = new BinaryObjectSchema(); }
/// <summary> /// Constructor. /// </summary> /// <param name="type">Type.</param> /// <param name="typeId">Type ID.</param> /// <param name="typeName">Type name.</param> /// <param name="userType">User type flag.</param> /// <param name="nameMapper">Name converter.</param> /// <param name="idMapper">Mapper.</param> /// <param name="serializer">Serializer.</param> /// <param name="keepDeserialized">Whether to cache deserialized value in IBinaryObject</param> /// <param name="affKeyFieldName">Affinity field key name.</param> /// <param name="isEnum">Enum flag.</param> /// <param name="comparer">Equality comparer.</param> public BinaryFullTypeDescriptor( Type type, int typeId, string typeName, bool userType, IBinaryNameMapper nameMapper, IBinaryIdMapper idMapper, IBinarySerializerInternal serializer, bool keepDeserialized, string affKeyFieldName, bool isEnum, IEqualityComparer <IBinaryObject> comparer) { _type = type; _typeId = typeId; _typeName = typeName; _userType = userType; _nameMapper = nameMapper; _idMapper = idMapper; _serializer = serializer; _keepDeserialized = keepDeserialized; _affKeyFieldName = affKeyFieldName; _isEnum = isEnum; _equalityComparer = comparer as IBinaryEqualityComparer; if (comparer != null && _equalityComparer == null) { throw new IgniteException(string.Format("Unsupported IEqualityComparer<IBinaryObject> " + "implementation: {0}. Only predefined implementations " + "are supported.", comparer.GetType())); } }
/// <summary> /// Gets the serializer. /// </summary> private static IBinarySerializerInternal GetSerializer(BinaryConfiguration cfg, BinaryTypeConfiguration typeCfg, Type type, int typeId, IBinaryNameMapper nameMapper, IBinaryIdMapper idMapper, ILogger log) { var serializer = (typeCfg != null ? typeCfg.Serializer : null) ?? (cfg != null ? cfg.Serializer : null); if (serializer == null) { if (type.GetInterfaces().Contains(typeof(IBinarizable))) { return(BinarizableSerializer.Instance); } if (type.GetInterfaces().Contains(typeof(ISerializable))) { LogSerializableWarning(type, log); return(new SerializableSerializer(type)); } serializer = new BinaryReflectiveSerializer { ForceTimestamp = cfg != null && cfg.ForceTimestamp }; } var refSerializer = serializer as BinaryReflectiveSerializer; return(refSerializer != null ? refSerializer.Register(type, typeId, nameMapper, idMapper) : new UserSerializerProxy(serializer)); }
/// <summary> /// Registers the specified type. /// </summary> internal IBinarySerializerInternal Register(Type type, int typeId, IBinaryNameMapper converter, IBinaryIdMapper idMapper) { _isInUse = true; return(new BinaryReflectiveSerializerInternal(_rawMode).Register(type, typeId, converter, idMapper)); }
/// <summary> /// Resolve type ID. /// </summary> /// <param name="typeName">Type name.</param> /// <param name="idMapper">ID mapper.</param> private static int GetTypeId(string typeName, IBinaryIdMapper idMapper) { Debug.Assert(typeName != null); int id = 0; if (idMapper != null) { try { id = idMapper.GetTypeId(typeName); } catch (Exception e) { throw new BinaryObjectException("Failed to resolve type ID due to ID mapper exception " + "[typeName=" + typeName + ", idMapper=" + idMapper + ']', e); } } if (id == 0) { id = BinaryUtils.GetStringHashCodeLowerCase(typeName); } return(id); }
/// <summary>Register type.</summary> /// <param name="type">Type.</param> /// <param name="typeId">Type ID.</param> /// <param name="converter">Name converter.</param> /// <param name="idMapper">ID mapper.</param> internal BinaryReflectiveSerializerInternal Register(Type type, int typeId, IBinaryNameMapper converter, IBinaryIdMapper idMapper) { Debug.Assert(_wActions == null && _rActions == null); List <FieldInfo> fields = new List <FieldInfo>(); Type curType = type; while (curType != null) { foreach (FieldInfo field in curType.GetFields(Flags)) { if (!field.IsNotSerialized) { fields.Add(field); } } curType = curType.BaseType; } IDictionary <int, string> idMap = new Dictionary <int, string>(); foreach (FieldInfo field in fields) { string fieldName = BinaryUtils.CleanFieldName(field.Name); int fieldId = BinaryUtils.FieldId(typeId, fieldName, converter, idMapper); if (idMap.ContainsKey(fieldId)) { throw new BinaryObjectException("Conflicting field IDs [type=" + type.Name + ", field1=" + idMap[fieldId] + ", field2=" + fieldName + ", fieldId=" + fieldId + ']'); } idMap[fieldId] = fieldName; } fields.Sort(Compare); var wActions = new BinaryReflectiveWriteAction[fields.Count]; var rActions = new BinaryReflectiveReadAction[fields.Count]; for (int i = 0; i < fields.Count; i++) { BinaryReflectiveWriteAction writeAction; BinaryReflectiveReadAction readAction; BinaryReflectiveActions.GetTypeActions(fields[i], out writeAction, out readAction, _rawMode); wActions[i] = writeAction; rActions[i] = readAction; } return(new BinaryReflectiveSerializerInternal(wActions, rActions, _rawMode)); }
/// <summary> /// Add user type. /// </summary> /// <param name="cfg">Configuration.</param> /// <param name="typeCfg">Type configuration.</param> /// <param name="typeResolver">The type resolver.</param> /// <param name="dfltSerializer">The default serializer.</param> private void AddUserType(BinaryConfiguration cfg, BinaryTypeConfiguration typeCfg, TypeResolver typeResolver, IBinarySerializer dfltSerializer) { // Get converter/mapper/serializer. IBinaryNameMapper nameMapper = typeCfg.NameMapper ?? cfg.DefaultNameMapper; IBinaryIdMapper idMapper = typeCfg.IdMapper ?? cfg.DefaultIdMapper; bool keepDeserialized = typeCfg.KeepDeserialized ?? cfg.DefaultKeepDeserialized; // Try resolving type. Type type = typeResolver.ResolveType(typeCfg.TypeName); if (type != null) { // Type is found. var typeName = BinaryUtils.GetTypeName(type); int typeId = BinaryUtils.TypeId(typeName, nameMapper, idMapper); var serializer = typeCfg.Serializer ?? cfg.DefaultSerializer ?? GetBinarizableSerializer(type) ?? dfltSerializer; var refSerializer = serializer as BinaryReflectiveSerializer; if (refSerializer != null) { refSerializer.Register(type, typeId, nameMapper, idMapper); } if (typeCfg.IsEnum != type.IsEnum) { throw new BinaryObjectException( string.Format( "Invalid IsEnum flag in binary type configuration. " + "Configuration value: IsEnum={0}, actual type: IsEnum={1}", typeCfg.IsEnum, type.IsEnum)); } var affKeyFld = typeCfg.AffinityKeyFieldName ?? GetAffinityKeyFieldNameFromAttribute(type); AddType(type, typeId, typeName, true, keepDeserialized, nameMapper, idMapper, serializer, affKeyFld, type.IsEnum); } else { // Type is not found. string typeName = BinaryUtils.SimpleTypeName(typeCfg.TypeName); int typeId = BinaryUtils.TypeId(typeName, nameMapper, idMapper); AddType(null, typeId, typeName, true, keepDeserialized, nameMapper, idMapper, null, typeCfg.AffinityKeyFieldName, typeCfg.IsEnum); } }
/// <summary> /// Register type. /// </summary> /// <param name="type">Type.</param> /// <param name="typeId">Type ID.</param> /// <param name="converter">Name converter.</param> /// <param name="idMapper">ID mapper.</param> /// <param name="forceTimestamp">Force timestamp serialization for DateTime fields..</param> /// <returns>Resulting serializer.</returns> internal BinaryReflectiveSerializerInternal Register(Type type, int typeId, IBinaryNameMapper converter, IBinaryIdMapper idMapper, bool forceTimestamp) { Debug.Assert(_wActions == null && _rActions == null); var fields = ReflectionUtils.GetAllFields(type).Where(x => !x.IsNotSerialized).ToList(); IDictionary <int, string> idMap = new Dictionary <int, string>(); foreach (FieldInfo field in fields) { string fieldName = BinaryUtils.CleanFieldName(field.Name); int fieldId = BinaryUtils.FieldId(typeId, fieldName, converter, idMapper); if (idMap.ContainsKey(fieldId)) { if (fieldName == idMap[fieldId]) { string baseClassName = field.DeclaringType != null ? field.DeclaringType.Name : null; throw new BinaryObjectException(string.Format( "{0} derives from {1} and hides field {2} from the base class. " + "Ignite can not serialize two fields with the same name.", type.Name, baseClassName, fieldName)); } throw new BinaryObjectException(string.Format( "Conflicting field IDs [type={0}, field1={1}, field2={2}, fieldId={3}])", type.Name, idMap[fieldId], fieldName, fieldId)); } idMap[fieldId] = fieldName; } fields.Sort(Compare); var wActions = new BinaryReflectiveWriteAction[fields.Count]; var rActions = new BinaryReflectiveReadAction[fields.Count]; for (int i = 0; i < fields.Count; i++) { BinaryReflectiveWriteAction writeAction; BinaryReflectiveReadAction readAction; BinaryReflectiveActions.GetTypeActions(fields[i], out writeAction, out readAction, _rawMode, forceTimestamp); wActions[i] = writeAction; rActions[i] = readAction; } var serDesc = SerializableTypeDescriptor.Get(type); return(new BinaryReflectiveSerializerInternal(wActions, rActions, _rawMode, serDesc)); }
/// <summary>Register type.</summary> /// <param name="type">Type.</param> /// <param name="typeId">Type ID.</param> /// <param name="converter">Name converter.</param> /// <param name="idMapper">ID mapper.</param> public void Register(Type type, int typeId, IBinaryNameMapper converter, IBinaryIdMapper idMapper) { if (type.GetInterface(typeof(IBinarizable).Name) != null) { return; } List <FieldInfo> fields = new List <FieldInfo>(); Type curType = type; while (curType != null) { foreach (FieldInfo field in curType.GetFields(Flags)) { if (!field.IsNotSerialized) { fields.Add(field); } } curType = curType.BaseType; } IDictionary <int, string> idMap = new Dictionary <int, string>(); foreach (FieldInfo field in fields) { string fieldName = BinaryUtils.CleanFieldName(field.Name); int fieldId = BinaryUtils.FieldId(typeId, fieldName, converter, idMapper); if (idMap.ContainsKey(fieldId)) { throw new BinaryObjectException("Conflicting field IDs [type=" + type.Name + ", field1=" + idMap[fieldId] + ", field2=" + fieldName + ", fieldId=" + fieldId + ']'); } idMap[fieldId] = fieldName; } fields.Sort(Compare); Descriptor desc = new Descriptor(fields); _types[type] = desc; }
/// <summary> /// Add user type. /// </summary> /// <param name="typeCfg">Type configuration.</param> /// <param name="typeResolver">The type resolver.</param> /// <exception cref="BinaryObjectException"></exception> private BinaryFullTypeDescriptor AddUserType(BinaryTypeConfiguration typeCfg, TypeResolver typeResolver) { // Get converter/mapper/serializer. IBinaryNameMapper nameMapper = typeCfg.NameMapper ?? _cfg.NameMapper ?? GetDefaultNameMapper(); IBinaryIdMapper idMapper = typeCfg.IdMapper ?? _cfg.IdMapper; bool keepDeserialized = typeCfg.KeepDeserialized ?? _cfg.KeepDeserialized; // Try resolving type. Type type = typeResolver.ResolveType(typeCfg.TypeName); if (type != null) { ValidateUserType(type); if (typeCfg.IsEnum != BinaryUtils.IsIgniteEnum(type)) { throw new BinaryObjectException( string.Format( "Invalid IsEnum flag in binary type configuration. " + "Configuration value: IsEnum={0}, actual type: IsEnum={1}, type={2}", typeCfg.IsEnum, type.IsEnum, type)); } // Type is found. var typeName = GetTypeName(type, nameMapper); int typeId = GetTypeId(typeName, idMapper); var affKeyFld = typeCfg.AffinityKeyFieldName ?? AffinityKeyMappedAttribute.GetFieldNameFromAttribute(type); var serializer = GetSerializer(_cfg, typeCfg, type, typeId, nameMapper, idMapper, _log); return(AddType(type, typeId, typeName, true, keepDeserialized, nameMapper, idMapper, serializer, affKeyFld, BinaryUtils.IsIgniteEnum(type))); } else { // Type is not found. string typeName = GetTypeName(typeCfg.TypeName, nameMapper); int typeId = GetTypeId(typeName, idMapper); return(AddType(null, typeId, typeName, true, keepDeserialized, nameMapper, idMapper, null, typeCfg.AffinityKeyFieldName, typeCfg.IsEnum)); } }
/// <summary>Register type.</summary> /// <param name="type">Type.</param> /// <param name="typeId">Type ID.</param> /// <param name="converter">Name converter.</param> /// <param name="idMapper">ID mapper.</param> public void Register(Type type, int typeId, IBinaryNameMapper converter, IBinaryIdMapper idMapper) { if (type.GetInterface(typeof(IBinarizable).Name) != null) return; List<FieldInfo> fields = new List<FieldInfo>(); Type curType = type; while (curType != null) { foreach (FieldInfo field in curType.GetFields(Flags)) { if (!field.IsNotSerialized) fields.Add(field); } curType = curType.BaseType; } IDictionary<int, string> idMap = new Dictionary<int, string>(); foreach (FieldInfo field in fields) { string fieldName = BinaryUtils.CleanFieldName(field.Name); int fieldId = BinaryUtils.FieldId(typeId, fieldName, converter, idMapper); if (idMap.ContainsKey(fieldId)) { throw new BinaryObjectException("Conflicting field IDs [type=" + type.Name + ", field1=" + idMap[fieldId] + ", field2=" + fieldName + ", fieldId=" + fieldId + ']'); } idMap[fieldId] = fieldName; } fields.Sort(Compare); Descriptor desc = new Descriptor(fields); _types[type] = desc; }
/// <summary> /// Register type. /// </summary> /// <param name="type">Type.</param> /// <param name="typeId">Type ID.</param> /// <param name="converter">Name converter.</param> /// <param name="idMapper">ID mapper.</param> /// <param name="forceTimestamp">Force timestamp serialization for DateTime fields..</param> /// <returns>Resulting serializer.</returns> internal BinaryReflectiveSerializerInternal Register(Type type, int typeId, IBinaryNameMapper converter, IBinaryIdMapper idMapper, bool forceTimestamp) { Debug.Assert(_wActions == null && _rActions == null); var fields = ReflectionUtils.GetAllFields(type).Where(x => !x.IsNotSerialized).ToList(); IDictionary <int, string> idMap = new Dictionary <int, string>(); foreach (FieldInfo field in fields) { string fieldName = BinaryUtils.CleanFieldName(field.Name); int fieldId = BinaryUtils.FieldId(typeId, fieldName, converter, idMapper); if (idMap.ContainsKey(fieldId)) { throw new BinaryObjectException("Conflicting field IDs [type=" + type.Name + ", field1=" + idMap[fieldId] + ", field2=" + fieldName + ", fieldId=" + fieldId + ']'); } idMap[fieldId] = fieldName; } fields.Sort(Compare); var wActions = new BinaryReflectiveWriteAction[fields.Count]; var rActions = new BinaryReflectiveReadAction[fields.Count]; for (int i = 0; i < fields.Count; i++) { BinaryReflectiveWriteAction writeAction; BinaryReflectiveReadAction readAction; BinaryReflectiveActions.GetTypeActions(fields[i], out writeAction, out readAction, _rawMode, forceTimestamp); wActions[i] = writeAction; rActions[i] = readAction; } var serDesc = SerializableTypeDescriptor.Get(type); return(new BinaryReflectiveSerializerInternal(wActions, rActions, _rawMode, serDesc)); }
/// <summary> /// Add user type. /// </summary> /// <param name="cfg">Configuration.</param> /// <param name="typeCfg">Type configuration.</param> /// <param name="typeResolver">The type resolver.</param> /// <param name="dfltSerializer">The default serializer.</param> private void AddUserType(BinaryConfiguration cfg, BinaryTypeConfiguration typeCfg, TypeResolver typeResolver, IBinarySerializer dfltSerializer) { // Get converter/mapper/serializer. IBinaryNameMapper nameMapper = typeCfg.NameMapper ?? cfg.DefaultNameMapper; IBinaryIdMapper idMapper = typeCfg.IdMapper ?? cfg.DefaultIdMapper; bool keepDeserialized = typeCfg.KeepDeserialized ?? cfg.DefaultKeepDeserialized; // Try resolving type. Type type = typeResolver.ResolveType(typeCfg.TypeName); if (type != null) { // Type is found. var typeName = GetTypeName(type); int typeId = BinaryUtils.TypeId(typeName, nameMapper, idMapper); var serializer = typeCfg.Serializer ?? cfg.DefaultSerializer ?? GetBinarizableSerializer(type) ?? dfltSerializer; var refSerializer = serializer as BinaryReflectiveSerializer; if (refSerializer != null) { refSerializer.Register(type, typeId, nameMapper, idMapper); } AddType(type, typeId, typeName, true, keepDeserialized, nameMapper, idMapper, serializer, typeCfg.AffinityKeyFieldName); } else { // Type is not found. string typeName = BinaryUtils.SimpleTypeName(typeCfg.TypeName); int typeId = BinaryUtils.TypeId(typeName, nameMapper, idMapper); AddType(null, typeId, typeName, true, keepDeserialized, nameMapper, idMapper, null, typeCfg.AffinityKeyFieldName); } }
/// <summary> /// Initializes a new instance of the <see cref="BinaryFullTypeDescriptor"/> class, /// copying values from specified descriptor. /// </summary> /// <param name="desc">The descriptor to copy from.</param> /// <param name="type">Type.</param> /// <param name="serializer">Serializer.</param> /// <param name="isRegistered">Registered flag.</param> public BinaryFullTypeDescriptor(BinaryFullTypeDescriptor desc, Type type, IBinarySerializerInternal serializer, bool isRegistered) { _type = type; _typeId = desc._typeId; _typeName = desc._typeName; _userType = desc._userType; _nameMapper = desc._nameMapper; _idMapper = desc._idMapper; _serializer = serializer; _keepDeserialized = desc._keepDeserialized; _affKeyFieldName = desc._affKeyFieldName; _isEnum = desc._isEnum; _isRegistered = isRegistered; _schema = desc._schema; _writerTypeStruct = desc._writerTypeStruct; _readerTypeStructure = desc._readerTypeStructure; }
/// <summary> /// Add type. /// </summary> /// <param name="type">Type.</param> /// <param name="typeId">Type ID.</param> /// <param name="typeName">Type name.</param> /// <param name="userType">User type flag.</param> /// <param name="keepDeserialized">Whether to cache deserialized value in IBinaryObject</param> /// <param name="nameMapper">Name mapper.</param> /// <param name="idMapper">ID mapper.</param> /// <param name="serializer">Serializer.</param> /// <param name="affKeyFieldName">Affinity key field name.</param> /// <param name="isEnum">Enum flag.</param> /// <param name="comparer">Comparer.</param> private void AddType(Type type, int typeId, string typeName, bool userType, bool keepDeserialized, IBinaryNameMapper nameMapper, IBinaryIdMapper idMapper, IBinarySerializerInternal serializer, string affKeyFieldName, bool isEnum, IEqualityComparer <IBinaryObject> comparer) { long typeKey = BinaryUtils.TypeKey(userType, typeId); IBinaryTypeDescriptor conflictingType; if (_idToDesc.TryGetValue(typeKey, out conflictingType)) { var type1 = conflictingType.Type != null ? conflictingType.Type.AssemblyQualifiedName : conflictingType.TypeName; var type2 = type != null ? type.AssemblyQualifiedName : typeName; throw new BinaryObjectException(string.Format("Conflicting type IDs [type1='{0}', " + "type2='{1}', typeId={2}]", type1, type2, typeId)); } if (userType && _typeNameToDesc.ContainsKey(typeName)) { throw new BinaryObjectException("Conflicting type name: " + typeName); } var descriptor = new BinaryFullTypeDescriptor(type, typeId, typeName, userType, nameMapper, idMapper, serializer, keepDeserialized, affKeyFieldName, isEnum, comparer); if (type != null) { _typeToDesc[type] = descriptor; } if (userType) { _typeNameToDesc[typeName] = descriptor; } _idToDesc.GetOrAdd(typeKey, _ => descriptor); }
/// <summary> /// Constructor. /// </summary> /// <param name="type">Type.</param> /// <param name="typeId">Type ID.</param> /// <param name="typeName">Type name.</param> /// <param name="userType">User type flag.</param> /// <param name="nameMapper">Name converter.</param> /// <param name="idMapper">Mapper.</param> /// <param name="serializer">Serializer.</param> /// <param name="keepDeserialized">Whether to cache deserialized value in IBinaryObject</param> /// <param name="affKeyFieldName">Affinity field key name.</param> public BinaryFullTypeDescriptor( Type type, int typeId, string typeName, bool userType, IBinaryNameMapper nameMapper, IBinaryIdMapper idMapper, IBinarySerializer serializer, bool keepDeserialized, string affKeyFieldName) { _type = type; _typeId = typeId; _typeName = typeName; _userType = userType; _nameMapper = nameMapper; _idMapper = idMapper; _serializer = serializer; _keepDeserialized = keepDeserialized; _affKeyFieldName = affKeyFieldName; }
/// <summary> /// Add type. /// </summary> /// <param name="type">Type.</param> /// <param name="typeId">Type ID.</param> /// <param name="typeName">Type name.</param> /// <param name="userType">User type flag.</param> /// <param name="keepDeserialized">Whether to cache deserialized value in IBinaryObject</param> /// <param name="nameMapper">Name mapper.</param> /// <param name="idMapper">ID mapper.</param> /// <param name="serializer">Serializer.</param> /// <param name="affKeyFieldName">Affinity key field name.</param> /// <param name="isEnum">Enum flag.</param> private void AddType(Type type, int typeId, string typeName, bool userType, bool keepDeserialized, IBinaryNameMapper nameMapper, IBinaryIdMapper idMapper, IBinarySerializerInternal serializer, string affKeyFieldName, bool isEnum) { long typeKey = BinaryUtils.TypeKey(userType, typeId); BinaryFullTypeDescriptor conflictingType; if (_idToDesc.TryGetValue(typeKey, out conflictingType)) { var type1 = conflictingType.Type != null ? conflictingType.Type.AssemblyQualifiedName : conflictingType.TypeName; var type2 = type != null ? type.AssemblyQualifiedName : typeName; ThrowConflictingTypeError(type1, type2, typeId); } if (userType && _typeNameToDesc.ContainsKey(typeName)) { throw new BinaryObjectException("Conflicting type name: " + typeName); } var descriptor = new BinaryFullTypeDescriptor(type, typeId, typeName, userType, nameMapper, idMapper, serializer, keepDeserialized, affKeyFieldName, isEnum); if (type != null) { _typeToDesc.GetOrAdd(type, x => descriptor); } if (userType) { _typeNameToDesc.GetOrAdd(typeName, x => descriptor); } _idToDesc.GetOrAdd(typeKey, _ => descriptor); }
/// <summary> /// Write object. /// </summary> /// <param name="obj">Object.</param> public void Write <T>(T obj) { // Handle special case for null. if (obj == null) { _stream.WriteByte(BinaryUtils.HdrNull); return; } // We use GetType() of a real object instead of typeof(T) to take advantage of // automatic Nullable'1 unwrapping. Type type = obj.GetType(); // Handle common case when primitive is written. if (type.IsPrimitive) { WritePrimitive(obj, type); return; } // Handle special case for builder. if (WriteBuilderSpecials(obj)) { return; } // Suppose that we faced normal object and perform descriptor lookup. IBinaryTypeDescriptor desc = type.IsEnum ? null : _marsh.GetDescriptor(type); if (desc != null) { // Writing normal object. var pos = _stream.Position; // Dealing with handles. if (!(desc.Serializer is IBinarySystemTypeSerializer) && WriteHandle(pos, obj)) { return; } // Skip header length as not everything is known now _stream.Seek(BinaryObjectHeader.Size, SeekOrigin.Current); // Preserve old frame. int oldTypeId = _curTypeId; IBinaryNameMapper oldConverter = _curConverter; IBinaryIdMapper oldMapper = _curMapper; int oldRawPos = _curRawPos; var oldPos = _curPos; var oldStruct = _curStruct; // Push new frame. _curTypeId = desc.TypeId; _curConverter = desc.NameMapper; _curMapper = desc.IdMapper; _curRawPos = 0; _curPos = pos; _curStruct = new BinaryStructureTracker(desc, desc.WriterTypeStructure); var schemaIdx = _schema.PushSchema(); try { // Write object fields. desc.Serializer.WriteBinary(obj, this); // Write schema var schemaOffset = _stream.Position - pos; int schemaId; var flags = desc.UserType ? BinaryObjectHeader.Flag.UserType : BinaryObjectHeader.Flag.None; var hasSchema = _schema.WriteSchema(_stream, schemaIdx, out schemaId, ref flags); if (hasSchema) { flags |= BinaryObjectHeader.Flag.HasSchema; // Calculate and write header. if (_curRawPos > 0) { _stream.WriteInt(_curRawPos - pos); // raw offset is in the last 4 bytes } } else { schemaOffset = BinaryObjectHeader.Size; } if (_curRawPos > 0) { flags |= BinaryObjectHeader.Flag.HasRaw; } var len = _stream.Position - pos; var header = new BinaryObjectHeader(desc.TypeId, obj.GetHashCode(), len, schemaId, schemaOffset, flags); BinaryObjectHeader.Write(header, _stream, pos); Stream.Seek(pos + len, SeekOrigin.Begin); // Seek to the end } finally { _schema.PopSchema(schemaIdx); } // Apply structure updates if any. _curStruct.UpdateWriterStructure(this); // Restore old frame. _curTypeId = oldTypeId; _curConverter = oldConverter; _curMapper = oldMapper; _curRawPos = oldRawPos; _curPos = oldPos; _curStruct = oldStruct; } else { // Are we dealing with a well-known type? var handler = BinarySystemHandlers.GetWriteHandler(type); if (handler == null) // We did our best, object cannot be marshalled. { throw new BinaryObjectException("Unsupported object type [type=" + type + ", object=" + obj + ']'); } handler(this, obj); } }
/// <summary> /// Add type. /// </summary> /// <param name="type">Type.</param> /// <param name="typeId">Type ID.</param> /// <param name="typeName">Type name.</param> /// <param name="userType">User type flag.</param> /// <param name="keepDeserialized">Whether to cache deserialized value in IBinaryObject</param> /// <param name="nameMapper">Name mapper.</param> /// <param name="idMapper">ID mapper.</param> /// <param name="serializer">Serializer.</param> /// <param name="affKeyFieldName">Affinity key field name.</param> /// <param name="isEnum">Enum flag.</param> private BinaryFullTypeDescriptor AddType(Type type, int typeId, string typeName, bool userType, bool keepDeserialized, IBinaryNameMapper nameMapper, IBinaryIdMapper idMapper, IBinarySerializerInternal serializer, string affKeyFieldName, bool isEnum) { Debug.Assert(!string.IsNullOrEmpty(typeName)); long typeKey = BinaryUtils.TypeKey(userType, typeId); BinaryFullTypeDescriptor conflictingType; if (_idToDesc.TryGetValue(typeKey, out conflictingType) && conflictingType.TypeName != typeName) { ThrowConflictingTypeError(typeName, conflictingType.TypeName, typeId); } var descriptor = new BinaryFullTypeDescriptor(type, typeId, typeName, userType, nameMapper, idMapper, serializer, keepDeserialized, affKeyFieldName, isEnum); if (RegistrationDisabled) { return(descriptor); } if (type != null) { _typeToDesc.Set(type, descriptor); } if (userType) { _typeNameToDesc.Set(typeName, descriptor); } _idToDesc.Set(typeKey, descriptor); return(descriptor); }
/// <summary> /// Gets the serializer. /// </summary> private static IBinarySerializerInternal GetSerializer(BinaryConfiguration cfg, BinaryTypeConfiguration typeCfg, Type type, int typeId, IBinaryNameMapper nameMapper, IBinaryIdMapper idMapper) { var serializer = typeCfg.Serializer ?? cfg.DefaultSerializer; if (serializer == null) { if (type.GetInterfaces().Contains(typeof(IBinarizable))) { return(BinarizableSerializer.Instance); } serializer = new BinaryReflectiveSerializer(); } var refSerializer = serializer as BinaryReflectiveSerializer; return(refSerializer != null ? refSerializer.Register(type, typeId, nameMapper, idMapper) : new UserSerializerProxy(serializer)); }