-Added documentation (gasp!)

-Fixed serialization of Uri members on Silverlight/Compact Framework
-Fixed serialization of JToken members
-Fixed (hopefully) cache threading issues
This commit is contained in:
JamesNK
2009-06-16 09:50:59 +00:00
parent d160b9f587
commit 63160b04ff
22 changed files with 452 additions and 91 deletions
+94
View File
@@ -0,0 +1,94 @@
<html>
<head>
<title>Advanced JSON Serialization</title>
<link href="styles.css" rel="stylesheet" type="text/css" />
<link href="custom.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="control">
<span class="productTitle">Json.NET - Quick Starts & API Documentation</span><br />
<span class="topicTitle">Advanced JSON Serialization</span></div>
<div id="content">
<span style="color: DarkGray"> </span>
<p>The Json.NET serializer has a number of advanced options to alter how JSON is serialized and deserialized.</p>
<h3>IMappingResolver</h3>
<p>The <a href="./html/T_Newtonsoft_Json_Serialization_IMappingResolver.htm">IMappingResolver</a> interface provides a way to globally customize how the JsonSerializer maps JSON properties to .NET object members.</p>
<p>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.</p>
<h4>DefaultMappingResolver</h4>
<p>The <a href="./html/T_Newtonsoft_Json_Serialization_DefaultMappingResolver.htm">DefaultMappingResolver</a> is the default resolver used by the serializer. It provides many avenues of extensibility in the form of virtual methods that can be overriden.</p>
<h4>CamelCaseMappingResolver</h4>
<p><a href="./html/T_Newtonsoft_Json_Serialization_CamelCaseMappingResolver.htm">CamelCaseMappingResolver</a> inherits from DefaultMappingResolver and simply overrides the JSON property name to be written in <a href="http://en.wikipedia.org/wiki/CamelCase" target="_blank">camelcase</a>.</p>
<div class="overflowpanel"> <div class="code"> <div style="font-family: courier new; color: black; font-size: 10pt;"> <pre style="margin: 0px;"><span style="color: rgb(43, 145, 175);">Product</span> product = <span style="color: blue;">new</span> <span style="color: rgb(43, 145, 175);">Product</span></pre>
<pre style="margin: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</pre>
<pre style="margin: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ExpiryDate = <span style="color: blue;">new</span> <span style="color: rgb(43, 145, 175);">DateTime</span>(2010, 12, 20, 18, 1, 0, <span style="color: rgb(43, 145, 175);">DateTimeKind</span>.Utc),</pre>
<pre style="margin: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Name = <span style="color: rgb(163, 21, 21);">"Widget"</span>,</pre>
<pre style="margin: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Price = 9.99m,</pre>
<pre style="margin: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Sizes = <span style="color: blue;">new</span>[] {<span style="color: rgb(163, 21, 21);">"Small"</span>, <span style="color: rgb(163, 21, 21);">"Medium"</span>, <span style="color: rgb(163, 21, 21);">"Large"</span>}</pre>
<pre style="margin: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; };</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;"><span style="color: blue;">string</span> json = </pre>
<pre style="margin: 0px;">&nbsp; <span style="color: rgb(43, 145, 175);">JsonConvert</span>.SerializeObject(</pre>
<pre style="margin: 0px;">&nbsp;&nbsp;&nbsp; product,</pre>
<pre style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">Formatting</span>.Indented,</pre>
<pre style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">new</span> <span style="color: rgb(43, 145, 175);">JsonSerializerSettings</span> { MappingResolver = <span style="color: blue;">new</span> <span style="color: rgb(43, 145, 175);">CamelCaseMappingResolver</span>() }</pre>
<pre style="margin: 0px;">&nbsp; );</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;"><span style="color: green;">//{</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//&nbsp; "name": "Widget",</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//&nbsp; "expiryDate": "\/Date(1292868060000)\/",</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//&nbsp; "price": 9.99,</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//&nbsp; "sizes": [</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//&nbsp;&nbsp;&nbsp; "Small",</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//&nbsp;&nbsp;&nbsp; "Medium",</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//&nbsp;&nbsp;&nbsp; "Large"</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//&nbsp; ]</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//}</span></pre>
</div>
</div>
</div>
<div id="footer">
</div>
</div>
</body>
</html>
+94
View File
@@ -0,0 +1,94 @@
<html>
<head>
<title>Serializing Dates in JSON</title>
<link href="styles.css" rel="stylesheet" type="text/css" />
<link href="custom.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="control">
<span class="productTitle">Json.NET - Quick Starts & API Documentation</span><br />
<span class="topicTitle">Serializing Dates in JSON</span></div>
<div id="content">
<span style="color: DarkGray"> </span>
<p>DateTimes in JSON are hard.</p>
<p>
The problem comes from the <a href="http://www.ietf.org/rfc/rfc4627.txt" target="_blank">JSON spec</a> 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.</p>
<p>The default format used by <a href="http://james.newtonking.com/projects/json-net.aspx" target="_blank">Json.NET</a> for dates is the same one used by Microsoft: "\/Date(1198908717056)\/". You can read more about it <a href="http://weblogs.asp.net/bleroy/archive/2008/01/18/dates-and-json.aspx" target="_blank">here</a>.</p>
<h3>DateTime JsonConverters</h3>
<p>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.</p>
<div class="overflowpanel">
<div class="code">
<div style="font-size: 10pt; color: black; font-family: courier new;">
<pre style="margin: 0px;"><span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: rgb(43, 145, 175);">LogEntry</span></pre>
<pre style="margin: 0px;">{</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: blue;">public</span> <span style="color: blue;">string</span> Details { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: blue;">public</span> <span style="color: rgb(43, 145, 175);">DateTime</span> LogDate { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }</pre>
<pre style="margin: 0px;">}</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;">[<span style="color: rgb(43, 145, 175);">Test</span>]</pre>
<pre style="margin: 0px;"><span style="color: blue;">public</span> <span style="color: blue;">void</span> WriteJsonDates()</pre>
<pre style="margin: 0px;">{</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: rgb(43, 145, 175);">LogEntry</span> entry = <span style="color: blue;">new</span> <span style="color: rgb(43, 145, 175);">LogEntry</span></pre>
<pre style="margin: 0px;">&nbsp; {</pre>
<pre style="margin: 0px;">&nbsp;&nbsp;&nbsp; LogDate = <span style="color: blue;">new</span> <span style="color: rgb(43, 145, 175);">DateTime</span>(2009, 2, 15, 0, 0, 0, <span style="color: rgb(43, 145, 175);">DateTimeKind</span>.Utc),</pre>
<pre style="margin: 0px;">&nbsp;&nbsp;&nbsp; Details = <span style="color: rgb(163, 21, 21);">"Application started."</span></pre>
<pre style="margin: 0px;">&nbsp; };</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: blue;">string</span> defaultJson = <span style="color: rgb(43, 145, 175);">JsonConvert</span>.SerializeObject(entry);</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: green;">// {"Details":"Application started.","LogDate":"\/Date(1234656000000)\/"}</span></pre>
<pre style="margin: 0px;"></pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: blue;">string</span> javascriptJson = <span style="color: rgb(43, 145, 175);">JsonConvert</span>.SerializeObject(entry, <span style="color: blue;">new</span> <span style="color: rgb(43, 145, 175);">JavaScriptDateTimeConverter</span>());</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: green;">// {"Details":"Application started.","LogDate":new Date(1234656000000)}</span></pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: blue;">string</span> isoJson = <span style="color: rgb(43, 145, 175);">JsonConvert</span>.SerializeObject(entry, <span style="color: blue;">new</span> <span style="color: rgb(43, 145, 175);">IsoDateTimeConverter</span>());</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: green;">// {"Details":"Application started.","LogDate":"2009-02-15T00:00:00Z"}</span></pre>
<pre style="margin: 0px;">}</pre>
</div>
</div>
</div>
<p>Simply pass the JsonConverter you wish to use to the Json.NET serializer.</p>
<h4>JavaScriptDateTimeConverter</h4>
<p>The JavaScriptDateTimeConverter class is one of the two DateTime JsonConverters that come with Json.NET. This converter serializes a DateTime as a <a href="https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Date" target="_blank">JavaScript Date object</a>.</p>
<div class="overflowpanel">
<div class="code">
<div style="font-size: 10pt; color: black; font-family: courier new;">
<pre style="margin: 0px;">new Date(1234656000000)</pre>
</div>
</div>
</div>
<p>Technically this is invalid JSON according to the spec but all browsers, and some JSON frameworks including Json.NET, support it. </p>
<h4>IsoDateTimeConverter</h4>
<p>IsoDateTimeConverter seralizes a DateTime to an <a href="http://en.wikipedia.org/wiki/ISO_8601" target="_blank">ISO 8601</a> formatted string.</p>
<div class="overflowpanel">
<div class="code">
<div style="font-size: 10pt; color: black; font-family: courier new;">
<pre style="margin: 0px;"><span style="color: rgb(163, 21, 21);">"2009-02-15T00:00:00Z"</span></pre>
</div>
</div>
</div>
<p>The IsoDateTimeConverter class has a property, DateTimeFormat, to further customize the formatted string.</p>
<p>&nbsp;</p>
<p>One final thing to note is all date values returned by Json.NET are in <a href="http://en.wikipedia.org/wiki/Utc" target="_blank">UTC time</a>.</p>
<div id="footer"></div>
</div>
</body>
</html>
+2 -2
View File
@@ -15,7 +15,7 @@
<div id="content">
<span style="color: DarkGray"> </span>
<p>To manually read and write JSON Json.NET provides the <a href="./html/T_Newtonsoft_Json_JsonReader.htm>JsonReader</a> and <a href="./html/T_Newtonsoft_Json_JsonWriter.htm">JsonWriter</a> classes.</p>
<p>To manually read and write JSON Json.NET provides the <a href="./html/T_Newtonsoft_Json_JsonReader.htm">JsonReader</a> and <a href="./html/T_Newtonsoft_Json_JsonWriter.htm">JsonWriter</a> classes.</p>
<h3>JsonTextReader and JsonTextWriter</h3>
<p><a href="./html/T_Newtonsoft_Json_JsonTextReader.htm">JsonTextReader</a> and <a href="./html/T_Newtonsoft_Json_JsonTextWriter.htm">JsonTextWriter</a> 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.</p>
@@ -60,7 +60,7 @@
</div></div>
<h3>JTokenReader and JTokenWriter</h3>
<p><a href="./html/T_Newtonsoft_Json_JTokenReader.htm">JTokenReader</a> and <a href="./html/T_Newtonsoft_Json_JTokenWriter.htm">JTokenWriter</a> read and write LINQ to JSON objects. They are located in the <a href="./html/N_Newtonsoft_Json_Linq.htm">Newtonsoft.Json.Linq</a> 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.</p>
<p><a href="./html/T_Newtonsoft_Json_Linq_JTokenReader.htm">JTokenReader</a> and <a href="./html/T_Newtonsoft_Json_Linq_JTokenWriter.htm">JTokenWriter</a> read and write LINQ to JSON objects. They are located in the <a href="./html/N_Newtonsoft_Json_Linq.htm">Newtonsoft.Json.Linq</a> 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.</p>
<div class="overflowpanel"> <div class="code">
+28 -8
View File
@@ -46,7 +46,7 @@
<pre style="margin: 0px;"><span style="color: green;">//&nbsp; ]</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//}</span></pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;"><span style="color: #2b91af;">Product</span> deserializedProduct = (<span style="color: #2b91af;">Product</span>)<span style="color: #2b91af;">JsonConvert</span>.DeserializeObject(output, <span style="color: blue;">typeof</span>(<span style="color: #2b91af;">Product</span>));</pre>
<pre style="margin: 0px;"><span style="color: #2b91af;">Product</span> deserializedProduct = <span style="color: #2b91af;">JsonConvert</span>.DeserializeObject&lt;<span style="color: #2b91af;">Product</span>&gt;(output);</pre>
</div>
</div></div>
@@ -95,8 +95,14 @@ the member's DefaultValueAttribute. Include or ignore.</p>
<h5>Converters</h5>
<p>A collection of JsonConverters that will be used during serialization and
deserialization.</p>
<h5>TypeNameHandling</h5>
<p>Controls how .NET type names are used when serializing and deserializing JSON. If
type names are SDFSDFSDF</p>
<h3>Serialization Attributes</h3>
<p>There are a number of attributes that can be placed on a class to control how it is serialized.</p>
<p>Note that as well as using the built-in Json.NET attributes, Json.NET also looks for the
<a href="http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractattribute.aspx" target="_blank">DataContract</a> and
<a href="http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractattribute.aspx" target="_blank">DataMember</a> attributes when determining how JSON is to be serialized and deserialized. If both are present the Json.NET serialization attributes take precedence.</p>
<div class="overflowpanel"> <div class="code">
@@ -144,17 +150,31 @@ finally any converters passed to the JsonSerializer.</p>
<h5>IsoDateTimeConverter</h5>
<p>Converts a DateTime to and from the ISO 8601 date format (e.g. 2008-04-12T12:53Z).</p>
<h5>JavaScriptDateTimeConverter</h5>
<p>Converts a DateTime to and from a JavaScript date constructor (e.g. new Date(52231943)).</p>
<h5>DateTime JSON Converters</h5>
<p>Json.NET comes with a number of JsonConverters for serializing and deserializing DateTimes. Read
more about dates and Json.NET <a href="DatesInJSON.html">here</a>.</p>
<h5>XmlNodeConverter</h5>
<p>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.</p>
<p>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.</p>
<div id="footer"></div>
<h5>BinaryConverter</h5>
<p>Converts binary data like a byte array or SqlBinary object to JSON. The binary
data is encoded in Base64.</p>
<h5>CustomCreationConverter</h5>
<p>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.</p>
<p>A possible example of using this converter would be to call out to a dependency injection framework to resolve what object should be created</p>
<div id="footer">
</div>
</div>
</body>
+2
View File
@@ -16,6 +16,8 @@
<contentItem sourcePath=".\LINQtoJSON.html" destPath="" excludeItems="False" />
<contentItem sourcePath=".\ReadingWritingJSON.html" destPath="" excludeItems="False" />
<contentItem sourcePath=".\donate.gif" destPath="" excludeItems="False" />
<contentItem sourcePath=".\AdvanceSerializingJSON.html" destPath="" excludeItems="False" />
<contentItem sourcePath=".\DatesInJSON.html" destPath="" excludeItems="False" />
</additionalContent>
<ProjectSummary />
<MissingTags>Summary, Parameter, Returns, AutoDocumentCtors, Namespace, TypeParameter</MissingTags>
+5 -2
View File
@@ -1,7 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0">
<siteMapNode title="Introduction" url=".\Introduction.html" isDefault="true" />
<siteMapNode title="Serializing and deserializing JSON" url=".\SerializingJSON.html" />
<siteMapNode title="Serializing and deserializing JSON" url=".\SerializingJSON.html">
<siteMapNode title="Advanced JSON serialization" url=".\AdvanceSerializingJSON.html" />
<siteMapNode title="Serializing dates in JSON" url=".\DatesInJSON.html" />
</siteMapNode>
<siteMapNode title="LINQ to JSON" url=".\LINQtoJSON.html" />
<siteMapNode title="Reading and Writing JSON" url=".\ReadingWritingJSON.html" />
<siteMapNode title="Reading and writing JSON" url=".\ReadingWritingJSON.html" />
</siteMap>
@@ -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&#45;marketing&#45;2009/"",
""short"": ""m2sqc6"",
""shortened"": ""http://short.ie/m2sqc6"",
""error"": {
""code"": 0,
""msg"": ""No action taken""
}
}
}";
JObject o = JObject.Parse(json);
Shortie s = JsonConvert.DeserializeObject<Shortie>(o["short"].ToString());
Assert.IsNotNull(s);
Assert.AreEqual(s.Original, "http://www.contrast.ie/blog/online&#45;marketing&#45;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<Uri>(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);
}
}
}
@@ -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);
}
}
}
@@ -110,6 +110,7 @@
<Compile Include="TestObjects\Product.cs" />
<Compile Include="TestObjects\ProductCollection.cs" />
<Compile Include="TestObjects\ProductShort.cs" />
<Compile Include="TestObjects\Shortie.cs" />
<Compile Include="TestObjects\Store.cs" />
<Compile Include="TestObjects\StoreColor.cs" />
<Compile Include="TestObjects\Person.cs" />
@@ -114,6 +114,7 @@
<Compile Include="TestObjects\Product.cs" />
<Compile Include="TestObjects\ProductCollection.cs" />
<Compile Include="TestObjects\ProductShort.cs" />
<Compile Include="TestObjects\Shortie.cs" />
<Compile Include="TestObjects\Store.cs" />
<Compile Include="TestObjects\StoreColor.cs" />
<Compile Include="TestObjects\Person.cs" />
@@ -143,6 +143,7 @@
<Compile Include="TestObjects\Product.cs" />
<Compile Include="TestObjects\ProductCollection.cs" />
<Compile Include="TestObjects\ProductShort.cs" />
<Compile Include="TestObjects\Shortie.cs" />
<Compile Include="TestObjects\Store.cs" />
<Compile Include="TestObjects\StoreColor.cs" />
<Compile Include="TestObjects\Person.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; }
}
}
+2
View File
@@ -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
@@ -135,6 +135,7 @@
<Compile Include="Serialization\JsonSerializerReader.cs" />
<Compile Include="Serialization\JsonSerializerWriter.cs" />
<Compile Include="Serialization\JsonTypeReflector.cs" />
<Compile Include="Serialization\ThreadSafeDictionaryWrapper.cs" />
<Compile Include="TypeNameHandling.cs" />
<Compile Include="Utilities\BidirectionalDictionary.cs" />
<Compile Include="Utilities\ConvertUtils.cs" />
@@ -113,6 +113,7 @@
<Compile Include="Serialization\JsonSerializerProxy.cs" />
<Compile Include="Serialization\JsonSerializerReader.cs" />
<Compile Include="Serialization\JsonSerializerWriter.cs" />
<Compile Include="Serialization\ThreadSafeDictionaryWrapper.cs" />
<Compile Include="TypeNameHandling.cs" />
<Compile Include="Utilities\BidirectionalDictionary.cs" />
<Compile Include="Utilities\CollectionUtils.cs" />
@@ -161,6 +161,7 @@
<Compile Include="Serialization\JsonSerializerWriter.cs" />
<Compile Include="Serialization\JsonTypeReflector.cs" />
<Compile Include="Serialization\CachedAttributeGetter.cs" />
<Compile Include="Serialization\ThreadSafeDictionaryWrapper.cs" />
<Compile Include="TypeNameHandling.cs" />
<Compile Include="Utilities\BidirectionalDictionary.cs" />
<Compile Include="Utilities\ConvertUtils.cs" />
@@ -34,26 +34,11 @@ namespace Newtonsoft.Json.Serialization
{
internal static class CachedAttributeGetter<T> where T : Attribute
{
private static readonly Dictionary<ICustomAttributeProvider, T> TypeAttributeCache = new Dictionary<ICustomAttributeProvider, T>();
private static readonly ThreadSafeDictionaryWrapper<ICustomAttributeProvider, T> TypeAttributeCache = new ThreadSafeDictionaryWrapper<ICustomAttributeProvider, T>(JsonTypeReflector.GetAttribute<T>);
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<T>(type);
TypeAttributeCache[type] = attribute;
return attribute;
}
return TypeAttributeCache.Get(type);
}
}
}
@@ -39,7 +39,7 @@ namespace Newtonsoft.Json.Serialization
{
internal static readonly IMappingResolver Instance = new DefaultMappingResolver();
private readonly Dictionary<Type, JsonMemberMappingCollection> _typeMemberMappingsCache = new Dictionary<Type, JsonMemberMappingCollection>();
private readonly ThreadSafeDictionaryWrapper<Type, JsonMemberMappingCollection> _typeMemberMappingsCache;
/// <summary>
/// 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<Type, JsonMemberMappingCollection>(CreateMemberMappings);
}
/// <summary>
@@ -63,22 +65,7 @@ namespace Newtonsoft.Json.Serialization
/// <returns>A collection of <see cref="JsonMemberMapping"/> to be used during serialization.</returns>
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);
}
/// <summary>
@@ -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;
@@ -43,8 +43,10 @@ namespace Newtonsoft.Json.Serialization
public const string TypePropertyName = "$type";
public const string ArrayValuesPropertyName = "$values";
private static readonly Dictionary<ICustomAttributeProvider, Type> ConverterTypeCache = new Dictionary<ICustomAttributeProvider, Type>();
private static readonly Dictionary<Type, Type> AssociatedMetadataTypesCache = new Dictionary<Type, Type>();
private static readonly ThreadSafeDictionaryWrapper<ICustomAttributeProvider, Type> ConverterTypeCache = new ThreadSafeDictionaryWrapper<ICustomAttributeProvider, Type>(GetConverterTypeFromAttribute);
#if !SILVERLIGHT && !PocketPC
private static readonly ThreadSafeDictionaryWrapper<Type, Type> AssociatedMetadataTypesCache = new ThreadSafeDictionaryWrapper<Type, Type>(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<JsonConverterAttribute>(attributeProvider);
converterType = (converterAttribute != null)
? converterAttribute.ConverterType
: null;
ConverterTypeCache[attributeProvider] = converterType;
return converterType;
}
private static Type GetConverterTypeFromAttribute(ICustomAttributeProvider attributeProvider)
{
JsonConverterAttribute converterAttribute = GetAttribute<JsonConverterAttribute>(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<MetadataTypeAttribute>(type, true);
// double check locking to avoid threading issues
lock (AssociatedMetadataTypesCache)
{
if (AssociatedMetadataTypesCache.TryGetValue(type, out associatedMetadataType))
return associatedMetadataType;
MetadataTypeAttribute metadataTypeAttribute = ReflectionUtils.GetAttribute<MetadataTypeAttribute>(type, true);
if (metadataTypeAttribute != null)
associatedMetadataType = metadataTypeAttribute.MetadataClassType;
AssociatedMetadataTypesCache[type] = associatedMetadataType;
return associatedMetadataType;
}
return (metadataTypeAttribute != null) ? metadataTypeAttribute.MetadataClassType : null;
}
private static T GetAttribute<T>(Type type) where T : Attribute
@@ -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<TKey, TValue>
{
private Dictionary<TKey, TValue> _dictionary;
private readonly Func<TKey, TValue> _creator;
public ThreadSafeDictionaryWrapper(Func<TKey, TValue> creator)
{
ValidationUtils.ArgumentNotNull(creator, "creator");
_creator = creator;
}
private TValue AddValue(TKey key)
{
lock (this)
{
TValue value;
if (_dictionary == null)
{
_dictionary = new Dictionary<TKey, TValue>();
value = _creator(key);
_dictionary[key] = value;
}
else
{
// double check locking
if (_dictionary.TryGetValue(key, out value))
return value;
Dictionary<TKey, TValue> newDictionary = new Dictionary<TKey, TValue>(_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;
}
}
}
@@ -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