From ddad0ebbe3bd5937ea19740077f5e80c45a82f22 Mon Sep 17 00:00:00 2001 From: Antoine Aubry Date: Fri, 26 Jan 2018 17:19:50 +0000 Subject: [PATCH] Add support for (de)serialization of System.Type --- .../Serialization/SerializationTests.cs | 54 ++++++++++++++----- YamlDotNet/Serialization/BuilderSkeleton.cs | 3 +- .../Serialization/Converters/GuidConverter.cs | 18 ++++--- .../Converters/SystemTypeConverter.cs | 33 ++++++++++++ YamlDotNet/Serialization/Deserializer.cs | 1 + YamlDotNet/Serialization/Serializer.cs | 1 + 6 files changed, 88 insertions(+), 22 deletions(-) create mode 100644 YamlDotNet/Serialization/Converters/SystemTypeConverter.cs diff --git a/YamlDotNet.Test/Serialization/SerializationTests.cs b/YamlDotNet.Test/Serialization/SerializationTests.cs index db9b1a5dc..916c97e63 100644 --- a/YamlDotNet.Test/Serialization/SerializationTests.cs +++ b/YamlDotNet.Test/Serialization/SerializationTests.cs @@ -1488,21 +1488,21 @@ static Exception GetExceptionWithStackTrace() public void RegisteringATypeConverterPreventsTheTypeFromBeingVisited() { var serializer = new SerializerBuilder() - .WithTypeConverter(new SystemTypeTypeConverter()) + .WithTypeConverter(new NonSerializableTypeConverter()) .Build(); - var yaml = serializer.Serialize(new TypeContainer + var yaml = serializer.Serialize(new NonSerializableContainer { - Type = typeof(string), + Value = new NonSerializable { Text = "hello" }, }); var deserializer = new DeserializerBuilder() - .WithTypeConverter(new SystemTypeTypeConverter()) + .WithTypeConverter(new NonSerializableTypeConverter()) .Build(); - var result = deserializer.Deserialize(yaml); + var result = deserializer.Deserialize(yaml); - Assert.Equal(typeof(string), result.Type); + Assert.Equal("hello", result.Value.Text); } [Fact] @@ -1531,34 +1531,62 @@ public void NamingConventionIsNotAppliedByDeserializerWhenApplyNamingConventions Assert.Equal("value", parsed.NoConvention); } + [Fact] + public void TypesAreSerializable() + { + var sut = new SerializerBuilder() + .Build(); + + var yaml = sut.Serialize(typeof(string)); + + Assert.Contains(typeof(string).AssemblyQualifiedName, yaml); + } + + [Fact] + public void TypesAreDeserializable() + { + var sut = new DeserializerBuilder() + .Build(); + + var type = sut.Deserialize(typeof(string).AssemblyQualifiedName); + + Assert.Equal(typeof(string), type); + } + public class NamingConventionDisabled { [YamlMember(ApplyNamingConventions = false)] public string NoConvention { get; set; } } - public class TypeContainer + public class NonSerializableContainer { - public Type Type { get; set; } + public NonSerializable Value { get; set; } + } + + public class NonSerializable + { + public string WillThrow { get { throw new Exception(); } } + + public string Text { get; set; } } - public class SystemTypeTypeConverter : IYamlTypeConverter + public class NonSerializableTypeConverter : IYamlTypeConverter { public bool Accepts(Type type) { - return typeof(Type).IsAssignableFrom(type); + return typeof(NonSerializable).IsAssignableFrom(type); } public object ReadYaml(IParser parser, Type type) { var scalar = parser.Expect(); - return Type.GetType(scalar.Value); + return new NonSerializable { Text = scalar.Value }; } public void WriteYaml(IEmitter emitter, object value, Type type) { - var typeName = ((Type)value).AssemblyQualifiedName; - emitter.Emit(new Scalar(typeName)); + emitter.Emit(new Scalar(((NonSerializable)value).Text)); } } } diff --git a/YamlDotNet/Serialization/BuilderSkeleton.cs b/YamlDotNet/Serialization/BuilderSkeleton.cs index e9c643374..ab9849532 100644 --- a/YamlDotNet/Serialization/BuilderSkeleton.cs +++ b/YamlDotNet/Serialization/BuilderSkeleton.cs @@ -21,9 +21,9 @@ using System; using System.Collections.Generic; +using System.Linq.Expressions; using YamlDotNet.Serialization.Converters; using YamlDotNet.Serialization.TypeInspectors; -using System.Linq.Expressions; namespace YamlDotNet.Serialization { @@ -45,6 +45,7 @@ internal BuilderSkeleton() typeConverterFactories = new LazyComponentRegistrationList(); typeConverterFactories.Add(typeof(GuidConverter), _ => new GuidConverter(false)); + typeConverterFactories.Add(typeof(SystemTypeConverter), _ => new SystemTypeConverter()); typeInspectorFactories = new LazyComponentRegistrationList(); } diff --git a/YamlDotNet/Serialization/Converters/GuidConverter.cs b/YamlDotNet/Serialization/Converters/GuidConverter.cs index 75c9c71e4..eeb84947d 100644 --- a/YamlDotNet/Serialization/Converters/GuidConverter.cs +++ b/YamlDotNet/Serialization/Converters/GuidConverter.cs @@ -19,7 +19,9 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +using System; using YamlDotNet.Core; +using YamlDotNet.Core.Events; namespace YamlDotNet.Serialization.Converters { @@ -35,22 +37,22 @@ public GuidConverter(bool jsonCompatible) this.jsonCompatible = jsonCompatible; } - public bool Accepts(System.Type type) + public bool Accepts(Type type) { - return type == typeof(System.Guid); + return type == typeof(Guid); } - public object ReadYaml(Core.IParser parser, System.Type type) + public object ReadYaml(IParser parser, Type type) { - var value = ((Core.Events.Scalar)parser.Current).Value; + var value = ((Scalar)parser.Current).Value; parser.MoveNext(); - return new System.Guid(value); + return new Guid(value); } - public void WriteYaml(Core.IEmitter emitter, object value, System.Type type) + public void WriteYaml(IEmitter emitter, object value, Type type) { - var guid = (System.Guid)value; - emitter.Emit(new Core.Events.Scalar(null, null, guid.ToString("D"), jsonCompatible ? ScalarStyle.DoubleQuoted : ScalarStyle.Any, true, false)); + var guid = (Guid)value; + emitter.Emit(new Scalar(null, null, guid.ToString("D"), jsonCompatible ? ScalarStyle.DoubleQuoted : ScalarStyle.Any, true, false)); } } } diff --git a/YamlDotNet/Serialization/Converters/SystemTypeConverter.cs b/YamlDotNet/Serialization/Converters/SystemTypeConverter.cs new file mode 100644 index 000000000..9a629e5f5 --- /dev/null +++ b/YamlDotNet/Serialization/Converters/SystemTypeConverter.cs @@ -0,0 +1,33 @@ +using System; +using YamlDotNet.Core; +using YamlDotNet.Core.Events; + +namespace YamlDotNet.Serialization.Converters +{ + /// + /// Converter for System.Type. + /// + /// + /// Converts to a scalar containing the assembly qualified name of the type. + /// + public class SystemTypeConverter : IYamlTypeConverter + { + public bool Accepts(Type type) + { + return typeof(Type).IsAssignableFrom(type); + } + + public object ReadYaml(IParser parser, Type type) + { + var value = ((Scalar)parser.Current).Value; + parser.MoveNext(); + return Type.GetType(value, throwOnError: true); + } + + public void WriteYaml(IEmitter emitter, object value, Type type) + { + var systemType = (Type)value; + emitter.Emit(new Scalar(null, null, systemType.AssemblyQualifiedName, ScalarStyle.Any, true, false)); + } + } +} diff --git a/YamlDotNet/Serialization/Deserializer.cs b/YamlDotNet/Serialization/Deserializer.cs index 2d84a5e67..0655aa651 100644 --- a/YamlDotNet/Serialization/Deserializer.cs +++ b/YamlDotNet/Serialization/Deserializer.cs @@ -107,6 +107,7 @@ public IPropertyDescriptor GetProperty(Type type, object container, string name, converters = new List(); converters.Add(new GuidConverter(false)); + converters.Add(new SystemTypeConverter()); NodeDeserializers = new List(); NodeDeserializers.Add(new YamlConvertibleNodeDeserializer(objectFactory)); diff --git a/YamlDotNet/Serialization/Serializer.cs b/YamlDotNet/Serialization/Serializer.cs index 2095299b9..37cfe5b14 100644 --- a/YamlDotNet/Serialization/Serializer.cs +++ b/YamlDotNet/Serialization/Serializer.cs @@ -55,6 +55,7 @@ public BackwardsCompatibleConfiguration(SerializationOptions options, INamingCon Converters = new List(); Converters.Add(new GuidConverter(IsOptionSet(SerializationOptions.JsonCompatible))); + Converters.Add(new SystemTypeConverter()); typeResolver = IsOptionSet(SerializationOptions.DefaultToStaticType) ? (ITypeResolver)new StaticTypeResolver()