/// <summary> /// Gets a value which indicates if should be ignored in Json serialization. /// </summary> /// <param name="value"></param> /// <returns></returns> public static bool IsXmlIgnore(object value) { if (value == null) { return(false); } Type type = value.GetType(); ICustomAttributeProvider provider = null; if (TCU.GetTypeInfo(type).IsEnum) { provider = TCU.GetTypeInfo(type).GetField(Enum.GetName(type, value)); } else { provider = value as ICustomAttributeProvider; } if (provider == null) { throw new ArgumentException(); } #if !UNITY3D return(provider.IsDefined(typeof(XmlIgnoreAttribute), true)); #else return(false); #endif }
/** Returns a member map if suitable for the object type. * Dictionary types will make this method return null */ public Dictionary <string, MemberInfo> GetMemberMap(Type objectType) { // don't incurr the cost of member map for dictionaries if (TCU.GetTypeInfo(typeof(IDictionary)).IsAssignableFrom(TCU.GetTypeInfo(objectType))) { return(null); } else { return(this.CreateMemberMap(objectType)); } }
/// <summary> /// Gets the name specified for use in Json serialization. /// </summary> /// <param name="value"></param> /// <returns></returns> public static string GetJsonName(object value) { if (value == null) { return(null); } Type type = value.GetType(); MemberInfo memberInfo = null; if (TCU.GetTypeInfo(type).IsEnum) { string name = Enum.GetName(type, value); if (String.IsNullOrEmpty(name)) { return(null); } memberInfo = TCU.GetTypeInfo(type).GetField(name); } else { memberInfo = value as MemberInfo; } if (MemberInfo.Equals(memberInfo, null)) { throw new ArgumentException(); } #if WINDOWS_STORE JsonNameAttribute attribute = memberInfo.GetCustomAttribute <JsonNameAttribute> (true); #else JsonNameAttribute attribute = Attribute.GetCustomAttribute(memberInfo, typeof(JsonNameAttribute)) as JsonNameAttribute; #endif return(attribute != null ? attribute.Name : null); }
protected virtual void Write(object value, bool isProperty, Type fieldType = null, bool skipConverters = false) { if (isProperty && this.settings.PrettyPrint) { this.Writer.Write(' '); } if (value == null) { this.Writer.Write(JsonReader.LiteralNull); return; } if (value is IJsonSerializable && !skipConverters) { try { if (isProperty) { this.depth++; if (this.depth > this.settings.MaxDepth) { throw new JsonSerializationException(String.Format(JsonWriter.ErrorMaxDepth, new System.Object[] { this.settings.MaxDepth })); } this.WriteLine(); } ((IJsonSerializable)value).WriteJson(this); } finally { if (isProperty) { this.depth--; } } return; } // must test enumerations before value types if (value is Enum) { this.Write((Enum)value); return; } // Type.GetTypeCode() allows us to more efficiently switch type // plus cannot use 'is' for ValueTypes Type type = value.GetType(); #if WINDOWS_STORE if (Type.Equals(type, typeof(bool))) { this.Write((Boolean)value); return; } else if (Type.Equals(type, typeof(System.Int32))) { this.Write((Int32)value); return; } else if (Type.Equals(type, typeof(System.Single))) { this.Write((Single)value); return; } else if (Type.Equals(type, typeof(System.String))) { this.Write((String)value); return; } else if (Type.Equals(type, typeof(byte))) { this.Write((Byte)value); return; } else if (Type.Equals(type, typeof(char))) { this.Write((Char)value); return; } else if (Type.Equals(type, typeof(DateTime))) { this.Write((DateTime)value); return; } else if (Type.Equals(type, typeof(DBNull)) || Type.Equals(type, null)) { this.Writer.Write(JsonReader.LiteralNull); return; } else if (Type.Equals(type, typeof(Decimal))) { // From MSDN: // Conversions from Char, SByte, Int16, Int32, Int64, Byte, UInt16, UInt32, and UInt64 // to Decimal are widening conversions that never lose information or throw exceptions. // Conversions from Single or Double to Decimal throw an OverflowException // if the result of the conversion is not representable as a Decimal. this.Write((Decimal)value); return; } else if (Type.Equals(type, typeof(double))) { this.Write((Double)value); return; } else if (Type.Equals(type, typeof(System.Int16))) { this.Write((Int16)value); return; } else if (Type.Equals(type, typeof(System.Int64))) { this.Write((Int64)value); return; } else if (Type.Equals(type, typeof(System.SByte))) { this.Write((SByte)value); return; } else if (Type.Equals(type, typeof(System.UInt16))) { this.Write((UInt16)value); return; } else if (Type.Equals(type, typeof(System.UInt32))) { this.Write((UInt32)value); return; } else if (Type.Equals(type, typeof(System.UInt64))) { this.Write((UInt64)value); return; } else { // all others must be explicitly tested } #else // Faster to switch on typecode, but Windows Store does not support it switch (TP.GetTypeCode(type)) { case TypeCode.Boolean: { this.Write((Boolean)value); return; } case TypeCode.Byte: { this.Write((Byte)value); return; } case TypeCode.Char: { this.Write((Char)value); return; } case TypeCode.DateTime: { this.Write((DateTime)value); return; } case TypeCode.DBNull: case TypeCode.Empty: { this.Writer.Write(JsonReader.LiteralNull); return; } case TypeCode.Decimal: { // From MSDN: // Conversions from Char, SByte, Int16, Int32, Int64, Byte, UInt16, UInt32, and UInt64 // to Decimal are widening conversions that never lose information or throw exceptions. // Conversions from Single or Double to Decimal throw an OverflowException // if the result of the conversion is not representable as a Decimal. this.Write((Decimal)value); return; } case TypeCode.Double: { this.Write((Double)value); return; } case TypeCode.Int16: { this.Write((Int16)value); return; } case TypeCode.Int32: { this.Write((Int32)value); return; } case TypeCode.Int64: { this.Write((Int64)value); return; } case TypeCode.SByte: { this.Write((SByte)value); return; } case TypeCode.Single: { this.Write((Single)value); return; } case TypeCode.String: { this.Write((String)value); return; } case TypeCode.UInt16: { this.Write((UInt16)value); return; } case TypeCode.UInt32: { this.Write((UInt32)value); return; } case TypeCode.UInt64: { this.Write((UInt64)value); return; } default: case TypeCode.Object: { // all others must be explicitly tested break; } } #endif if (!skipConverters) { JsonConverter converter = this.Settings.GetConverter(type); if (converter != null) { // Return if converter serialized the object if (converter.Write(this, depth, type, value)) { return; } } } if (value is Guid) { this.Write((Guid)value); return; } if (value is Uri) { this.Write((Uri)value); return; } if (value is TimeSpan) { this.Write((TimeSpan)value); return; } if (value is Version) { this.Write((Version)value); return; } // IDictionary test must happen BEFORE IEnumerable test // since IDictionary implements IEnumerable if (value is IDictionary) { try { if (isProperty) { this.depth++; if (this.depth > this.settings.MaxDepth) { throw new JsonSerializationException(String.Format(JsonWriter.ErrorMaxDepth, new System.Object[] { this.settings.MaxDepth })); } this.WriteLine(); } this.WriteObject((IDictionary)value); } finally { if (isProperty) { this.depth--; } } return; } //if (!Type.Equals (TCU.GetTypeInfo(type).GetInterface (JsonReader.TypeGenericIDictionary), null)) if (TCU.GetTypeInfo(typeof(IDictionary)).IsAssignableFrom(TCU.GetTypeInfo(value.GetType()))) { try { if (isProperty) { this.depth++; if (this.depth > this.settings.MaxDepth) { throw new JsonSerializationException(String.Format(JsonWriter.ErrorMaxDepth, new System.Object[] { this.settings.MaxDepth })); } this.WriteLine(); } this.WriteDictionary((IEnumerable)value); } finally { if (isProperty) { this.depth--; } } return; } if (value is IList && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List <>)) { // Is List<T> var memberType = type.GetGenericArguments() [0]; try { if (isProperty) { this.depth++; if (this.depth > this.settings.MaxDepth) { throw new JsonSerializationException(String.Format(JsonWriter.ErrorMaxDepth, new System.Object[] { this.settings.MaxDepth })); } this.WriteLine(); } this.WriteArray((IEnumerable)value, memberType); } finally { if (isProperty) { this.depth--; } } return; } // IDictionary test must happen BEFORE IEnumerable test // since IDictionary implements IEnumerable if (value is IEnumerable) { #if !UNITY3D if (value is XmlNode) { this.Write((System.Xml.XmlNode)value); return; } #endif try { if (isProperty) { this.depth++; if (this.depth > this.settings.MaxDepth) { throw new JsonSerializationException(String.Format(JsonWriter.ErrorMaxDepth, new System.Object[] { this.settings.MaxDepth })); } this.WriteLine(); } this.WriteArray((IEnumerable)value, type.GetElementType()); } finally { if (isProperty) { this.depth--; } } return; } // structs and classes try { if (isProperty) { this.depth++; if (this.depth > this.settings.MaxDepth) { throw new JsonSerializationException(String.Format(JsonWriter.ErrorMaxDepth, new System.Object[] { this.settings.MaxDepth })); } this.WriteLine(); } this.WriteObject(value, type, true, fieldType); } finally { if (isProperty) { this.depth--; } } }
protected virtual void WriteObject(object value, Type type, bool serializePrivate, Type fieldType = null) { bool appendDelim = false; if (settings.HandleCyclicReferences && !TCU.GetTypeInfo(type).IsValueType) { int prevIndex = 0; if (this.previouslySerializedObjects.TryGetValue(value, out prevIndex)) { this.Writer.Write(JsonReader.OperatorObjectStart); this.WriteObjectProperty("@ref", prevIndex); this.WriteLine(); this.Writer.Write(JsonReader.OperatorObjectEnd); return; } else { this.previouslySerializedObjects.Add(value, this.previouslySerializedObjects.Count); } } this.Writer.Write(JsonReader.OperatorObjectStart); this.depth++; if (this.depth > this.settings.MaxDepth) { throw new JsonSerializationException(String.Format(JsonWriter.ErrorMaxDepth, new System.Object[] { this.settings.MaxDepth })); } try { if (!String.IsNullOrEmpty(this.settings.TypeHintName) && (!settings.TypeHintsOnlyWhenNeeded || depth <= 1 || (!Type.Equals(fieldType, type) && !Type.Equals(fieldType, null)))) { if (appendDelim) { this.WriteObjectPropertyDelim(); } else { appendDelim = true; } if (type.Assembly.Equals(Settings.DefaultAssembly)) { this.WriteObjectProperty(this.settings.TypeHintName, type.FullName); } else { this.WriteObjectProperty(this.settings.TypeHintName, type.FullName + ", " + type.Assembly.GetName().Name); } } // Set tag so that other objects can find it when deserializing // Note that this must be set after the type hint is serialized // To make sure the fields are read correctly when deserializing if (referenceHandler != null && referenceHandler.IsHandled(type)) { if (appendDelim) { this.WriteObjectPropertyDelim(); } else { appendDelim = true; } this.WriteObjectProperty("@tag", referenceHandler.GetReferenceID(value)); // Notify the reference handler that this value has now been serialized referenceHandler.MarkAsSerialized(value); } //Console.WriteLine ("Anon " + anonymousType); //Console.WriteLine (type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic).Length + " " + type.GetProperties().Length); // serialize public properties TypeCoercionUtility.Member[] members; this.settings.Coercion.GetMemberWritingMap(type, settings, out members); for (int j = 0; j < members.Length; j++) { MemberInfo member = members[j].member; System.Type memberType; object memberValue; PropertyInfo property = member as PropertyInfo; if (property != null) { memberType = property.PropertyType; memberValue = property.GetValue(value, null); } else { var field = member as FieldInfo; memberType = field.FieldType; memberValue = field.GetValue(value); } if (members[j].IsDefaultValue(memberValue)) { if (Settings.DebugMode) { Console.WriteLine("Cannot serialize " + member.Name + " : is default value"); } continue; } if (appendDelim) { this.WriteObjectPropertyDelim(); } else { appendDelim = true; } string name = members[j].name; bool ownedRef = referenceHandler == null || !referenceHandler.IsHandled(memberType) || referenceHandler.IsOwnedRef(member); if (ownedRef || memberValue == null) { // Reference is owned by this member, serialize it as normal this.WriteObjectProperty(name, memberValue, memberType); } else { // Reference is not owned by this property, write a reference to it this.WriteObjectProperty(name, "@" + referenceHandler.GetReferenceID(memberValue), typeof(string)); } } } finally { this.depth--; } if (appendDelim) { this.WriteLine(); } this.Writer.Write(JsonReader.OperatorObjectEnd); }
/// <summary> /// Determines if the property or field should not be serialized. /// </summary> /// <param name="objType"></param> /// <param name="member"></param> /// <param name="value"></param> /// <returns></returns> /// <remarks> /// Checks these in order, if any returns true then this is true: /// - is flagged with the JsonIgnoreAttribute property /// - has a JsonSpecifiedProperty which returns false /// </remarks> private bool IsIgnored(Type objType, MemberInfo member, object obj) { if (JsonIgnoreAttribute.IsJsonIgnore(member)) { return(true); } string specifiedProperty = JsonSpecifiedPropertyAttribute.GetJsonSpecifiedProperty(member); if (!String.IsNullOrEmpty(specifiedProperty)) { #if WINDOWS_STORE PropertyInfo specProp = TCU.GetTypeInfo(objType).GetRuntimeProperty(specifiedProperty); #else PropertyInfo specProp = TCU.GetTypeInfo(objType).GetProperty(specifiedProperty); #endif if (!PropertyInfo.Equals(specProp, null)) { object isSpecified = specProp.GetValue(obj, null); if (isSpecified is Boolean && !Convert.ToBoolean(isSpecified)) { return(true); } } } //If the class is specified as opt-in serialization only, members must have the JsonMember attribute #if WINDOWS_STORE if (objType.GetCustomAttribute <JsonOptInAttribute>(true) != null) { if (member.GetCustomAttribute <JsonMemberAttribute>(true) == null) { return(true); } } #else if (objType.GetCustomAttributes(typeof(JsonOptInAttribute), true).Length != 0) { if (member.GetCustomAttributes(typeof(JsonMemberAttribute), true).Length == 0) { return(true); } } #endif if (this.settings.UseXmlSerializationAttributes) { if (JsonIgnoreAttribute.IsXmlIgnore(member)) { return(true); } #if WINDOWS_STORE PropertyInfo specProp = TCU.GetTypeInfo(objType).GetRuntimeProperty(specifiedProperty); #else PropertyInfo specProp = TCU.GetTypeInfo(objType).GetProperty(member.Name + "Specified"); #endif if (!PropertyInfo.Equals(specProp, null)) { object isSpecified = specProp.GetValue(obj, null); if (isSpecified is Boolean && !Convert.ToBoolean(isSpecified)) { return(true); } } } return(false); }
protected virtual void WriteObject(object value, Type type, bool serializePrivate, Type fieldType = null) { bool appendDelim = false; if (settings.HandleCyclicReferences && !TCU.GetTypeInfo(type).IsValueType) { int prevIndex = 0; if (this.previouslySerializedObjects.TryGetValue(value, out prevIndex)) { this.Writer.Write(JsonReader.OperatorObjectStart); this.WriteObjectProperty("@ref", prevIndex); this.WriteLine(); this.Writer.Write(JsonReader.OperatorObjectEnd); return; } else { this.previouslySerializedObjects.Add(value, this.previouslySerializedObjects.Count); } } this.Writer.Write(JsonReader.OperatorObjectStart); this.depth++; if (this.depth > this.settings.MaxDepth) { throw new JsonSerializationException(String.Format(JsonWriter.ErrorMaxDepth, new System.Object[] { this.settings.MaxDepth })); } try { if (!String.IsNullOrEmpty(this.settings.TypeHintName) && (!settings.TypeHintsOnlyWhenNeeded || depth <= 1 || (!Type.Equals(fieldType, type) && !Type.Equals(fieldType, null)))) { if (appendDelim) { this.WriteObjectPropertyDelim(); } else { appendDelim = true; } this.WriteObjectProperty(this.settings.TypeHintName, type.FullName + ", " + type.Assembly.GetName().Name); } //Console.WriteLine ("Anon " + anonymousType); //Console.WriteLine (type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic).Length + " " + type.GetProperties().Length); // serialize public properties KeyValuePair <string, FieldInfo>[] fields; KeyValuePair <string, PropertyInfo>[] properties; this.settings.Coercion.GetMemberWritingMap(type, settings, out fields, out properties); for (int j = 0; j < properties.Length; j++) { PropertyInfo property = properties [j].Value; object propertyValue = property.GetValue(value, null); if (this.IsDefaultValue(property, propertyValue)) { if (Settings.DebugMode) { Console.WriteLine("Cannot serialize " + property.Name + " : is default value"); } continue; } if (appendDelim) { this.WriteObjectPropertyDelim(); } else { appendDelim = true; } string name = properties [j].Key; this.WriteObjectProperty(name, propertyValue, property.PropertyType); } for (int j = 0; j < fields.Length; j++) { FieldInfo field = fields [j].Value; object fieldValue = field.GetValue(value); if (this.IsDefaultValue(field, fieldValue)) { if (Settings.DebugMode) { Console.WriteLine("Cannot serialize " + field.Name + " : is default value"); } continue; } if (appendDelim) { this.WriteObjectPropertyDelim(); } else { appendDelim = true; } string name = fields [j].Key; this.WriteObjectProperty(name, fieldValue, field.FieldType); } /*// serialize public fields * FieldInfo[] fields = TCU.GetTypeInfo(type).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); * for (int j = 0; j < fields.Length; j++ ) { * if (field.IsStatic || (!field.IsPublic && #if WINDOWS_STORE * field.GetCustomAttribute<JsonMemberAttribute>(true) == null)) #else * field.GetCustomAttributes(typeof(JsonMemberAttribute),true).Length == 0)) #endif * { #if DEBUG * if (Settings.DebugMode) * Console.WriteLine ("Cannot serialize "+field.Name+" : not public or is static (and does not have a JsonMember attribute)"); #endif * continue; * } * * if (this.IsIgnored(type, field, value)) { #if DEBUG * if (Settings.DebugMode) * Console.WriteLine ("Cannot serialize "+field.Name+" : ignored by settings"); #endif * continue; * } * * object fieldValue = field.GetValue(value); * if (this.IsDefaultValue(field, fieldValue)) { #if DEBUG * if (Settings.DebugMode) * Console.WriteLine ("Cannot serialize "+field.Name+" : is default value"); #endif * continue; * } * * if (appendDelim) * { * this.WriteObjectPropertyDelim(); * this.WriteLine(); * } else * { * appendDelim = true; * } * * // use Attributes here to control naming * string fieldName = JsonNameAttribute.GetJsonName(field); * if (String.IsNullOrEmpty(fieldName)) * fieldName = field.Name; * * this.WriteObjectProperty(fieldName, fieldValue, field.FieldType); * }*/ } finally { this.depth--; } if (appendDelim) { this.WriteLine(); } this.Writer.Write(JsonReader.OperatorObjectEnd); }
private static bool IsNullable(Type type) { return(TCU.GetTypeInfo(type).IsGenericType&& (typeof(Nullable <>).Equals(type.GetGenericTypeDefinition()))); }
private object CoerceList(Type targetType, Type arrayType, IEnumerable value) { if (targetType.IsArray) { return(this.CoerceArray(targetType.GetElementType(), value)); } // targetType serializes as a JSON array but is not an array // assume is an ICollection / IEnumerable with AddRange, Add, // or custom Constructor with which we can populate it // many ICollection types take an IEnumerable or ICollection // as a constructor argument. look through constructors for // a compatible match. ConstructorInfo[] ctors = targetType.GetConstructors(); ConstructorInfo defaultCtor = null; foreach (ConstructorInfo ctor in ctors) { ParameterInfo[] paramList = ctor.GetParameters(); if (paramList.Length == 0) { // save for in case cannot find closer match defaultCtor = ctor; continue; } if (paramList.Length == 1 && TCU.GetTypeInfo(paramList[0].ParameterType).IsAssignableFrom(TCU.GetTypeInfo(arrayType))) { try { // invoke first constructor that can take this value as an argument return(ctor.Invoke( new object[] { value } )); } catch { // there might exist a better match continue; } } } if (ConstructorInfo.Equals(defaultCtor, null)) { throw new JsonTypeCoercionException( String.Format(TypeCoercionUtility.ErrorDefaultCtor, new System.Object[] { targetType.FullName })); } object collection; try { // always try-catch Invoke() to expose real exception collection = defaultCtor.Invoke(null); } catch (TargetInvocationException ex) { if (ex.InnerException != null) { throw new JsonTypeCoercionException(ex.InnerException.Message, ex.InnerException); } throw new JsonTypeCoercionException("Error instantiating " + targetType.FullName, ex); } // many ICollection types have an AddRange method // which adds all items at once #if WINDOWS_STORE /** \todo Not sure if this finds the correct methods */ MethodInfo method = TCU.GetTypeInfo(targetType).GetDeclaredMethod("AddRange"); #else MethodInfo method = TCU.GetTypeInfo(targetType).GetMethod("AddRange"); #endif ParameterInfo[] parameters = (MethodInfo.Equals(method, null)) ? null : method.GetParameters(); Type paramType = (parameters == null || parameters.Length != 1) ? null : parameters[0].ParameterType; if (!Type.Equals(paramType, null) && TCU.GetTypeInfo(paramType).IsAssignableFrom(TCU.GetTypeInfo(arrayType))) { try { // always try-catch Invoke() to expose real exception // add all members in one method method.Invoke( collection, new object[] { value }); } catch (TargetInvocationException ex) { if (ex.InnerException != null) { throw new JsonTypeCoercionException(ex.InnerException.Message, ex.InnerException); } throw new JsonTypeCoercionException("Error calling AddRange on " + targetType.FullName, ex); } return(collection); } else { // many ICollection types have an Add method // which adds items one at a time #if WINDOWS_STORE /** \todo Not sure if this finds the correct methods */ method = TCU.GetTypeInfo(targetType).GetDeclaredMethod("Add"); #else method = TCU.GetTypeInfo(targetType).GetMethod("Add"); #endif parameters = (MethodInfo.Equals(method, null)) ? null : method.GetParameters(); paramType = (parameters == null || parameters.Length != 1) ? null : parameters[0].ParameterType; if (!Type.Equals(paramType, null)) { // loop through adding items to collection foreach (object item in value) { try { // always try-catch Invoke() to expose real exception method.Invoke( collection, new object[] { this.CoerceType(paramType, item) }); } catch (TargetInvocationException ex) { if (ex.InnerException != null) { throw new JsonTypeCoercionException(ex.InnerException.Message, ex.InnerException); } throw new JsonTypeCoercionException("Error calling Add on " + targetType.FullName, ex); } } return(collection); } } try { // fall back to basics return(Convert.ChangeType(value, targetType)); } catch (Exception ex) { throw new JsonTypeCoercionException(String.Format("Error converting {0} to {1}", new System.Object[] { value.GetType().FullName, targetType.FullName }), ex); } }
internal object CoerceType(Type targetType, object value) { bool isNullable = TypeCoercionUtility.IsNullable(targetType); if (value == null) { if (!allowNullValueTypes && TCU.GetTypeInfo(targetType).IsValueType&& !isNullable) { throw new JsonTypeCoercionException(String.Format(TypeCoercionUtility.ErrorNullValueType, new System.Object[] { targetType.FullName })); } return(value); } if (isNullable) { // nullable types have a real underlying struct Type[] genericArgs = targetType.GetGenericArguments(); if (genericArgs.Length == 1) { targetType = genericArgs[0]; } } Type actualType = value.GetType(); if (TCU.GetTypeInfo(targetType).IsAssignableFrom(TCU.GetTypeInfo(actualType))) { return(value); } if (TCU.GetTypeInfo(targetType).IsEnum) { if (value is String) { if (!Enum.IsDefined(targetType, value)) { // if isn't a defined value perhaps it is the JsonName foreach (FieldInfo field in TCU.GetTypeInfo(targetType).GetFields()) { string jsonName = JsonNameAttribute.GetJsonName(field); if (((string)value).Equals(jsonName)) { value = field.Name; break; } } } return(Enum.Parse(targetType, (string)value)); } else { value = this.CoerceType(Enum.GetUnderlyingType(targetType), value); return(Enum.ToObject(targetType, value)); } } // Value is of the wrong type and it has been deserialized as an IDictionary. // Previously coercion was supported // but this generally just caused more problems than it solved, so type hints are recommended now. // More specifically this can cause annoying problems with tags when a tag is referencing some object // for which there is no type info for (e.g the field has been removed), that data would have been // deserialized as an IDictionary, but when the tag gets the information it will try to coerce it // which will often fail horribly if (value is IDictionary) { return(null); // Dictionary<string, MemberInfo> memberMap; // return this.CoerceType(targetType, (IDictionary)value, out memberMap); } if (TCU.GetTypeInfo(typeof(IEnumerable)).IsAssignableFrom(TCU.GetTypeInfo(targetType)) && TCU.GetTypeInfo(typeof(IEnumerable)).IsAssignableFrom(TCU.GetTypeInfo(actualType))) { return(this.CoerceList(targetType, actualType, (IEnumerable)value)); } if (value is String) { if (Type.Equals(targetType, typeof(DateTime))) { DateTime date; if (DateTime.TryParse( (string)value, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.RoundtripKind | DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.NoCurrentDateDefault, out date)) { return(date); } } else if (Type.Equals(targetType, typeof(Guid))) { // try-catch is pointless since will throw upon generic conversion return(new Guid((string)value)); } else if (Type.Equals(targetType, typeof(Char))) { if (((string)value).Length == 1) { return(((string)value)[0]); } } else if (Equals(targetType, typeof(Uri))) { Uri uri; if (Uri.TryCreate((string)value, UriKind.RelativeOrAbsolute, out uri)) { return(uri); } } else if (Type.Equals(targetType, typeof(Version))) { // try-catch is pointless since will throw upon generic conversion return(new Version((string)value)); } } else if (Type.Equals(targetType, typeof(TimeSpan))) { return(new TimeSpan((long)this.CoerceType(typeof(Int64), value))); } #if !WINPHONE_8 TypeConverter converter = TypeDescriptor.GetConverter(targetType); if (converter.CanConvertFrom(actualType)) { return(converter.ConvertFrom(value)); } converter = TypeDescriptor.GetConverter(actualType); if (converter.CanConvertTo(targetType)) { return(converter.ConvertTo(value, targetType)); } #endif try { // fall back to basics return(Convert.ChangeType(value, targetType)); } catch (Exception ex) { throw new JsonTypeCoercionException( String.Format("Error converting {0} to {1}", new System.Object[] { value.GetType().FullName, targetType.FullName }), ex); } }
/** Creates a member map for the type */ private Dictionary <string, MemberInfo> CreateMemberMap(Type objectType) { Dictionary <string, MemberInfo> memberMap; if (this.MemberMapCache.TryGetValue(objectType, out memberMap)) { // map was stored in cache return(memberMap); } // create a new map memberMap = new Dictionary <string, MemberInfo>(); // load properties into property map Type tp = objectType; while (tp != null) { PropertyInfo[] properties = TCU.GetTypeInfo(tp).GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); for (int i = 0; i < properties.Length; i++) { PropertyInfo info = properties [i]; if (!info.CanRead || !info.CanWrite) { continue; } if (JsonIgnoreAttribute.IsJsonIgnore(info)) { continue; } string jsonName = JsonNameAttribute.GetJsonName(info); if (String.IsNullOrEmpty(jsonName)) { memberMap[info.Name] = info; } else { memberMap[jsonName] = info; } } // load public fields into property map FieldInfo[] fields = TCU.GetTypeInfo(tp).GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); foreach (FieldInfo info in fields) { if (!info.IsPublic && #if WINDOWS_STORE info.GetCustomAttribute <JsonMemberAttribute>(false) == null #else info.GetCustomAttributes(typeof(JsonMemberAttribute), false).Length == 0 #endif ) { continue; } if (JsonIgnoreAttribute.IsJsonIgnore(info)) { continue; } string jsonName = JsonNameAttribute.GetJsonName(info); if (String.IsNullOrEmpty(jsonName)) { memberMap[info.Name] = info; } else { memberMap[jsonName] = info; } var formerlySerializedAs = info.GetCustomAttributes(typeof(JsonFormerlySerializedAsAttribute), true); if (formerlySerializedAs.Length > 0) { var formerName = (formerlySerializedAs [0] as JsonFormerlySerializedAsAttribute).name; if (!String.IsNullOrEmpty(formerName) && !memberMap.ContainsKey(formerName)) { memberMap [formerName] = info; } } } tp = tp.BaseType; } // store in cache for repeated usage this.MemberMapCache[objectType] = memberMap; return(memberMap); }
internal object CoerceType(Type targetType, object value) { bool isNullable = TypeCoercionUtility.IsNullable(targetType); if (value == null) { if (!allowNullValueTypes && TCU.GetTypeInfo(targetType).IsValueType&& !isNullable) { throw new JsonTypeCoercionException(String.Format(TypeCoercionUtility.ErrorNullValueType, new System.Object[] { targetType.FullName })); } return(value); } if (isNullable) { // nullable types have a real underlying struct Type[] genericArgs = targetType.GetGenericArguments(); if (genericArgs.Length == 1) { targetType = genericArgs[0]; } } Type actualType = value.GetType(); if (TCU.GetTypeInfo(targetType).IsAssignableFrom(TCU.GetTypeInfo(actualType))) { return(value); } if (TCU.GetTypeInfo(targetType).IsEnum) { if (value is String) { if (!Enum.IsDefined(targetType, value)) { // if isn't a defined value perhaps it is the JsonName foreach (FieldInfo field in TCU.GetTypeInfo(targetType).GetFields()) { string jsonName = JsonNameAttribute.GetJsonName(field); if (((string)value).Equals(jsonName)) { value = field.Name; break; } } } return(Enum.Parse(targetType, (string)value)); } else { value = this.CoerceType(Enum.GetUnderlyingType(targetType), value); return(Enum.ToObject(targetType, value)); } } if (value is IDictionary) { Dictionary <string, MemberInfo> memberMap; return(this.CoerceType(targetType, (IDictionary)value, out memberMap)); } if (TCU.GetTypeInfo(typeof(IEnumerable)).IsAssignableFrom(TCU.GetTypeInfo(targetType)) && TCU.GetTypeInfo(typeof(IEnumerable)).IsAssignableFrom(TCU.GetTypeInfo(actualType))) { return(this.CoerceList(targetType, actualType, (IEnumerable)value)); } if (value is String) { if (Type.Equals(targetType, typeof(DateTime))) { DateTime date; if (DateTime.TryParse( (string)value, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.RoundtripKind | DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.NoCurrentDateDefault, out date)) { return(date); } } else if (Type.Equals(targetType, typeof(Guid))) { // try-catch is pointless since will throw upon generic conversion return(new Guid((string)value)); } else if (Type.Equals(targetType, typeof(Char))) { if (((string)value).Length == 1) { return(((string)value)[0]); } } else if (Equals(targetType, typeof(Uri))) { Uri uri; if (Uri.TryCreate((string)value, UriKind.RelativeOrAbsolute, out uri)) { return(uri); } } else if (Type.Equals(targetType, typeof(Version))) { // try-catch is pointless since will throw upon generic conversion return(new Version((string)value)); } } else if (Type.Equals(targetType, typeof(TimeSpan))) { return(new TimeSpan((long)this.CoerceType(typeof(Int64), value))); } #if !WINPHONE_8 TypeConverter converter = TypeDescriptor.GetConverter(targetType); if (converter.CanConvertFrom(actualType)) { return(converter.ConvertFrom(value)); } converter = TypeDescriptor.GetConverter(actualType); if (converter.CanConvertTo(targetType)) { return(converter.ConvertTo(value, targetType)); } #endif try { // fall back to basics return(Convert.ChangeType(value, targetType)); } catch (Exception ex) { throw new JsonTypeCoercionException( String.Format("Error converting {0} to {1}", new System.Object[] { value.GetType().FullName, targetType.FullName }), ex); } }