diff --git a/Src/Doc/AdvanceSerializingJSON.html b/Src/Doc/AdvanceSerializingJSON.html new file mode 100644 index 00000000..4db0a917 --- /dev/null +++ b/Src/Doc/AdvanceSerializingJSON.html @@ -0,0 +1,94 @@ + + + + Advanced JSON Serialization + + + + + + +
+ Json.NET - Quick Starts & API Documentation
+ Advanced JSON Serialization
+ +
+ + +

The Json.NET serializer has a number of advanced options to alter how JSON is serialized and deserialized.

+ +

IMappingResolver

+ +

The IMappingResolver interface provides a way to globally customize how the JsonSerializer maps JSON properties to .NET object members.

+

Implementing the IMappingResolver interface and then assigning an instance to a JsonSerializer lets you control what object members should be serialized, how they are serialized and what they are called.

+ +

DefaultMappingResolver

+

The DefaultMappingResolver is the default resolver used by the serializer. It provides many avenues of extensibility in the form of virtual methods that can be overriden.

+ +

CamelCaseMappingResolver

+

CamelCaseMappingResolver inherits from DefaultMappingResolver and simply overrides the JSON property name to be written in camelcase.

+ +
Product product = new Product
+ +
                    {
+ +
                      ExpiryDate = new DateTime(2010, 12, 20, 18, 1, 0, DateTimeKind.Utc),
+ +
                      Name = "Widget",
+ +
                      Price = 9.99m,
+ +
                      Sizes = new[] {"Small", "Medium", "Large"}
+ +
                    };
+ +
 
+ +
string json = 
+ +
  JsonConvert.SerializeObject(
+ +
    product,
+ +
    Formatting.Indented,
+ +
    new JsonSerializerSettings { MappingResolver = new CamelCaseMappingResolver() }
+ +
  );
+ +
 
+ +
//{
+ +
//  "name": "Widget",
+ +
//  "expiryDate": "\/Date(1292868060000)\/",
+ +
//  "price": 9.99,
+ +
//  "sizes": [
+ +
//    "Small",
+ +
//    "Medium",
+ +
//    "Large"
+ +
//  ]
+ +
//}
+
+
+
+ + + +
+ + + + \ No newline at end of file diff --git a/Src/Doc/DatesInJSON.html b/Src/Doc/DatesInJSON.html new file mode 100644 index 00000000..fab328c9 --- /dev/null +++ b/Src/Doc/DatesInJSON.html @@ -0,0 +1,94 @@ + + + + Serializing Dates in JSON + + + + + + +
+ Json.NET - Quick Starts & API Documentation
+ Serializing Dates in JSON
+ +
+ +

DateTimes in JSON are hard.

+

+ The problem comes from the JSON spec itself, there is no literal syntax for dates in JSON. The spec has objects, arrays, strings, integers and floats, but it defines no standard for what a date looks like.

+

The default format used by Json.NET for dates is the same one used by Microsoft: "\/Date(1198908717056)\/". You can read more about it here.

+ +

DateTime JsonConverters

+

With no standard for dates in JSON, the number of possible different formats when interoping with other systems is endless. Fortunately Json.NET has a solution to deal with reading and writing custom dates: JsonConverters. A JsonConverter is used to override how a type is serialized.

+ +
+
+
+
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 javascriptJson = JsonConvert.SerializeObject(entry, new JavaScriptDateTimeConverter());
+ +
  // {"Details":"Application started.","LogDate":new Date(1234656000000)}
+
 
+
  string isoJson = JsonConvert.SerializeObject(entry, new IsoDateTimeConverter());
+
  // {"Details":"Application started.","LogDate":"2009-02-15T00:00:00Z"}
+ +
}
+
+
+
+

Simply pass the JsonConverter you wish to use to the Json.NET serializer.

+

JavaScriptDateTimeConverter

+

The JavaScriptDateTimeConverter class is one of the two DateTime JsonConverters that come with Json.NET. This converter serializes a DateTime as a JavaScript Date object.

+
+
+
+
new Date(1234656000000)
+ +
+
+
+

Technically this is invalid JSON according to the spec but all browsers, and some JSON frameworks including Json.NET, support it.

+

IsoDateTimeConverter

+

IsoDateTimeConverter seralizes a DateTime to an ISO 8601 formatted string.

+
+
+
+
"2009-02-15T00:00:00Z"
+ +
+
+
+

The IsoDateTimeConverter class has a property, DateTimeFormat, to further customize the formatted string.

+

 

+

One final thing to note is all date values returned by Json.NET are in UTC time.

+ + + +
+ + + + \ No newline at end of file diff --git a/Src/Doc/ReadingWritingJSON.html b/Src/Doc/ReadingWritingJSON.html index 64bbbdd4..ad37cc32 100644 --- a/Src/Doc/ReadingWritingJSON.html +++ b/Src/Doc/ReadingWritingJSON.html @@ -15,7 +15,7 @@
-

To manually read and write JSON Json.NET provides the JsonWriter classes.

+

To manually read and write JSON Json.NET provides the JsonReader and JsonWriter classes.

JsonTextReader and JsonTextWriter

JsonTextReader and JsonTextWriter are used to read and write JSON text. The JsonTextWriter has a number of settings on it to control how JSON is formatted when it is written. These options include formatting, indention character, indent count and quote character.

@@ -60,7 +60,7 @@

JTokenReader and JTokenWriter

-

JTokenReader and JTokenWriter read and write LINQ to JSON objects. They are located in the Newtonsoft.Json.Linq namespace. These objects allow you to use LINQ to JSON objects with objects that read and write JSON such as the JsonSerializer. For example you can deserialize from a LINQ to JSON object into a regular .NET object and vice versa.

+

JTokenReader and JTokenWriter read and write LINQ to JSON objects. They are located in the Newtonsoft.Json.Linq namespace. These objects allow you to use LINQ to JSON objects with objects that read and write JSON such as the JsonSerializer. For example you can deserialize from a LINQ to JSON object into a regular .NET object and vice versa.

diff --git a/Src/Doc/SerializingJSON.html b/Src/Doc/SerializingJSON.html index 6ca109c9..75a70f22 100644 --- a/Src/Doc/SerializingJSON.html +++ b/Src/Doc/SerializingJSON.html @@ -46,7 +46,7 @@
//  ]
//}
 
-
Product deserializedProduct = (Product)JsonConvert.DeserializeObject(output, typeof(Product));
+
Product deserializedProduct = JsonConvert.DeserializeObject<Product>(output);
@@ -95,8 +95,14 @@ the member's DefaultValueAttribute. Include or ignore.

Converters

A collection of JsonConverters that will be used during serialization and deserialization.

+
TypeNameHandling
+

Controls how .NET type names are used when serializing and deserializing JSON. If + type names are SDFSDFSDF

Serialization Attributes

There are a number of attributes that can be placed on a class to control how it is serialized.

+

Note that as well as using the built-in Json.NET attributes, Json.NET also looks for the + DataContract and + DataMember attributes when determining how JSON is to be serialized and deserialized. If both are present the Json.NET serialization attributes take precedence.

@@ -144,17 +150,31 @@ finally any converters passed to the JsonSerializer.

-
IsoDateTimeConverter
-

Converts a DateTime to and from the ISO 8601 date format (e.g. 2008-04-12T12:53Z).

- -
JavaScriptDateTimeConverter
-

Converts a DateTime to and from a JavaScript date constructor (e.g. new Date(52231943)).

+
DateTime JSON Converters
+

Json.NET comes with a number of JsonConverters for serializing and deserializing DateTimes. Read + more about dates and Json.NET here.

XmlNodeConverter
-

Converts an XmlNode to and from JSON. Note that to convert a JSON object it must have only a single property. This is required because properties are converted into nodes and XML can only have one root node.

+

Converts an XmlNode to and from JSON. Note that to convert a JSON object it must have only a single property + or you must define a root node name to be inserted when using this converter. This is required because properties are converted into nodes and + well formed XML can only have one root node.

- +
BinaryConverter
+

Converts binary data like a byte array or SqlBinary object to JSON. The binary + data is encoded in Base64.

+ +
CustomCreationConverter
+

An abstract JsonConverter for customizing how an object is create during deserialization. + Inherit from this class and implement the Create method with your own code to create and return an object. + The object will then be populated with JSON values by the serializer.

+

A possible example of using this converter would be to call out to a dependency injection framework to resolve what object should be created

+ +
diff --git a/Src/Doc/doc.shfb b/Src/Doc/doc.shfb index cc8c1c9f..5508d344 100644 --- a/Src/Doc/doc.shfb +++ b/Src/Doc/doc.shfb @@ -16,6 +16,8 @@ + + Summary, Parameter, Returns, AutoDocumentCtors, Namespace, TypeParameter diff --git a/Src/Doc/doc.sitemap b/Src/Doc/doc.sitemap index b7ae69aa..2002607b 100644 --- a/Src/Doc/doc.sitemap +++ b/Src/Doc/doc.sitemap @@ -1,7 +1,10 @@  - + + + + - + \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs index 397e9261..3c007774 100644 --- a/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs @@ -2573,5 +2573,55 @@ keyword such as type of business."" Assert.AreEqual("Medium", deserializedProduct.Sizes[1]); Assert.AreEqual("Large", deserializedProduct.Sizes[2]); } + + [Test] + public void NestedInsideOuterObject() + { + string json = @"{ + ""short"": { + ""original"": ""http://www.contrast.ie/blog/online-marketing-2009/"", + ""short"": ""m2sqc6"", + ""shortened"": ""http://short.ie/m2sqc6"", + ""error"": { + ""code"": 0, + ""msg"": ""No action taken"" + } + } +}"; + + JObject o = JObject.Parse(json); + + Shortie s = JsonConvert.DeserializeObject(o["short"].ToString()); + Assert.IsNotNull(s); + + Assert.AreEqual(s.Original, "http://www.contrast.ie/blog/online-marketing-2009/"); + Assert.AreEqual(s.Short, "m2sqc6"); + Assert.AreEqual(s.Shortened, "http://short.ie/m2sqc6"); + } + + [Test] + public void UriSerialization() + { + Uri uri = new Uri("http://codeplex.com"); + string json = JsonConvert.SerializeObject(uri); + + Assert.AreEqual("http://codeplex.com/", uri.ToString()); + + Uri newUri = JsonConvert.DeserializeObject(json); + Assert.AreEqual(uri, newUri); + } + + [Test] + public void AnonymousPlusLinqToSql() + { + var value = new + { + bar = new JObject(new JProperty("baz", 13)) + }; + + string json = JsonConvert.SerializeObject(value); + + Assert.AreEqual(@"{""bar"":{""baz"":13}}", json); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs index ea437367..cf9c82ee 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs @@ -454,5 +454,37 @@ Parameter name: arrayIndex")] Console.WriteLine(name); Console.WriteLine(smallest); } + + [Test] + public void sdfs() + { + string jsonText = @"{ + ""short"":{ + ""original"":""http://www.foo.com/"", + ""short"":""krehqk"", + ""error"":{ + ""code"":0, + ""msg"":""No action taken""} + }"; + + JObject json = JObject.Parse(jsonText); + + Shortie shortie = new Shortie + { + Original = (string)json["short"]["original"], + Short = (string)json["short"]["short"], + Error = new ShortieException + { + Code = (int)json["short"]["error"]["code"], + ErrorMessage = (string)json["short"]["error"]["msg"] + } + }; + + Assert.AreEqual("http://www.foo.com/", shortie.Original); + Assert.AreEqual("krehqk", shortie.Short); + Assert.AreEqual(null, shortie.Shortened); + Assert.AreEqual(0, shortie.Error.Code); + Assert.AreEqual("No action taken", shortie.Error.ErrorMessage); + } } } diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj index a3b2a106..a137849b 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj @@ -110,6 +110,7 @@ + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj index 741733a7..c00a2b16 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj @@ -114,6 +114,7 @@ + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj index 1420f8b4..68a8f8ae 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj @@ -143,6 +143,7 @@ + diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/Shortie.cs b/Src/Newtonsoft.Json.Tests/TestObjects/Shortie.cs new file mode 100644 index 00000000..13aff870 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/Shortie.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Serialization; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + [XmlRoot("short")] + [JsonObject(MemberSerialization.OptIn)] + public class Shortie + { + [JsonProperty("original")] + [XmlElement("original")] + public String Original { get; set; } + + [JsonProperty("shortened")] + [XmlElement("shortened")] + public String Shortened { get; set; } + + [JsonProperty("short")] + [XmlElement("short")] + public String Short { get; set; } + + public ShortieException Error { get; set; } + } + + public class ShortieException + { + [JsonProperty("code")] + [XmlElement("code")] + public int Code { get; set; } + + [JsonProperty("msg")] + [XmlElement("msg")] + public String ErrorMessage { get; set; } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.sln b/Src/Newtonsoft.Json.sln index 9001fde4..984cdb5d 100644 --- a/Src/Newtonsoft.Json.sln +++ b/Src/Newtonsoft.Json.sln @@ -13,7 +13,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Newtonsoft.Json.Tests", "Ne EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Doc", "Doc", "{8F9E13D9-4181-4BA6-8802-EB5B3EB9445A}" ProjectSection(SolutionItems) = preProject + Doc\AdvanceSerializingJSON.html = Doc\AdvanceSerializingJSON.html Doc\custom.css = Doc\custom.css + Doc\DatesInJSON.html = Doc\DatesInJSON.html Doc\doc.shfb = Doc\doc.shfb Doc\doc.sitemap = Doc\doc.sitemap Doc\donate.gif = Doc\donate.gif diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj index 58c468c4..ac364524 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj @@ -135,6 +135,7 @@ + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj index 71ca0d8d..def157ff 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj @@ -113,6 +113,7 @@ + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj index 47cbbbe4..588350da 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj @@ -161,6 +161,7 @@ + diff --git a/Src/Newtonsoft.Json/Serialization/CachedAttributeGetter.cs b/Src/Newtonsoft.Json/Serialization/CachedAttributeGetter.cs index 38bc2a63..b51ca4a8 100644 --- a/Src/Newtonsoft.Json/Serialization/CachedAttributeGetter.cs +++ b/Src/Newtonsoft.Json/Serialization/CachedAttributeGetter.cs @@ -34,26 +34,11 @@ namespace Newtonsoft.Json.Serialization { internal static class CachedAttributeGetter where T : Attribute { - private static readonly Dictionary TypeAttributeCache = new Dictionary(); + private static readonly ThreadSafeDictionaryWrapper TypeAttributeCache = new ThreadSafeDictionaryWrapper(JsonTypeReflector.GetAttribute); public static T GetAttribute(ICustomAttributeProvider type) { - T attribute; - - if (TypeAttributeCache.TryGetValue(type, out attribute)) - return attribute; - - // double check locking to avoid threading issues - lock (TypeAttributeCache) - { - if (TypeAttributeCache.TryGetValue(type, out attribute)) - return attribute; - - attribute = JsonTypeReflector.GetAttribute(type); - TypeAttributeCache[type] = attribute; - - return attribute; - } + return TypeAttributeCache.Get(type); } } } diff --git a/Src/Newtonsoft.Json/Serialization/DefaultMappingResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultMappingResolver.cs index 39c61e06..4ef43d5b 100644 --- a/Src/Newtonsoft.Json/Serialization/DefaultMappingResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/DefaultMappingResolver.cs @@ -39,7 +39,7 @@ namespace Newtonsoft.Json.Serialization { internal static readonly IMappingResolver Instance = new DefaultMappingResolver(); - private readonly Dictionary _typeMemberMappingsCache = new Dictionary(); + private readonly ThreadSafeDictionaryWrapper _typeMemberMappingsCache; /// /// Gets or sets the default members search flags. @@ -53,6 +53,8 @@ namespace Newtonsoft.Json.Serialization public DefaultMappingResolver() { DefaultMembersSearchFlags = BindingFlags.Public | BindingFlags.Instance; + + _typeMemberMappingsCache = new ThreadSafeDictionaryWrapper(CreateMemberMappings); } /// @@ -63,22 +65,7 @@ namespace Newtonsoft.Json.Serialization /// A collection of to be used during serialization. public virtual JsonMemberMappingCollection ResolveMappings(Type type) { - JsonMemberMappingCollection memberMappings; - - if (_typeMemberMappingsCache.TryGetValue(type, out memberMappings)) - return memberMappings; - - // double check locking to avoid threading issues - lock (_typeMemberMappingsCache) - { - if (_typeMemberMappingsCache.TryGetValue(type, out memberMappings)) - return memberMappings; - - memberMappings = CreateMemberMappings(type); - _typeMemberMappingsCache[type] = memberMappings; - - return memberMappings; - } + return _typeMemberMappingsCache.Get(type); } /// diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerWriter.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerWriter.cs index 753af484..46ae8330 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerWriter.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerWriter.cs @@ -64,10 +64,7 @@ namespace Newtonsoft.Json.Serialization if (jsonWriter == null) throw new ArgumentNullException("jsonWriter"); - if (value is JToken) - ((JToken)value).WriteTo(jsonWriter, (_serializer.Converters != null) ? _serializer.Converters.ToArray() : null); - else - SerializeValue(jsonWriter, value, null); + SerializeValue(jsonWriter, value, null); } private JsonSerializerProxy GetInternalSerializer() @@ -96,6 +93,10 @@ namespace Newtonsoft.Json.Serialization { writer.WriteValue(value); } + else if (value is JToken) + { + ((JToken)value).WriteTo(writer, (_serializer.Converters != null) ? _serializer.Converters.ToArray() : null); + } else if (value is IList) { SerializeList(writer, (IList)value); @@ -224,7 +225,7 @@ namespace Newtonsoft.Json.Serialization } } #else - if (value is Guid || value is Type) + if (value is Guid || value is Type || value is Uri) { writer.WriteValue(value.ToString()); return; diff --git a/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs b/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs index aa3241d1..46097be7 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs @@ -43,8 +43,10 @@ namespace Newtonsoft.Json.Serialization public const string TypePropertyName = "$type"; public const string ArrayValuesPropertyName = "$values"; - private static readonly Dictionary ConverterTypeCache = new Dictionary(); - private static readonly Dictionary AssociatedMetadataTypesCache = new Dictionary(); + private static readonly ThreadSafeDictionaryWrapper ConverterTypeCache = new ThreadSafeDictionaryWrapper(GetConverterTypeFromAttribute); +#if !SILVERLIGHT && !PocketPC + private static readonly ThreadSafeDictionaryWrapper AssociatedMetadataTypesCache = new ThreadSafeDictionaryWrapper(GetAssociateMetadataTypeFromAttribute); +#endif public static JsonContainerAttribute GetJsonContainerAttribute(Type type) { @@ -79,26 +81,15 @@ namespace Newtonsoft.Json.Serialization private static Type GetConverterType(ICustomAttributeProvider attributeProvider) { - Type converterType; + return ConverterTypeCache.Get(attributeProvider); + } - 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 = GetAttribute(attributeProvider); - converterType = (converterAttribute != null) - ? converterAttribute.ConverterType - : null; - - ConverterTypeCache[attributeProvider] = converterType; - - return converterType; - } + private static Type GetConverterTypeFromAttribute(ICustomAttributeProvider attributeProvider) + { + JsonConverterAttribute converterAttribute = GetAttribute(attributeProvider); + return (converterAttribute != null) + ? converterAttribute.ConverterType + : null; } public static JsonConverter GetConverter(ICustomAttributeProvider attributeProvider, Type targetConvertedType) @@ -121,25 +112,14 @@ namespace Newtonsoft.Json.Serialization #if !SILVERLIGHT && !PocketPC private static Type GetAssociatedMetadataType(Type type) { - Type associatedMetadataType; + return AssociatedMetadataTypesCache.Get(type); + } - if (AssociatedMetadataTypesCache.TryGetValue(type, out associatedMetadataType)) - return associatedMetadataType; + private static Type GetAssociateMetadataTypeFromAttribute(Type type) + { + MetadataTypeAttribute metadataTypeAttribute = ReflectionUtils.GetAttribute(type, true); - // double check locking to avoid threading issues - lock (AssociatedMetadataTypesCache) - { - if (AssociatedMetadataTypesCache.TryGetValue(type, out associatedMetadataType)) - return associatedMetadataType; - - MetadataTypeAttribute metadataTypeAttribute = ReflectionUtils.GetAttribute(type, true); - if (metadataTypeAttribute != null) - associatedMetadataType = metadataTypeAttribute.MetadataClassType; - - AssociatedMetadataTypesCache[type] = associatedMetadataType; - - return associatedMetadataType; - } + return (metadataTypeAttribute != null) ? metadataTypeAttribute.MetadataClassType : null; } private static T GetAttribute(Type type) where T : Attribute diff --git a/Src/Newtonsoft.Json/Serialization/ThreadSafeDictionaryWrapper.cs b/Src/Newtonsoft.Json/Serialization/ThreadSafeDictionaryWrapper.cs new file mode 100644 index 00000000..651051be --- /dev/null +++ b/Src/Newtonsoft.Json/Serialization/ThreadSafeDictionaryWrapper.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Newtonsoft.Json.Utilities; + +namespace Newtonsoft.Json.Serialization +{ + internal class ThreadSafeDictionaryWrapper + { + private Dictionary _dictionary; + private readonly Func _creator; + + public ThreadSafeDictionaryWrapper(Func creator) + { + ValidationUtils.ArgumentNotNull(creator, "creator"); + + _creator = creator; + } + + private TValue AddValue(TKey key) + { + lock (this) + { + TValue value; + + if (_dictionary == null) + { + _dictionary = new Dictionary(); + value = _creator(key); + _dictionary[key] = value; + } + else + { + // double check locking + if (_dictionary.TryGetValue(key, out value)) + return value; + + Dictionary newDictionary = new Dictionary(_dictionary); + value = _creator(key); + newDictionary[key] = value; + + _dictionary = newDictionary; + } + + return value; + } + } + + public TValue Get(TKey key) + { + if (_dictionary == null) + return AddValue(key); + + TValue value; + if (!_dictionary.TryGetValue(key, out value)) + return AddValue(key); + + return value; + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs b/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs index 02b53ff2..9441fe2f 100644 --- a/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs @@ -164,8 +164,13 @@ namespace Newtonsoft.Json.Utilities if (initialValue is DateTime && targetType == typeof(DateTimeOffset)) return new DateTimeOffset((DateTime)initialValue); - if (initialValue is string && targetType == typeof(Guid)) - return new Guid((string)initialValue); + if (initialValue is string) + { + if (targetType == typeof(Guid)) + return new Guid((string)initialValue); + if (targetType == typeof(Uri)) + return new Uri((string) initialValue); + } #if !PocketPC // see if source or target types have a TypeConverter that converts between the two