From 6068b06744ec052ab60d3b5f26b9cad490206ef8 Mon Sep 17 00:00:00 2001 From: JamesNK Date: Fri, 27 Feb 2009 06:12:37 +0000 Subject: [PATCH] -Fix ToString(JsonConverter[]) overload on JToken -Ensure JavaScriptDateTimeConverter converts nullable DateTimes -Make JsonTypeReflector thread safe --- .../JsonSerializerTest.cs | 74 +++++++++++++++++++ Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs | 20 +++++ .../Converters/JavaScriptDateTimeConverter.cs | 4 +- Src/Newtonsoft.Json/Linq/JToken.cs | 4 +- .../Serialization/JsonTypeReflector.cs | 46 +++++++++--- 5 files changed, 134 insertions(+), 14 deletions(-) diff --git a/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs index e3e8b985..bf24d244 100644 --- a/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs @@ -1259,5 +1259,79 @@ keyword such as type of business."" String strFromTest = JsonConvert.SerializeObject(testClass); Test testFromDe = (Test)JsonConvert.DeserializeObject(strFromTest, typeof(Test)); } + + private Person GetPerson() + { + Person person = new Person + { + Name = "Mike Manager", + BirthDate = new DateTime(1983, 8, 3, 0, 0, 0, DateTimeKind.Utc), + Department = "IT", + LastModified = new DateTime(2009, 2, 15, 0, 0, 0, DateTimeKind.Utc) + }; + return person; + } + + //[Test] + public void WriteJsonToFile() + { + //Person person = GetPerson(); + + //string json = JsonConvert.SerializeObject(person, Formatting.Indented); + + //File.WriteAllText(@"c:\person.json", json); + + Person person = GetPerson(); + + using (FileStream fs = File.Open(@"c:\person.json", FileMode.CreateNew)) + using (StreamWriter sw = new StreamWriter(fs)) + using (JsonWriter jw = new JsonTextWriter(sw)) + { + jw.Formatting = Formatting.Indented; + + JsonSerializer serializer = new JsonSerializer(); + serializer.Serialize(jw, person); + } + } + + public class LogEntry + { + public string Details { get; set; } + public DateTime LogDate { get; set; } + } + + [Test] + public void WriteJsonDates() + { + LogEntry entry = new LogEntry + { + LogDate = new DateTime(2009, 2, 15, 0, 0, 0, DateTimeKind.Utc), + Details = "Application started." + }; + + string defaultJson = JsonConvert.SerializeObject(entry); + // {"Details":"Application started.","LogDate":"\/Date(1234656000000)\/"} + + string isoJson = JsonConvert.SerializeObject(entry, new IsoDateTimeConverter()); + // {"Details":"Application started.","LogDate":"2009-02-15T00:00:00.0000000Z"} + + string javascriptJson = JsonConvert.SerializeObject(entry, new JavaScriptDateTimeConverter()); + // {"Details":"Application started.","LogDate":new Date(1234656000000)} + + Console.WriteLine(defaultJson); + Console.WriteLine(isoJson); + Console.WriteLine(javascriptJson); + } + + public class SomeClass + { + public int? SomeProp { get; set; } + } + + [Test] + public void Main() + { + var pokes = JsonConvert.DeserializeObject(@"{""SomeProp"":1}"); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs index ecf8e0b9..776c34e3 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; +using Newtonsoft.Json.Converters; using NUnit.Framework; using Newtonsoft.Json.Linq; using System.IO; @@ -496,5 +497,24 @@ namespace Newtonsoft.Json.Tests.Linq Assert.IsTrue(JToken.DeepEquals(new JArray(int.MaxValue, new JArray("Test"), int.MaxValue, new JArray(1, 2, 3)), a)); } + + [Test] + public void ToStringWithConverters() + { + JArray a = + new JArray( + new JValue(new DateTime(2009, 2, 15, 0, 0, 0, DateTimeKind.Utc)) + ); + + string json = a.ToString(new IsoDateTimeConverter()); + + Assert.AreEqual(@"[ + ""2009-02-15T00:00:00.0000000Z"" +]", json); + + json = JsonConvert.SerializeObject(a, new IsoDateTimeConverter()); + + Assert.AreEqual(@"[""2009-02-15T00:00:00.0000000Z""]", json); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs index e5d438d0..9ac9588d 100644 --- a/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs @@ -95,9 +95,9 @@ namespace Newtonsoft.Json.Converters ? Nullable.GetUnderlyingType(objectType) : objectType; - if (typeof(DateTime).IsAssignableFrom(objectType)) + if (typeof(DateTime).IsAssignableFrom(t)) return true; - if (typeof(DateTimeOffset).IsAssignableFrom(objectType)) + if (typeof(DateTimeOffset).IsAssignableFrom(t)) return true; return false; diff --git a/Src/Newtonsoft.Json/Linq/JToken.cs b/Src/Newtonsoft.Json/Linq/JToken.cs index ff963b99..1b88c067 100644 --- a/Src/Newtonsoft.Json/Linq/JToken.cs +++ b/Src/Newtonsoft.Json/Linq/JToken.cs @@ -327,14 +327,14 @@ namespace Newtonsoft.Json.Linq /// /// A collection of which will be used when writing the token. /// - private string ToString(params JsonConverter[] converters) + public string ToString(params JsonConverter[] converters) { using (StringWriter sw = new StringWriter(CultureInfo.InvariantCulture)) { JsonTextWriter jw = new JsonTextWriter(sw); jw.Formatting = Formatting.Indented; - WriteTo(jw); + WriteTo(jw, converters); return sw.ToString(); } diff --git a/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs b/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs index 4a3bce08..41a2a8ee 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs @@ -47,10 +47,17 @@ namespace Newtonsoft.Json.Serialization if (TypeContainerAttributeCache.TryGetValue(type, out containerAttribute)) return containerAttribute; - containerAttribute = ReflectionUtils.GetAttribute(type); - TypeContainerAttributeCache[type] = containerAttribute; + // double check locking to avoid threading issues + lock (TypeContainerAttributeCache) + { + if (TypeContainerAttributeCache.TryGetValue(type, out containerAttribute)) + return containerAttribute; - return containerAttribute; + containerAttribute = ReflectionUtils.GetAttribute(type); + TypeContainerAttributeCache[type] = containerAttribute; + + return containerAttribute; + } } public static MemberSerialization GetObjectMemberSerialization(Type objectType) @@ -70,10 +77,17 @@ namespace Newtonsoft.Json.Serialization if (TypeMemberMappingsCache.TryGetValue(objectType, out memberMappings)) return memberMappings; - memberMappings = CreateMemberMappings(objectType); - TypeMemberMappingsCache[objectType] = memberMappings; + // double check locking to avoid threading issues + lock (TypeMemberMappingsCache) + { + if (TypeMemberMappingsCache.TryGetValue(objectType, out memberMappings)) + return memberMappings; - return memberMappings; + memberMappings = CreateMemberMappings(objectType); + TypeMemberMappingsCache[objectType] = memberMappings; + + return memberMappings; + } } public static JsonMemberMappingCollection CreateMemberMappings(Type objectType) @@ -116,19 +130,33 @@ namespace Newtonsoft.Json.Serialization return memberMappings; } - public static JsonConverter GetConverter(ICustomAttributeProvider attributeProvider, Type targetConvertedType) + private static Type GetConverterType(ICustomAttributeProvider attributeProvider) { Type converterType; - if (!ConverterTypeCache.TryGetValue(attributeProvider, out converterType)) + if (ConverterTypeCache.TryGetValue(attributeProvider, out converterType)) + return converterType; + + // double check locking to avoid threading issues + lock (ConverterTypeCache) { + if (ConverterTypeCache.TryGetValue(attributeProvider, out converterType)) + return converterType; + JsonConverterAttribute converterAttribute = ReflectionUtils.GetAttribute(attributeProvider, true); converterType = (converterAttribute != null) ? converterAttribute.ConverterType : null; ConverterTypeCache[attributeProvider] = converterType; + + return converterType; } + } + + public static JsonConverter GetConverter(ICustomAttributeProvider attributeProvider, Type targetConvertedType) + { + Type converterType = GetConverterType(attributeProvider); if (converterType != null) { @@ -143,8 +171,6 @@ namespace Newtonsoft.Json.Serialization return null; } - - public static List GetSerializableMembers(Type objectType) { return ReflectionUtils.GetFieldsAndProperties(objectType, BindingFlags.Public | BindingFlags.Instance);