diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj index 1d4cc07b..cd48bfe0 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj @@ -203,6 +203,7 @@ + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj index 7e43745e..a1684bfa 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj @@ -209,6 +209,7 @@ + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj index 4de04665..4bc8d118 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj @@ -214,6 +214,7 @@ + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj index 17695f7a..872f5b32 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj @@ -249,6 +249,7 @@ + diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs index 5c5a84f2..fa0e14f6 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs @@ -3506,5 +3506,32 @@ keyword such as type of business."" JsonConvert.DeserializeObject(json); } #endif + + [JsonObject(MemberSerialization.OptIn)] + public struct StructWithAttribute + { + public string MyString { get; set; } + [JsonProperty] + public int MyInt { get; set; } + } + + [Test] + public void SerializeStructWithJsonObjectAttribute() + { + StructWithAttribute testStruct = new StructWithAttribute + { + MyInt = int.MaxValue + }; + + string json = JsonConvert.SerializeObject(testStruct, Formatting.Indented); + + Assert.AreEqual(@"{ + ""MyInt"": 2147483647 +}", json); + + StructWithAttribute newStruct = JsonConvert.DeserializeObject(json); + + Assert.AreEqual(int.MaxValue, newStruct.MyInt); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Utilities/ReflectionUtilsTests.cs b/Src/Newtonsoft.Json.Tests/Utilities/ReflectionUtilsTests.cs new file mode 100644 index 00000000..9f17faf6 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Utilities/ReflectionUtilsTests.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization.Formatters; +using System.Text; +using NUnit.Framework; +using Newtonsoft.Json.Utilities; + +namespace Newtonsoft.Json.Tests.Utilities +{ + public class ReflectionUtilsTests : TestFixtureBase + { + [Test] + public void GetTypeNameSimpleForGenericTypes() + { + string typeName; + + typeName = ReflectionUtils.GetTypeName(typeof(IList), FormatterAssemblyStyle.Simple); + Assert.AreEqual("System.Collections.Generic.IList`1[[System.Type, mscorlib]], mscorlib", typeName); + + typeName = ReflectionUtils.GetTypeName(typeof(IDictionary, IList>), FormatterAssemblyStyle.Simple); + Assert.AreEqual("System.Collections.Generic.IDictionary`2[[System.Collections.Generic.IList`1[[System.Type, mscorlib]], mscorlib],[System.Collections.Generic.IList`1[[System.Type, mscorlib]], mscorlib]], mscorlib", typeName); + + typeName = ReflectionUtils.GetTypeName(typeof(IList<>), FormatterAssemblyStyle.Simple); + Assert.AreEqual("System.Collections.Generic.IList`1, mscorlib", typeName); + + typeName = ReflectionUtils.GetTypeName(typeof(IDictionary<,>), FormatterAssemblyStyle.Simple); + Assert.AreEqual("System.Collections.Generic.IDictionary`2, mscorlib", typeName); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonObjectAttribute.cs b/Src/Newtonsoft.Json/JsonObjectAttribute.cs index 42410324..6035009f 100644 --- a/Src/Newtonsoft.Json/JsonObjectAttribute.cs +++ b/Src/Newtonsoft.Json/JsonObjectAttribute.cs @@ -30,7 +30,7 @@ namespace Newtonsoft.Json /// /// Instructs the how to serialize the object. /// - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)] + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, AllowMultiple = false)] public sealed class JsonObjectAttribute : JsonContainerAttribute { private MemberSerialization _memberSerialization = MemberSerialization.OptOut; diff --git a/Src/Newtonsoft.Json/Linq/JProperty.cs b/Src/Newtonsoft.Json/Linq/JProperty.cs index 7996ed75..d1003888 100644 --- a/Src/Newtonsoft.Json/Linq/JProperty.cs +++ b/Src/Newtonsoft.Json/Linq/JProperty.cs @@ -161,10 +161,10 @@ namespace Newtonsoft.Json.Linq /// public override JEnumerable Children() { - return new JEnumerable(ChildrenInternal()); + return new JEnumerable(GetValueEnumerable()); } - private IEnumerable ChildrenInternal() + private IEnumerable GetValueEnumerable() { yield return Value; } diff --git a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs index 3d4a0ce6..682919dd 100644 --- a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs @@ -30,6 +30,8 @@ using System.Collections; using System.Linq; using System.Globalization; using System.Runtime.Serialization.Formatters; +using System.Text; +using System.Text.RegularExpressions; namespace Newtonsoft.Json.Utilities { @@ -45,7 +47,7 @@ namespace Newtonsoft.Json.Utilities switch (assemblyFormat) { case FormatterAssemblyStyle.Simple: - return t.FullName + ", " + t.Assembly.GetName().Name; + return GetSimpleTypeName(t); case FormatterAssemblyStyle.Full: return t.AssemblyQualifiedName; default: @@ -53,6 +55,55 @@ namespace Newtonsoft.Json.Utilities } } + private static string GetSimpleTypeName(Type type) + { + string fullyQualifiedTypeName = type.FullName + ", " + type.Assembly.GetName().Name; + + // for type names with no nested type names then return + if (!type.IsGenericType || type.IsGenericTypeDefinition) + return fullyQualifiedTypeName; + + StringBuilder builder = new StringBuilder(); + + // loop through the type name and filter out qualified assembly details from nested type names + bool writingAssemblyName = false; + bool skippingAssemblyDetails = false; + for (int i = 0; i < fullyQualifiedTypeName.Length; i++) + { + char current = fullyQualifiedTypeName[i]; + switch (current) + { + case '[': + writingAssemblyName = false; + skippingAssemblyDetails = false; + builder.Append(current); + break; + case ']': + writingAssemblyName = false; + skippingAssemblyDetails = false; + builder.Append(current); + break; + case ',': + if (!writingAssemblyName) + { + writingAssemblyName = true; + builder.Append(current); + } + else + { + skippingAssemblyDetails = true; + } + break; + default: + if (!skippingAssemblyDetails) + builder.Append(current); + break; + } + } + + return builder.ToString(); + } + public static bool IsInstantiatableType(Type t) { ValidationUtils.ArgumentNotNull(t, "t");