From 496cb1eb5d1e2f9ee17fe8c1f7c4dd6aeed61c0a Mon Sep 17 00:00:00 2001 From: Matteo Cominetti Date: Tue, 22 Oct 2019 14:30:16 +0100 Subject: [PATCH] Added SpeckleError --- Conversion/ConverterDeserialisation.cs | 272 +++++++++++++------------ Data/SpeckleError.cs | 18 ++ SpeckleCore.csproj | 1 + 3 files changed, 164 insertions(+), 127 deletions(-) create mode 100644 Data/SpeckleError.cs diff --git a/Conversion/ConverterDeserialisation.cs b/Conversion/ConverterDeserialisation.cs index d4560d1..3c288d5 100644 --- a/Conversion/ConverterDeserialisation.cs +++ b/Conversion/ConverterDeserialisation.cs @@ -1,4 +1,5 @@ -using System; +using SpeckleCore.Data; +using System; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -29,6 +30,9 @@ public static List Deserialise( IEnumerable objectList, I /// an object, a SpeckleAbstract or null. public static object Deserialise( SpeckleObject obj, object root = null, IEnumerable excludeAssebmlies = null ) { + + var currentType = obj.GetType(); + try { // null check @@ -44,7 +48,6 @@ public static object Deserialise( SpeckleObject obj, object root = null, IEnumer } var methods = new List(); - var currentType = obj.GetType(); var baseTypes = new List(); // create a list of base types for this object @@ -90,170 +93,185 @@ public static object Deserialise( SpeckleObject obj, object root = null, IEnumer } } - // last, but not least, try and return the original object (?) - return obj; + return new SpeckleConversionError + { + Message = $"Could not convert object of type '{currentType}'", + Details = $"No Speckle kit capable of converting objects of type '{currentType}' was found, this either means we haven't developed it yet or that you're missing the required kit ¯\\_(ツ)_/¯", + SourceObject = obj + }; } else { - // we have a speckle abstract object - var absObj = obj as SpeckleAbstract; + return DeserializeSpeckleAbstract(obj, root); + } + + } + catch (Exception e) + { + return new SpeckleConversionError + { + Message = $"Failed to convert object of type '{currentType}'", + Details = e.Message, + SourceObject = obj + }; + } + } - if ( absObj._type == "ref" ) - return null; + private static object DeserializeSpeckleAbstract(object obj, object root) + { + // we have a speckle abstract object + var absObj = obj as SpeckleAbstract; - //var shortName = absObj._assembly.Split( ',' )[ 0 ]; + if (absObj._type == "ref") + return null; - var assembly = System.AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault( a => a.FullName == absObj._assembly ); + //var shortName = absObj._assembly.Split( ',' )[ 0 ]; - //try again, without version control - if ( assembly == null ) - { - var shortName = absObj._assembly.Split( ',' )[ 0 ]; - assembly = System.AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault( a => a.FullName.Contains( shortName ) ); - } + var assembly = System.AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == absObj._assembly); + + //try again, without version control + if (assembly == null) + { + var shortName = absObj._assembly.Split(',')[0]; + assembly = System.AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName.Contains(shortName)); + } + + if (assembly == null) // we can't deserialise for sure + return Converter.ShallowConvert(absObj); - if ( assembly == null ) // we can't deserialise for sure - return Converter.ShallowConvert( absObj ); + var type = assembly.GetTypes().FirstOrDefault(t => t.Name == absObj._type); + if (type == null) // type not present in the assembly + return Converter.ShallowConvert(absObj); - var type = assembly.GetTypes().FirstOrDefault( t => t.Name == absObj._type ); - if ( type == null ) // type not present in the assembly - return Converter.ShallowConvert( absObj ); + object myObject = null; - object myObject = null; + try + { + var constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { }, null); + if (constructor != null) + myObject = constructor.Invoke(new object[] { }); + if (myObject == null) + myObject = Activator.CreateInstance(type); + } + catch + { + myObject = System.Runtime.Serialization.FormatterServices.GetUninitializedObject(type); + } + if (myObject == null) + return absObj; + + if (root == null) + root = myObject; + + var keys = absObj.Properties.Keys; + foreach (string key in keys) + { + var prop = TryGetProperty(type, key); + var field = type.GetField(key); + + if (prop == null && field == null) continue; + + if (absObj.Properties[key] == null) continue; + + var value = ReadValue(absObj.Properties[key], root); + + // handles both hashsets and lists or whatevers + if (value is IEnumerable && !(value is IDictionary) && value.GetType() != typeof(string)) + { try { - var constructor = type.GetConstructor( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[ ] { }, null ); - if ( constructor != null ) - myObject = constructor.Invoke( new object[ ] { } ); - if ( myObject == null ) - myObject = Activator.CreateInstance( type ); - } - catch - { - myObject = System.Runtime.Serialization.FormatterServices.GetUninitializedObject( type ); - } - if ( myObject == null ) - return absObj; + if ((prop != null && prop.PropertyType.IsArray) || (field != null && field.FieldType.IsArray)) + { + value = ((List)value).ToArray(); + } + else + { + var mySubList = Activator.CreateInstance(prop != null ? prop.PropertyType : field.FieldType); + foreach (var myObj in ((IEnumerable)value)) + mySubList.GetType().GetMethod("Add").Invoke(mySubList, new object[] { Convert.ChangeType(myObj, mySubList.GetType().GetGenericArguments().Single()) }); - if ( root == null ) - root = myObject; + value = mySubList; + } + } + catch { } + } - var keys = absObj.Properties.Keys; - foreach ( string key in keys ) + // handles dictionaries of all sorts (kind-of!) + if (value is IDictionary) + { + try { - var prop = TryGetProperty( type, key ); - var field = type.GetField( key ); + var MyDict = Activator.CreateInstance(prop != null ? prop.PropertyType : field.FieldType); - if ( prop == null && field == null ) continue; + foreach (DictionaryEntry kvp in (IDictionary)value) + MyDict.GetType().GetMethod("Add").Invoke(MyDict, new object[] { Convert.ChangeType(kvp.Key, MyDict.GetType().GetGenericArguments()[0]), kvp.Value }); - if ( absObj.Properties[ key ] == null ) continue; + value = MyDict; + } + catch (Exception e) + { + System.Diagnostics.Debug.WriteLine(e.Message); + } + } - var value = ReadValue( absObj.Properties[ key ], root ); + // guids are a pain + if ((prop != null && prop.PropertyType == typeof(Guid)) || (field != null && field.FieldType == typeof(Guid))) + value = new Guid((string)value); - // handles both hashsets and lists or whatevers - if ( value is IEnumerable && !( value is IDictionary ) && value.GetType() != typeof( string ) ) + // Actually set the value below, whether it's a property or field + // if it is a property + if (prop != null && prop.CanWrite) + { + if (prop.PropertyType.IsEnum) + prop.SetValue(myObject, Enum.ToObject(prop.PropertyType, Convert.ChangeType(value, TypeCode.Int32))); + else + { + try { - try - { - - if ( ( prop != null && prop.PropertyType.IsArray ) || ( field != null && field.FieldType.IsArray ) ) - { - value = ( ( List ) value ).ToArray(); - } - else - { - var mySubList = Activator.CreateInstance( prop != null ? prop.PropertyType : field.FieldType ); - foreach ( var myObj in ( ( IEnumerable ) value ) ) - mySubList.GetType().GetMethod( "Add" ).Invoke( mySubList, new object[ ] { Convert.ChangeType( myObj, mySubList.GetType().GetGenericArguments().Single() ) } ); - - value = mySubList; - } - } - catch { } + prop.SetValue(myObject, value); } - - // handles dictionaries of all sorts (kind-of!) - if ( value is IDictionary ) + catch { try { - var MyDict = Activator.CreateInstance( prop != null ? prop.PropertyType : field.FieldType ); - - foreach ( DictionaryEntry kvp in ( IDictionary ) value ) - MyDict.GetType().GetMethod( "Add" ).Invoke( MyDict, new object[ ] { Convert.ChangeType( kvp.Key, MyDict.GetType().GetGenericArguments()[ 0 ] ), kvp.Value } ); - - value = MyDict; + prop.SetValue(myObject, Convert.ChangeType(value, prop.PropertyType)); } - catch ( Exception e ) + catch { - System.Diagnostics.Debug.WriteLine( e.Message ); } } - - // guids are a pain - if ( ( prop != null && prop.PropertyType == typeof( Guid ) ) || ( field != null && field.FieldType == typeof( Guid ) ) ) - value = new Guid( ( string ) value ); - - // Actually set the value below, whether it's a property or field - // if it is a property - if ( prop != null && prop.CanWrite ) + } + } + // if it is a field + else if (field != null) + { + if (field.FieldType.IsEnum) + field.SetValue(myObject, Enum.ToObject(field.FieldType, Convert.ChangeType(value, TypeCode.Int32))); + else + { + try { - if ( prop.PropertyType.IsEnum ) - prop.SetValue( myObject, Enum.ToObject( prop.PropertyType, Convert.ChangeType( value, TypeCode.Int32 ) ) ); - else - { - try - { - prop.SetValue( myObject, value ); - } - catch - { - try - { - prop.SetValue( myObject, Convert.ChangeType( value, prop.PropertyType ) ); - } - catch - { - } - } - } + field.SetValue(absObj, value); } - // if it is a field - else if ( field != null ) + catch { - if ( field.FieldType.IsEnum ) - field.SetValue( myObject, Enum.ToObject( field.FieldType, Convert.ChangeType( value, TypeCode.Int32 ) ) ); - else + try { - try - { - field.SetValue( absObj, value ); - } - catch - { - try - { - field.SetValue( myObject, Convert.ChangeType( value, field.FieldType ) ); - } - catch { } - } + field.SetValue(myObject, Convert.ChangeType(value, field.FieldType)); } + catch { } } } - - // set references too. - if ( root == myObject ) - Converter.ResolveRefs( absObj, myObject, "root" ); - - return myObject; } } - catch - { - return obj; - } + + // set references too. + if (root == myObject) + Converter.ResolveRefs(absObj, myObject, "root"); + + return myObject; } private static object ShallowConvert( SpeckleAbstract obj ) diff --git a/Data/SpeckleError.cs b/Data/SpeckleError.cs new file mode 100644 index 0000000..3fb178d --- /dev/null +++ b/Data/SpeckleError.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SpeckleCore.Data +{ + public class SpeckleError + { + public string Message { get; set; } + public string Details { get; set; } + } + public class SpeckleConversionError : SpeckleError + { + public object SourceObject { get; set; } + } +} diff --git a/SpeckleCore.csproj b/SpeckleCore.csproj index 51a6b08..a635d6a 100644 --- a/SpeckleCore.csproj +++ b/SpeckleCore.csproj @@ -72,6 +72,7 @@ +