From bdb4a4783a9785bc547c550ff6f199504870560d Mon Sep 17 00:00:00 2001 From: Haran Shivanan Date: Tue, 4 Oct 2016 18:27:21 +0530 Subject: [PATCH] Added a serializer for types where building the serializer raises exceptions This is a fix for https://github.com/AsynkronIT/Wire/issues/115 --- Wire.Tests/UnsupportedTypeSerializerTests.cs | 151 ++++++++++++++++++ Wire.Tests/Wire.Tests.csproj | 1 + Wire/Serializer.cs | 34 +++- .../UnsupportedTypeSerializer.cs | 55 +++++++ Wire/Wire.csproj | 1 + 5 files changed, 238 insertions(+), 4 deletions(-) create mode 100644 Wire.Tests/UnsupportedTypeSerializerTests.cs create mode 100644 Wire/ValueSerializers/UnsupportedTypeSerializer.cs diff --git a/Wire.Tests/UnsupportedTypeSerializerTests.cs b/Wire.Tests/UnsupportedTypeSerializerTests.cs new file mode 100644 index 0000000..0dde3c9 --- /dev/null +++ b/Wire.Tests/UnsupportedTypeSerializerTests.cs @@ -0,0 +1,151 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; +namespace Wire.Tests +{ + [TestClass] + public class UnsupportedTypeSerializerTests:TestBase + { + [TestMethod] + public void DoUnsupportedTypesThrowErrors() + { + var serializer = new Wire.Serializer(); + var t = new TestElement(); + try + { + serializer.Serialize(t, new System.IO.MemoryStream()); + } + catch(Wire.ValueSerializers.UnsupportedTypeException) + { + Assert.IsTrue(true); + return; + } + + } + + [TestMethod] + public void DoUnsupportedTypesNotHangOnExceptions() + { + var th = new System.Threading.Thread(new System.Threading.ThreadStart(() => + { + var serializer = new Wire.Serializer(); + var t = new TestElement(); + try + { + serializer.Serialize(t, new System.IO.MemoryStream()); + } + catch (Exception) + { + try + { + serializer.Serialize(t, new System.IO.MemoryStream()); + } + catch (Wire.ValueSerializers.UnsupportedTypeException) + { + return; + } + + } + })); + th.Start(); + if (!th.Join(TimeSpan.FromSeconds(5))) + { + th.Abort(); + Assert.Fail("Serializer did not complete in 5 seconds"); + } + + } + } + + + /* Copied from MongoDB.Bson.BsonElement - causes failures in the serializer - not sure why */ +#if NET45 + [Serializable] +#endif + struct TestElement : IComparable, IEquatable + { + private readonly string _name; + private readonly string _value; + + + public TestElement(string name, string value) + { + if (name == null) + { + throw new ArgumentNullException("name"); + } + if (value == null) + { + throw new ArgumentNullException("value"); + } + _name = name; + _value = value; + } + + public string Name + { + get { return _name; } + } + + public string Value + { + get { return _value; } + } + + public static bool operator ==(TestElement lhs, TestElement rhs) + { + return Equals(lhs, rhs); + } + + public static bool operator !=(TestElement lhs, TestElement rhs) + { + return !(lhs == rhs); + } + + public TestElement Clone() + { + return new TestElement(_name, _value); + } + + public TestElement DeepClone() + { + return new TestElement(_name, _value); + } + + public int CompareTo(TestElement other) + { + int r = _name.CompareTo(other._name); + if (r != 0) { return r; } + return _value.CompareTo(other._value); + } + + public bool Equals(TestElement rhs) + { + return _name == rhs._name && _value == rhs._value; + } + + public override bool Equals(object obj) + { + if (obj == null || obj.GetType() != typeof(TestElement)) { return false; } + return Equals((TestElement)obj); + } + + public override int GetHashCode() + { + // see Effective Java by Joshua Bloch + int hash = 17; + hash = 37 * hash + _name.GetHashCode(); + hash = 37 * hash + _value.GetHashCode(); + return hash; + } + + public override string ToString() + { + return string.Format("{0}={1}", _name, _value); + } + } + +} diff --git a/Wire.Tests/Wire.Tests.csproj b/Wire.Tests/Wire.Tests.csproj index e3a6894..473c402 100644 --- a/Wire.Tests/Wire.Tests.csproj +++ b/Wire.Tests/Wire.Tests.csproj @@ -73,6 +73,7 @@ + diff --git a/Wire/Serializer.cs b/Wire/Serializer.cs index 3c55601..fbab4ac 100644 --- a/Wire/Serializer.cs +++ b/Wire/Serializer.cs @@ -215,16 +215,42 @@ namespace Wire if (!_serializers.TryAdd(type, wrapper)) return _serializers[type]; - //build the serializer IL code - CodeGenerator.BuildSerializer(this, (ObjectSerializer) serializer); + + + + try + { + //build the serializer IL code + CodeGenerator.BuildSerializer(this, (ObjectSerializer)serializer); + } + catch (Exception exp) + { + var invalidSerializer = new UnsupportedTypeSerializer(type,exp.Message); + _serializers[type] = invalidSerializer; + return invalidSerializer; + } //just ignore if this fails, another thread have already added an identical serializer return wrapper; } if (!_serializers.TryAdd(type, serializer)) return _serializers[type]; - //build the serializer IL code - CodeGenerator.BuildSerializer(this, (ObjectSerializer) serializer); + + + try + { + //build the serializer IL code + CodeGenerator.BuildSerializer(this, (ObjectSerializer)serializer); + + } + catch(Exception exp) + { + var invalidSerializer = new UnsupportedTypeSerializer(type,exp.Message); + _serializers[type] = invalidSerializer; + return invalidSerializer; + } + + //just ignore if this fails, another thread have already added an identical serializer return serializer; //add it to the serializer lookup in case of recursive serialization diff --git a/Wire/ValueSerializers/UnsupportedTypeSerializer.cs b/Wire/ValueSerializers/UnsupportedTypeSerializer.cs new file mode 100644 index 0000000..b64c840 --- /dev/null +++ b/Wire/ValueSerializers/UnsupportedTypeSerializer.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Wire.Compilation; +using Wire.Internal; + +namespace Wire.ValueSerializers +{ + //https://github.com/AsynkronIT/Wire/issues/115 + + public class UnsupportedTypeException:Exception + { + public Type Type; + public UnsupportedTypeException(Type t, string msg):base(msg) + { } + } + public class UnsupportedTypeSerializer:ValueSerializer + { + private string errorMessage = ""; + private Type invalidType; + public UnsupportedTypeSerializer(Type t, string msg) + { + errorMessage = msg; + invalidType = t; + } + public override int EmitReadValue([NotNull] ICompiler c, int stream, int session, [NotNull] FieldInfo field) + { + throw new UnsupportedTypeException(invalidType, errorMessage); + } + public override void EmitWriteValue(ICompiler c, int stream, int fieldValue, int session) + { + throw new UnsupportedTypeException(invalidType, errorMessage); + } + public override object ReadValue([NotNull] Stream stream, [NotNull] DeserializerSession session) + { + throw new UnsupportedTypeException(invalidType, errorMessage); + } + public override void WriteManifest([NotNull] Stream stream, [NotNull] SerializerSession session) + { + throw new UnsupportedTypeException(invalidType, errorMessage); + } + public override void WriteValue([NotNull] Stream stream, object value, [NotNull] SerializerSession session) + { + throw new UnsupportedTypeException(invalidType, errorMessage); + } + public override Type GetElementType() + { + throw new UnsupportedTypeException(invalidType, errorMessage); + } + } +} diff --git a/Wire/Wire.csproj b/Wire/Wire.csproj index a3e1a8b..f8a21ee 100644 --- a/Wire/Wire.csproj +++ b/Wire/Wire.csproj @@ -94,6 +94,7 @@ +