diff --git a/README.md b/README.md index f3c5ffc..73ebe6f 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ Install-Package SimpleJson * Windows Phone 7.1 (Mango) * Windows Phone 8 * Portable Class Libraries (PCL) +* Unity **Note:** By default SimpleJson expects `System.Linq`. If you are targeting older version of .NET framework (.net < 3.0 or WP7.0) you will need to add `#define SIMPLE_JSON_NO_LINQ_EXPRESSION`. diff --git a/src/SimpleJson.sln b/src/SimpleJson.sln index f7eaf8f..27c883d 100644 --- a/src/SimpleJson.sln +++ b/src/SimpleJson.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 -VisualStudioVersion = 12.0.20827.3 +VisualStudioVersion = 12.0.31101.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{AEDAD4B4-9F2C-4992-8CD6-A43DFDFF7172}" EndProject @@ -42,6 +42,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimleJson.Tests-WindowsStor EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleJson-Portable-WP8WinStoreNet45", "SimpleJson\SimpleJson-Portable-WP8WinStoreNet45.csproj", "{EC52A094-1CDB-4F5D-8A8A-86F501FC601C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleJson-Unity", "SimpleJson\SimpleJson-Unity.csproj", "{B6DF8C2D-A8F8-4FDB-B0E5-DFEEAA76CFE6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -288,6 +290,20 @@ Global {EC52A094-1CDB-4F5D-8A8A-86F501FC601C}.Release|Mixed Platforms.Build.0 = Release|Any CPU {EC52A094-1CDB-4F5D-8A8A-86F501FC601C}.Release|x64.ActiveCfg = Release|Any CPU {EC52A094-1CDB-4F5D-8A8A-86F501FC601C}.Release|x86.ActiveCfg = Release|Any CPU + {B6DF8C2D-A8F8-4FDB-B0E5-DFEEAA76CFE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B6DF8C2D-A8F8-4FDB-B0E5-DFEEAA76CFE6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B6DF8C2D-A8F8-4FDB-B0E5-DFEEAA76CFE6}.Debug|ARM.ActiveCfg = Debug|Any CPU + {B6DF8C2D-A8F8-4FDB-B0E5-DFEEAA76CFE6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {B6DF8C2D-A8F8-4FDB-B0E5-DFEEAA76CFE6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {B6DF8C2D-A8F8-4FDB-B0E5-DFEEAA76CFE6}.Debug|x64.ActiveCfg = Debug|Any CPU + {B6DF8C2D-A8F8-4FDB-B0E5-DFEEAA76CFE6}.Debug|x86.ActiveCfg = Debug|Any CPU + {B6DF8C2D-A8F8-4FDB-B0E5-DFEEAA76CFE6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B6DF8C2D-A8F8-4FDB-B0E5-DFEEAA76CFE6}.Release|Any CPU.Build.0 = Release|Any CPU + {B6DF8C2D-A8F8-4FDB-B0E5-DFEEAA76CFE6}.Release|ARM.ActiveCfg = Release|Any CPU + {B6DF8C2D-A8F8-4FDB-B0E5-DFEEAA76CFE6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {B6DF8C2D-A8F8-4FDB-B0E5-DFEEAA76CFE6}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {B6DF8C2D-A8F8-4FDB-B0E5-DFEEAA76CFE6}.Release|x64.ActiveCfg = Release|Any CPU + {B6DF8C2D-A8F8-4FDB-B0E5-DFEEAA76CFE6}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/SimpleJson/SimpleJson-Unity.csproj b/src/SimpleJson/SimpleJson-Unity.csproj new file mode 100644 index 0000000..323b575 --- /dev/null +++ b/src/SimpleJson/SimpleJson-Unity.csproj @@ -0,0 +1,49 @@ + + + + + Debug + AnyCPU + {B6DF8C2D-A8F8-4FDB-B0E5-DFEEAA76CFE6} + Library + Properties + SimpleJson + SimpleJson + v3.5 + 512 + + + + true + full + false + ..\..\bin\Unity\Debug\ + TRACE;DEBUG;SIMPLE_JSON_NO_LINQ_EXPRESSION;SIMPLE_JSON_DATACONTRACT; + prompt + 4 + + + pdbonly + true + ..\..\bin\Unity\Release\ + TRACE;SIMPLE_JSON_NO_LINQ_EXPRESSION;SIMPLE_JSON_DATACONTRACT; + prompt + 4 + + + + + + + + + + + + \ No newline at end of file diff --git a/src/SimpleJson/SimpleJson.cs b/src/SimpleJson/SimpleJson.cs index 2ab9742..e15e653 100644 --- a/src/SimpleJson/SimpleJson.cs +++ b/src/SimpleJson/SimpleJson.cs @@ -579,7 +579,25 @@ public static object DeserializeObject(string json, Type type, IJsonSerializerSt ? jsonObject : (jsonSerializerStrategy ?? CurrentJsonSerializerStrategy).DeserializeObject(jsonObject, type); } - +#if SIMPLE_JSON_NO_LINQ_EXPRESSION + public static object DeserializeObject(ref object target,string json, Type type, IJsonSerializerStrategy jsonSerializerStrategy) + { + object jsonObject = DeserializeObject(json); + return type == null || jsonObject != null && ReflectionUtils.IsAssignableFrom(jsonObject.GetType(), type) + ? jsonObject + : (jsonSerializerStrategy ?? CurrentJsonSerializerStrategy).DeserializeObject(ref target, jsonObject, + type); + } +#else + public static object DeserializeObject(object target, string json, Type type, IJsonSerializerStrategy jsonSerializerStrategy) + { + object jsonObject = DeserializeObject(json); + return type == null || jsonObject != null && ReflectionUtils.IsAssignableFrom(jsonObject.GetType(), type) + ? jsonObject + : (jsonSerializerStrategy ?? CurrentJsonSerializerStrategy).DeserializeObject(target, jsonObject, + type); + } +#endif public static object DeserializeObject(string json, Type type) { return DeserializeObject(json, type, null); @@ -594,7 +612,14 @@ public static T DeserializeObject(string json) { return (T)DeserializeObject(json, typeof(T), null); } - + public static T DeserializeObject(object target,string json) + { +#if SIMPLE_JSON_NO_LINQ_EXPRESSION + return (T)DeserializeObject(ref target, json, typeof(T), null); +#else + return (T)DeserializeObject(target, json, typeof(T), null); +#endif + } /// /// Converts a IDictionary<string,object> / IList<object> object into a JSON string /// @@ -613,6 +638,20 @@ public static string SerializeObject(object json) return SerializeObject(json, CurrentJsonSerializerStrategy); } + /// + /// ±ÜÃâ¶ÑÄÚ´æ·ÖÅäµÄ½âÎö·½Ê½ + /// Modify By ZhangMinglin + /// + public static StringBuilder SerializeObject(object json, StringBuilder builder) + { + if (builder == null) + { + return null; + } + bool success = SerializeValue(CurrentJsonSerializerStrategy, json, builder); + return (success ? builder : null); + } + public static string EscapeToJavascriptString(string jsonString) { if (string.IsNullOrEmpty(jsonString)) @@ -786,9 +825,26 @@ static object ParseValue(char[] json, ref int index, ref bool success) return null; } + [ThreadStatic] + static StringBuilder tempStringBuilder; static string ParseString(char[] json, ref int index, ref bool success) { - StringBuilder s = new StringBuilder(BUILDER_CAPACITY); + ///ÐÞ¸ÄΪʹÓÃÒ»¸ö¾²Ì¬»º´æStringBuilder,¼õÉÙ¶ÑÄÚ´æ·ÖÅ䣬²»¹ý´Ë´¦»áÒýÆðÒ»¸ö³¤×¤µÄ¶ÑÄÚ´æ + ///Modify by ZhangMinglin + /// + /// Old: + ///StringBuilder s = new StringBuilder(BUILDER_CAPACITY); + /// Now: + if(tempStringBuilder == null) + { + tempStringBuilder = new StringBuilder(BUILDER_CAPACITY); + } + else + { + tempStringBuilder.Length = 0; + } + StringBuilder s = tempStringBuilder; + char c; EatWhitespace(json, ref index); @@ -907,9 +963,18 @@ static object ParseNumber(char[] json, ref int index, ref bool success) } else { + //Modify by xtqqksszml@163.com + //Support uint, ulong long number; success = long.TryParse(new string(json, index, charLength), NumberStyles.Any, CultureInfo.InvariantCulture, out number); - returnNumber = number; + if (success) + returnNumber = number; + else + { + ulong unsign_number; + success = ulong.TryParse(str, NumberStyles.Any, CultureInfo.InvariantCulture, out unsign_number); + returnNumber = unsign_number; + } } index = lastIndex + 1; return returnNumber; @@ -1234,6 +1299,12 @@ interface IJsonSerializerStrategy [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification="Need to support .NET 2")] bool TrySerializeNonPrimitiveObject(object input, out object output); object DeserializeObject(object value, Type type); +#if SIMPLE_JSON_NO_LINQ_EXPRESSION + object DeserializeObject(ref object target, object value, Type type); +#else + object DeserializeObject(object target,object value, Type type); +#endif + } [GeneratedCode("simple-json", "1.0.0")] @@ -1379,14 +1450,17 @@ public virtual object DeserializeObject(object value, Type type) } else if (value is bool) return value; - + + //Modify by xtqqksszml@163.com + //Support uint, ulong bool valueIsLong = value is long; + bool valueIsULong = value is ulong; bool valueIsDouble = value is double; - if ((valueIsLong && type == typeof(long)) || (valueIsDouble && type == typeof(double))) + if ((valueIsLong && type == typeof(long)) || (valueIsDouble && type == typeof(double)) || (valueIsULong && type == typeof(ulong))) return value; - if ((valueIsDouble && type != typeof(double)) || (valueIsLong && type != typeof(long))) + if ((valueIsDouble && type != typeof(double)) || (valueIsLong && type != typeof(long)) || (valueIsULong && type != typeof(ulong))) { - obj = type == typeof(int) || type == typeof(long) || type == typeof(double) || type == typeof(float) || type == typeof(bool) || type == typeof(decimal) || type == typeof(byte) || type == typeof(short) + obj = type == typeof(int) || type == typeof(long) || type == typeof(uint) || type == typeof(ulong) || type == typeof(double) || type == typeof(float) || type == typeof(bool) || type == typeof(decimal) || type == typeof(byte) || type == typeof(short) ? Convert.ChangeType(value, type, CultureInfo.InvariantCulture) : value; } @@ -1408,8 +1482,10 @@ public virtual object DeserializeObject(object value, Type type) IDictionary dict = (IDictionary)ConstructorCache[genericType](); + // Modify by xtqqksszml@163.com + // Key support the other types foreach (KeyValuePair kvp in jsonObject) - dict.Add(kvp.Key, DeserializeObject(kvp.Value, valueType)); + dict.Add(DeserializeObject(kvp.Key, keyType), DeserializeObject(kvp.Value, valueType)); obj = dict; } @@ -1419,14 +1495,21 @@ public virtual object DeserializeObject(object value, Type type) obj = value; else { - obj = ConstructorCache[type](); + if(type.IsClass) + obj = ConstructorCache[type](); + else + obj = Activator.CreateInstance(type); foreach (KeyValuePair> setter in SetCache[type]) { object jsonValue; if (jsonObject.TryGetValue(setter.Key, out jsonValue)) { jsonValue = DeserializeObject(jsonValue, setter.Value.Key); +#if SIMPLE_JSON_NO_LINQ_EXPRESSION + setter.Value.Value(ref obj, jsonValue); +#else setter.Value.Value(obj, jsonValue); +#endif } } } @@ -1450,11 +1533,40 @@ public virtual object DeserializeObject(object value, Type type) else if (ReflectionUtils.IsTypeGenericeCollectionInterface(type) || ReflectionUtils.IsAssignableFrom(typeof(IList), type)) { Type innerType = ReflectionUtils.GetGenericListElementType(type); + //Modify by xtqqksszml@163.com +#if SIMPLE_JSON_NO_LINQ_EXPRESSION + list = (IList)(ConstructorCache[type] ?? ConstructorCache[typeof(List<>).MakeGenericType(innerType)])(); +#else list = (IList)(ConstructorCache[type] ?? ConstructorCache[typeof(List<>).MakeGenericType(innerType)])(jsonObject.Count); +#endif foreach (object o in jsonObject) list.Add(DeserializeObject(o, innerType)); } obj = list; + + //Modify by xtqqksszml@163.com + //Support Dictionary Formats([{"Key":?,"Value":?},]) + if (ReflectionUtils.IsTypeDictionary(type)) + { + Type[] types = ReflectionUtils.GetGenericTypeArguments(type); + Type keyType = types[0]; + Type valueType = types[1]; + + Type genericType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType); + + IDictionary dict = (IDictionary)ConstructorCache[genericType](); + + foreach (object o in jsonObject) + { + IDictionary element = o as IDictionary; + if (element != null) + { + dict.Add(DeserializeObject(element["Key"], keyType) + , DeserializeObject(element["Value"], valueType)); + } + } + obj = dict; + } } } return obj; @@ -1463,7 +1575,197 @@ public virtual object DeserializeObject(object value, Type type) return ReflectionUtils.ToNullableType(obj, type); return obj; } + [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] +#if SIMPLE_JSON_NO_LINQ_EXPRESSION + public virtual object DeserializeObject(ref object target, object value, Type type) +#else + public virtual object DeserializeObject(object target, object value, Type type) +#endif + { + if (type == null) throw new ArgumentNullException("type"); + string str = value as string; + + if (type == typeof(Guid) && string.IsNullOrEmpty(str)) + return default(Guid); + + if (value == null) + return null; + + object obj = null; + + if (str != null) + { + if (str.Length != 0) // We know it can't be null now. + { + if (type == typeof(DateTime) || (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(DateTime))) + return DateTime.ParseExact(str, Iso8601Format, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal); + if (type == typeof(DateTimeOffset) || (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(DateTimeOffset))) + return DateTimeOffset.ParseExact(str, Iso8601Format, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal); + if (type == typeof(Guid) || (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid))) + return new Guid(str); + if (type == typeof(Uri)) + { + bool isValid = Uri.IsWellFormedUriString(str, UriKind.RelativeOrAbsolute); + + Uri result; + if (isValid && Uri.TryCreate(str, UriKind.RelativeOrAbsolute, out result)) + return result; + + return null; + } + + if (type == typeof(string)) + return str; + + return Convert.ChangeType(str, type, CultureInfo.InvariantCulture); + } + else + { + if (type == typeof(Guid)) + obj = default(Guid); + else if (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid)) + obj = null; + else + obj = str; + } + // Empty string case + if (!ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid)) + return str; + } + else if (value is bool) + return value; + + //Modify by xtqqksszml@163.com + //Support uint, ulong + bool valueIsLong = value is long; + bool valueIsULong = value is ulong; + bool valueIsDouble = value is double; + if ((valueIsLong && type == typeof(long)) || (valueIsDouble && type == typeof(double)) || (valueIsULong && type == typeof(ulong))) + return value; + if ((valueIsDouble && type != typeof(double)) || (valueIsLong && type != typeof(long)) || (valueIsULong && type != typeof(ulong))) + { + obj = type == typeof(int) || type == typeof(long) || type == typeof(uint) || type == typeof(ulong) || type == typeof(double) || type == typeof(float) || type == typeof(bool) || type == typeof(decimal) || type == typeof(byte) || type == typeof(short) + ? Convert.ChangeType(value, type, CultureInfo.InvariantCulture) + : value; + } + else + { + IDictionary objects = value as IDictionary; + if (objects != null) + { + IDictionary jsonObject = objects; + + if (ReflectionUtils.IsTypeDictionary(type)) + { + // if dictionary then + Type[] types = ReflectionUtils.GetGenericTypeArguments(type); + Type keyType = types[0]; + Type valueType = types[1]; + + Type genericType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType); + + IDictionary dict = (IDictionary)ConstructorCache[genericType](); + + // Modify by xtqqksszml@163.com + // Key support the other types + foreach (KeyValuePair kvp in jsonObject) + dict.Add(DeserializeObject(kvp.Key, keyType), DeserializeObject(kvp.Value, valueType)); + + obj = dict; + } + else + { + if (type == typeof(object)) + obj = value; + else + { + + if (target.GetType() == type && target != null) + obj = target; + else + { + if (type.IsClass) + obj = ConstructorCache[type](); + else + obj = Activator.CreateInstance(type); + } + + foreach (KeyValuePair> setter in SetCache[type]) + { + object jsonValue; + if (jsonObject.TryGetValue(setter.Key, out jsonValue)) + { + jsonValue = DeserializeObject(jsonValue, setter.Value.Key); +#if SIMPLE_JSON_NO_LINQ_EXPRESSION + setter.Value.Value(ref obj, jsonValue); +#else + setter.Value.Value(obj, jsonValue); +#endif + } + } + } + } + } + else + { + IList valueAsList = value as IList; + if (valueAsList != null) + { + IList jsonObject = valueAsList; + IList list = null; + + if (type.IsArray) + { + list = (IList)ConstructorCache[type](jsonObject.Count); + int i = 0; + foreach (object o in jsonObject) + list[i++] = DeserializeObject(o, type.GetElementType()); + } + else if (ReflectionUtils.IsTypeGenericeCollectionInterface(type) || ReflectionUtils.IsAssignableFrom(typeof(IList), type)) + { + Type innerType = ReflectionUtils.GetGenericListElementType(type); + //Modify by xtqqksszml@163.com +#if SIMPLE_JSON_NO_LINQ_EXPRESSION + list = (IList)(ConstructorCache[type] ?? ConstructorCache[typeof(List<>).MakeGenericType(innerType)])(); +#else + list = (IList)(ConstructorCache[type] ?? ConstructorCache[typeof(List<>).MakeGenericType(innerType)])(jsonObject.Count); +#endif + foreach (object o in jsonObject) + list.Add(DeserializeObject(o, innerType)); + } + obj = list; + + //Modify by xtqqksszml@163.com + //Support Dictionary Formats([{"Key":?,"Value":?},]) + if (ReflectionUtils.IsTypeDictionary(type)) + { + Type[] types = ReflectionUtils.GetGenericTypeArguments(type); + Type keyType = types[0]; + Type valueType = types[1]; + + Type genericType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType); + IDictionary dict = (IDictionary)ConstructorCache[genericType](); + + foreach (object o in jsonObject) + { + IDictionary element = o as IDictionary; + if (element != null) + { + dict.Add(DeserializeObject(element["Key"], keyType) + , DeserializeObject(element["Value"], valueType)); + } + } + obj = dict; + } + } + } + return obj; + } + if (ReflectionUtils.IsNullableType(type)) + return ReflectionUtils.ToNullableType(obj, type); + return obj; + } protected virtual object SerializeEnum(Enum p) { return Convert.ToDouble(p, CultureInfo.InvariantCulture); @@ -1608,7 +1910,11 @@ class ReflectionUtils private static readonly object[] EmptyObjects = new object[] { }; public delegate object GetDelegate(object source); +#if SIMPLE_JSON_NO_LINQ_EXPRESSION + public delegate void SetDelegate(ref object source, object value); +#else public delegate void SetDelegate(object source, object value); +#endif public delegate object ConstructorDelegate(params object[] args); public delegate TValue ThreadSafeDictionaryValueFactory(TKey key); @@ -1941,12 +2247,21 @@ public static SetDelegate GetSetMethod(FieldInfo fieldInfo) public static SetDelegate GetSetMethodByReflection(PropertyInfo propertyInfo) { MethodInfo methodInfo = GetSetterMethodInfo(propertyInfo); - return delegate(object source, object value) { methodInfo.Invoke(source, new object[] { value }); }; +#if SIMPLE_JSON_NO_LINQ_EXPRESSION + return delegate (ref object source, object value) { methodInfo.Invoke(source, new object[] { value }); }; +#else + return delegate (object source, object value) { methodInfo.Invoke(source, new object[] { value }); }; +#endif } public static SetDelegate GetSetMethodByReflection(FieldInfo fieldInfo) { - return delegate(object source, object value) { fieldInfo.SetValue(source, value); }; +#if SIMPLE_JSON_NO_LINQ_EXPRESSION + return delegate (ref object source, object value) { fieldInfo.SetValue(source, value); }; +#else + return delegate (object source, object value) { fieldInfo.SetValue(source, value); }; +#endif + } #if !SIMPLE_JSON_NO_LINQ_EXPRESSION