Esempio n. 1
0
        /// <summary>
        /// Deserializes an object from the specified stream (expecting a YAML string).
        /// </summary>
        /// <param name="eventReader">A YAML event reader.</param>
        /// <param name="value">The value.</param>
        /// <param name="expectedType">The expected type.</param>
        /// <returns>An instance of the YAML data.</returns>
        public static object Deserialize(EventReader eventReader, object value, Type expectedType)
        {
            var serializer = GetYamlSerializer();

            return(serializer.Deserialize(eventReader, expectedType, value));
        }
Esempio n. 2
0
        /// <summary>
        /// Deserializes an object from the specified stream (expecting a YAML string).
        /// </summary>
        /// <param name="eventReader">A YAML event reader.</param>
        /// <param name="value">The value.</param>
        /// <param name="expectedType">The expected type.</param>
        /// <param name="contextSettings">The context settings.</param>
        /// <returns>An instance of the YAML data.</returns>
        public static object Deserialize(EventReader eventReader, object value, Type expectedType, SerializerContextSettings contextSettings)
        {
            var serializer = GetYamlSerializer();

            return(serializer.Deserialize(eventReader, expectedType, value, contextSettings));
        }
        public override object ReadYaml(ref ObjectContext objectContext)
        {
            // Check if we already have a memory parser
            var         previousReader = objectContext.SerializerContext.Reader;
            EventReader reader;

            if (!(previousReader.Parser is MemoryParser))
            {
                // Switch to a memory parser so that we can easily rollback in case of error
                // Read all events from this node
                var parsingEvents = new List <ParsingEvent>();
                previousReader.ReadCurrent(parsingEvents);

                objectContext.SerializerContext.Reader = reader = new EventReader(new MemoryParser(parsingEvents));
            }
            else
            {
                reader         = previousReader;
                previousReader = null;
            }

            // Get start position in case we need to recover
            var memoryParser  = (MemoryParser)reader.Parser;
            var startDepth    = reader.CurrentDepth;
            var startPosition = memoryParser.Position;

            // Allow errors to happen
            var previousAllowErrors = objectContext.SerializerContext.AllowErrors;

            objectContext.SerializerContext.AllowErrors = true;

            try
            {
                // Deserialize normally
                return(base.ReadYaml(ref objectContext));
            }
            catch (YamlException ex) // TODO: Filter only TagTypeSerializer TypeFromTag decoding errors? or more?
            {
                // Find the parsing range for this object
                // Skipping is also important to make sure the depth is properly updated
                reader.Skip(startDepth, startPosition == memoryParser.Position);
                var endPosition = memoryParser.Position;

                // TODO: Only type from user assemblies (and plugins?)
                var type = objectContext.Descriptor?.Type;
                if (type != null)
                {
                    // Dump the range of Yaml for this object
                    var parsingEvents = new List <ParsingEvent>();
                    for (int i = startPosition; i < endPosition; ++i)
                    {
                        parsingEvents.Add(memoryParser.ParsingEvents[i]);
                    }

                    // Get typename (if available) and temporarily erase it from the parsing events for partial deserialization of base type
                    string tag       = "Unknown";
                    var    firstNode = memoryParser.ParsingEvents[startPosition] as NodeEvent;
                    if (firstNode != null)
                    {
                        if (firstNode.Tag != null)
                        {
                            tag = firstNode.Tag;
                        }

                        // Temporarily recreate the node without its tag, so that we can try deserializing as many members as possible still
                        // TODO: Replace this with switch pattern matching (C# 7.0)
                        var mappingStart  = firstNode as MappingStart;
                        var sequenceStart = firstNode as SequenceStart;
                        var scalar        = firstNode as Scalar;
                        if (mappingStart != null)
                        {
                            memoryParser.ParsingEvents[startPosition] = new MappingStart(mappingStart.Anchor, null, mappingStart.IsImplicit, mappingStart.Style, mappingStart.Start, mappingStart.End);
                        }
                        else if (sequenceStart != null)
                        {
                            memoryParser.ParsingEvents[startPosition] = new SequenceStart(sequenceStart.Anchor, null, sequenceStart.IsImplicit, sequenceStart.Style, sequenceStart.Start, sequenceStart.End);
                        }
                        else if (scalar != null)
                        {
                            memoryParser.ParsingEvents[startPosition] = new Scalar(scalar.Anchor, null, scalar.Value, scalar.Style, scalar.IsPlainImplicit, scalar.IsQuotedImplicit, scalar.Start, scalar.End);
                        }
                        else
                        {
                            throw new NotImplementedException("Unknown node type");
                        }
                    }

                    string typeName     = null;
                    string assemblyName = null;
                    if (tag != null)
                    {
                        var tagAsType = tag.StartsWith("!") ? tag.Substring(1) : tag;
                        objectContext.SerializerContext.ParseType(tagAsType, out typeName, out assemblyName);
                    }

                    var unloadableObject = UnloadableObjectInstantiator.CreateUnloadableObject(type, typeName, assemblyName, ex.Message, parsingEvents);
                    objectContext.Instance   = unloadableObject;
                    objectContext.Descriptor = objectContext.SerializerContext.FindTypeDescriptor(unloadableObject.GetType());

                    // Restore parser position at beginning of object
                    memoryParser.Position = startPosition;
                    reader.RefreshParserState();

                    try
                    {
                        // Here, we try again to deserialize the object in the proxy
                        // Since we erase the tag, it shouldn't try to resolve the unknown type anymore (it will deserialize properties that exist in the base type)
                        unloadableObject = (IUnloadable)base.ReadYaml(ref objectContext);
                    }
                    catch (YamlException)
                    {
                        // Mute exceptions when trying to deserialize the proxy
                        // (in most case, we can do fine with incomplete objects)
                    }
                    finally
                    {
                        // Read until end of object (in case it failed again)
                        // Skipping is also important to make sure the depth is properly updated
                        reader.Skip(startDepth, startPosition == memoryParser.Position);
                        if (firstNode != null)
                        {
                            memoryParser.ParsingEvents[startPosition] = firstNode;
                        }
                    }

                    var log = objectContext.SerializerContext.Logger;
                    log?.Warning($"Could not deserialize object of type {tag}; replacing it with an object implementing {nameof(IUnloadable)}", ex);

                    return(unloadableObject);
                }
                throw;
            }
            finally
            {
                // Restore reader
                if (previousReader != null)
                {
                    objectContext.SerializerContext.Reader = previousReader;
                }

                // Restore states
                objectContext.SerializerContext.AllowErrors = previousAllowErrors;
            }
        }