/// <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)); }
/// <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; } }