-More documentation (I know!)

-Fixed decimals to always be written with a decimal place
-Replaced IMappingResolver with IContractResolver
-Renamed JsonMemberMapping to JsonProperty
-Added JsonContract, JsonObjectContract, JsonArrayContract, JsonDictionaryContract
-Added support for OnSerializing, OnSerialized, OnDeserializing, OnDeserialized callback methods
-Major refactoring of serialization internals
This commit is contained in:
JamesNK
2009-07-05 02:55:58 +00:00
parent 6b19c9cf72
commit a4022ec5d3
51 changed files with 3317 additions and 1826 deletions
+126 -7
View File
@@ -17,16 +17,135 @@
<p>The Json.NET serializer has a number of advanced options to alter how JSON is serialized and deserialized.</p>
<h3>IMappingResolver</h3>
<h3>Serialization Callbacks</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>
<p>Json.NET supports serialization callback methods. A callback can be used to
manipulate an object before and after its serialization and deserialization by
the JsonSerializer.</p>
<ul>
<li><b>OnSerializing</b></li>
<li><b>OnSerialized</b></li>
<li><b>OnDeserializing</b></li>
<li><b>OnDeserialized</b></li>
</ul>
<p>To tell the serializer which methods should be called during the object&#39;s serialization
lifecycle, decorate a method with the appropraite attribute (<a
href="http://msdn.microsoft.com/en-us/library/system.runtime.serialization.onserializingattribute.aspx" target="_blank">OnSerializingAttribute</a>,
<a href="http://msdn.microsoft.com/en-us/library/system.runtime.serialization.onserializedattribute.aspx" target="_blank">OnSerializedAttribute</a>,
<a href="http://msdn.microsoft.com/en-us/library/system.runtime.serialization.ondeserializingattribute.aspx" target="_blank">OnDeserializingAttribute</a>,
<a href="http://msdn.microsoft.com/en-us/library/system.runtime.serialization.ondeserializedattribute.aspx" target="_blank">OnDeserializedAttribute</a>).</p>
<p>Example object with serialization callback methods:</p>
<div class="overflowpanel"> <div class="code">
<div style="font-family: Courier New; font-size: 10pt; color: black;">
<pre style="margin: 0px;"><span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">SerializationEventTestObject</span></pre>
<pre style="margin: 0px;">{</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: green;">// This member is serialized and deserialized with no change.</span></pre>
<pre style="margin: 0px;">&nbsp; <span style="color: blue;">public</span> <span style="color: blue;">int</span> Member1 { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: green;">// The value of this field is set and reset during and </span></pre>
<pre style="margin: 0px;">&nbsp; <span style="color: green;">// after serialization.</span></pre>
<pre style="margin: 0px;">&nbsp; <span style="color: blue;">public</span> <span style="color: blue;">string</span> Member2 { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: green;">// This field is not serialized. The OnDeserializedAttribute </span></pre>
<pre style="margin: 0px;">&nbsp; <span style="color: green;">// is used to set the member value after serialization.</span></pre>
<pre style="margin: 0px;">&nbsp; [<span style="color: #2b91af;">JsonIgnore</span>]</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: blue;">public</span> <span style="color: blue;">string</span> Member3 { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: green;">// This field is set to null, but populated after deserialization.</span></pre>
<pre style="margin: 0px;">&nbsp; <span style="color: blue;">public</span> <span style="color: blue;">string</span> Member4 { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: blue;">public</span> SerializationEventTestObject()</pre>
<pre style="margin: 0px;">&nbsp; {</pre>
<pre style="margin: 0px;">&nbsp; &nbsp; Member1 = 11;</pre>
<pre style="margin: 0px;">&nbsp; &nbsp; Member2 = <span style="color: #a31515;">"Hello World!"</span>;</pre>
<pre style="margin: 0px;">&nbsp; &nbsp; Member3 = <span style="color: #a31515;">"This is a nonserialized value"</span>;</pre>
<pre style="margin: 0px;">&nbsp; &nbsp; Member4 = <span style="color: blue;">null</span>;</pre>
<pre style="margin: 0px;">&nbsp; }</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;">&nbsp; [<span style="color: #2b91af;">OnSerializing</span>]</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: blue;">internal</span> <span style="color: blue;">void</span> OnSerializingMethod(<span style="color: #2b91af;">StreamingContext</span> context)</pre>
<pre style="margin: 0px;">&nbsp; {</pre>
<pre style="margin: 0px;">&nbsp; &nbsp; Member2 = <span style="color: #a31515;">"This value went into the data file during serialization."</span>;</pre>
<pre style="margin: 0px;">&nbsp; }</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;">&nbsp; [<span style="color: #2b91af;">OnSerialized</span>]</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: blue;">internal</span> <span style="color: blue;">void</span> OnSerializedMethod(<span style="color: #2b91af;">StreamingContext</span> context)</pre>
<pre style="margin: 0px;">&nbsp; {</pre>
<pre style="margin: 0px;">&nbsp; &nbsp; Member2 = <span style="color: #a31515;">"This value was reset after serialization."</span>;</pre>
<pre style="margin: 0px;">&nbsp; }</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;">&nbsp; [<span style="color: #2b91af;">OnDeserializing</span>]</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: blue;">internal</span> <span style="color: blue;">void</span> OnDeserializingMethod(<span style="color: #2b91af;">StreamingContext</span> context)</pre>
<pre style="margin: 0px;">&nbsp; {</pre>
<pre style="margin: 0px;">&nbsp; &nbsp; Member3 = <span style="color: #a31515;">"This value was set during deserialization"</span>;</pre>
<pre style="margin: 0px;">&nbsp; }</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;">&nbsp; [<span style="color: #2b91af;">OnDeserialized</span>]</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: blue;">internal</span> <span style="color: blue;">void</span> OnDeserializedMethod(<span style="color: #2b91af;">StreamingContext</span> context)</pre>
<pre style="margin: 0px;">&nbsp; {</pre>
<pre style="margin: 0px;">&nbsp; &nbsp; Member4 = <span style="color: #a31515;">"This value was set after deserialization."</span>;</pre>
<pre style="margin: 0px;">&nbsp; }</pre>
<pre style="margin: 0px;">}</pre>
</div>
</div></div>
<p>The example object being serialized and deserialized by Json.NET:</p>
<div class="overflowpanel"> <div class="code">
<div style="font-family: Courier New; font-size: 10pt; color: black;">
<pre style="margin: 0px;"><span style="color: #2b91af;">SerializationEventTestObject</span> obj = <span style="color: blue;">new</span> <span style="color: #2b91af;">SerializationEventTestObject</span>();</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;"><span style="color: #2b91af;">Console</span>.WriteLine(obj.Member1);</pre>
<pre style="margin: 0px;"><span style="color: green;">// 11</span></pre>
<pre style="margin: 0px;"><span style="color: #2b91af;">Console</span>.WriteLine(obj.Member2);</pre>
<pre style="margin: 0px;"><span style="color: green;">// Hello World!</span></pre>
<pre style="margin: 0px;"><span style="color: #2b91af;">Console</span>.WriteLine(obj.Member3);</pre>
<pre style="margin: 0px;"><span style="color: green;">// This is a nonserialized value</span></pre>
<pre style="margin: 0px;"><span style="color: #2b91af;">Console</span>.WriteLine(obj.Member4);</pre>
<pre style="margin: 0px;"><span style="color: green;">// null</span></pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;"><span style="color: blue;">string</span> json = <span style="color: #2b91af;">JsonConvert</span>.SerializeObject(obj, <span style="color: #2b91af;">Formatting</span>.Indented);</pre>
<pre style="margin: 0px;"><span style="color: green;">// {</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//&nbsp; "Member1": 11,</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//&nbsp; "Member2": "This value went into the data file during serialization.",</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//&nbsp; "Member4": null</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;">Console</span>.WriteLine(obj.Member1);</pre>
<pre style="margin: 0px;"><span style="color: green;">// 11</span></pre>
<pre style="margin: 0px;"><span style="color: #2b91af;">Console</span>.WriteLine(obj.Member2);</pre>
<pre style="margin: 0px;"><span style="color: green;">// This value was reset after serialization.</span></pre>
<pre style="margin: 0px;"><span style="color: #2b91af;">Console</span>.WriteLine(obj.Member3);</pre>
<pre style="margin: 0px;"><span style="color: green;">// This is a nonserialized value</span></pre>
<pre style="margin: 0px;"><span style="color: #2b91af;">Console</span>.WriteLine(obj.Member4);</pre>
<pre style="margin: 0px;"><span style="color: green;">// null</span></pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;">obj = <span style="color: #2b91af;">JsonConvert</span>.DeserializeObject&lt;<span style="color: #2b91af;">SerializationEventTestObject</span>&gt;(json);</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;"><span style="color: #2b91af;">Console</span>.WriteLine(obj.Member1);</pre>
<pre style="margin: 0px;"><span style="color: green;">// 11</span></pre>
<pre style="margin: 0px;"><span style="color: #2b91af;">Console</span>.WriteLine(obj.Member2);</pre>
<pre style="margin: 0px;"><span style="color: green;">// This value went into the data file during serialization.</span></pre>
<pre style="margin: 0px;"><span style="color: #2b91af;">Console</span>.WriteLine(obj.Member3);</pre>
<pre style="margin: 0px;"><span style="color: green;">// This value was set during deserialization</span></pre>
<pre style="margin: 0px;"><span style="color: #2b91af;">Console</span>.WriteLine(obj.Member4);</pre>
<pre style="margin: 0px;"><span style="color: green;">// This value was set after deserialization.</span></pre>
</div>
</div></div>
<h3>IContractResolver</h3>
<p>The <a href="./html/T_Newtonsoft_Json_Serialization_IContractResolver.htm">IContractResolver</a> interface provides a way to customize how the JsonSerializer serializes and deserializes .NET objects to JSON.</p>
<p>Implementing the IContractResolver interface and then assigning an instance to a JsonSerializer lets you control
whether the object is serialized as a JSON object or JSON array, 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>DefaultContractResolver</h4>
<p>The <a href="./html/T_Newtonsoft_Json_Serialization_DefaultContractResolver.htm">DefaultContractResolver</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>
<h4>CamelCasePropertyNamesContractResolver</h4>
<p><a href="./html/T_Newtonsoft_Json_Serialization_CamelCasePropertyNamesContractResolver.htm">CamelCasePropertyNamesContractResolver</a> inherits from DefaultContractResolver 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>
+1 -1
View File
@@ -50,7 +50,7 @@
<p>
Json.NET is a free open source project that I have developed in my personal time.</p>
<p>
You can show your support for Json.NET by donating. I really appreciate your feedback and support.</p>
I really appreciate your feedback and support for Json.NET and its future development.</p>
<p><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=james%40newtonking%2ecom&item_name=Supporting%20Json%2eNET&no_shipping=0&no_note=1&tax=0&currency_code=USD&lc=US&bn=PP%2dDonationsBF&charset=UTF%2d8" target="_blank">
<img src="donate.gif" alt="Donate" style="border-width:0;" />
</a></p>
+218
View File
@@ -0,0 +1,218 @@
<html>
<head>
<title>Serializing and deserializing 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">Serialization and PreserveObjectRefences</span></div>
<div id="content">
<span style="color: DarkGray"> </span>
<p>The quickest method of converting between JSON text and a .NET object is using
the <a href="./html/T_Newtonsoft_Json_JsonSerializer.htm">JsonSerializer</a>. The JsonSerializer converts .NET objects into their JSON
equivalent and back again.</p>
<p>For simple scenarios the <a href="./html/Overload_Newtonsoft_Json_JsonConvert_SerializeObject.htm">SerializeObject</a> and <a href="./html/Overload_Newtonsoft_Json_JsonConvert_DeserializeObject.htm">DeserializeObject</a> methods on <a href="./html/T_Newtonsoft_Json_JsonConvert.htm">JsonConvert</a> provide an easy to use wrapper over
JsonSerializer.</p>
<div class="overflowpanel"> <div class="code">
<div style="font-family: Courier New; font-size: 10pt; color: black;">
<pre style="margin: 0px;"><span style="color: #2b91af;">Product</span> product = <span style="color: blue;">new</span> <span style="color: #2b91af;">Product</span>();</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;">product.Name = <span style="color: #a31515;">"Apple"</span>;</pre>
<pre style="margin: 0px;">product.Expiry = <span style="color: blue;">new</span> <span style="color: #2b91af;">DateTime</span>(2008, 12, 28);</pre>
<pre style="margin: 0px;">product.Price = 3.99M;</pre>
<pre style="margin: 0px;">product.Sizes = <span style="color: blue;">new</span> <span style="color: blue;">string</span>[] { <span style="color: #a31515;">"Small"</span>, <span style="color: #a31515;">"Medium"</span>, <span style="color: #a31515;">"Large"</span> };</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;"><span style="color: blue;">string</span> output = <span style="color: #2b91af;">JsonConvert</span>.SerializeObject(product);</pre>
<pre style="margin: 0px;"><span style="color: green;">//{</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//&nbsp; "Name": "Apple",</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//&nbsp; "Expiry": &quot;\/Date(1230375600000+1300)\/&quot;,</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//&nbsp; "Price": 3.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; "Small",</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//&nbsp; &nbsp; "Medium",</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//&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>
<pre style="margin: 0px;">&nbsp;</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>
<h3>JsonSerializer</h3>
<p>For more control over how an object is serialized the JsonSerializer can be used
directly. The JsonSerializer has a number of properties to control its behaviour
when serializing and deserializing.</p>
<div class="overflowpanel"> <div class="code">
<div style="font-family: Courier New; font-size: 10pt; color: black;">
<pre style="margin: 0px;"><span style="color: #2b91af;">Product</span> product = <span style="color: blue;">new</span> <span style="color: #2b91af;">Product</span>();</pre>
<pre style="margin: 0px;">product.Expiry = <span style="color: blue;">new</span> <span style="color: #2b91af;">DateTime</span>(2008, 12, 28);</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;"><span style="color: #2b91af;">JsonSerializer</span> serializer = <span style="color: blue;">new</span> <span style="color: #2b91af;">JsonSerializer</span>();</pre>
<pre style="margin: 0px;">serializer.Converters.Add(<span style="color: blue;">new</span> <span style="color: #2b91af;">JavaScriptDateTimeConverter</span>());</pre>
<pre style="margin: 0px;">serializer.NullValueHandling = <span style="color: #2b91af;">NullValueHandling</span>.Ignore;</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;"><span style="color: blue;">using</span> (<span style="color: #2b91af;">StreamWriter</span> sw = <span style="color: blue;">new</span> <span style="color: #2b91af;">StreamWriter</span>(<span style="color: #a31515;">@"c:\json.txt"</span>))</pre>
<pre style="margin: 0px;"><span style="color: blue;">using</span> (<span style="color: #2b91af;">JsonWriter</span> writer = <span style="color: blue;">new</span> <span style="color: #2b91af;">JsonTextWriter</span>(sw))</pre>
<pre style="margin: 0px;">{</pre>
<pre style="margin: 0px;">&nbsp; serializer.Serialize(writer, product);</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: green;">// {"Expiry":new Date(1230375600000),"Price":0}</span></pre>
<pre style="margin: 0px;">}</pre>
</div>
</div></div>
<h5>ReferenceLoopHandling</h5>
<p>Controls how circular referencing objects are serialized. Error, ignore or
serialize.</p>
<h5>MissingMemberHandling</h5>
<p>Controls how missing members (e.g. JSON contains a property that isn&#39;t a member
on the object) are handled during deserialization. Ignore or error.</p>
<h5>NullValueHandling</h5>
<p>Controls how null values are handled during serialization and deserialization.
Include or ignore.</p>
<h5>DefaultValueHandling</h5>
<p>Controls whether a value will be written to JSON or not if it matches the value specified in
the member's DefaultValueAttribute. Include or ignore.</p>
<h5>ObjectCreationHandling</h5>
<p>Controls how objects are created during deserialization. Auto, reuse, replace.</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">
<div style="font-family: Courier New; font-size: 10pt; color: black;">
<pre style="margin: 0px;">[<span style="color: #2b91af;">JsonObject</span>(<span style="color: #2b91af;">MemberSerialization</span>.OptIn)]</pre>
<pre style="margin: 0px;"><span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">Person</span></pre>
<pre style="margin: 0px;">{</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: green;">// "John Smith"</span></pre>
<pre style="margin: 0px;">&nbsp; [<span style="color: #2b91af;">JsonProperty</span>]</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: blue;">public</span> <span style="color: blue;">string</span> Name { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: green;">// "2000-12-15T22:11:03"</span></pre>
<pre style="margin: 0px;">&nbsp; [<span style="color: #2b91af;">JsonProperty</span>]</pre>
<pre style="margin: 0px;">&nbsp; [<span style="color: #2b91af;">JsonConverter</span>(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">IsoDateTimeConverter</span>))]</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: blue;">public</span> <span style="color: #2b91af;">DateTime</span> BirthDate { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: green;">// new Date(976918263055)</span></pre>
<pre style="margin: 0px;">&nbsp; [<span style="color: #2b91af;">JsonProperty</span>]</pre>
<pre style="margin: 0px;">&nbsp; [<span style="color: #2b91af;">JsonConverter</span>(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">JavaScriptDateTimeConverter</span>))]</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: blue;">public</span> <span style="color: #2b91af;">DateTime</span> LastModified { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: green;">// not serialized</span></pre>
<pre style="margin: 0px;">&nbsp; <span style="color: blue;">public</span> <span style="color: blue;">string</span> Department { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }</pre>
<pre style="margin: 0px;">}</pre>
</div>
</div></div>
<h5>JsonObjectAttribute</h5>
<p>The MemberSerialization flag on this attribute specifies whether member serialization is opt-in (a member must have the JsonProperty or DataMember attribute to be serialized) or opt-out (everything is serialized by default but can be ignored with the JsonIgnoreAttribute).</p>
<p>.NET classes that implement IEnumerable are automatically serialized as an array, populated with the IEnumerable values. Placing the JsonPropertyAttribute will override this and force the serializer to serialize the class's fields and properties.</p>
<h5>JsonPropertyAttribute</h5>
<p>Allows the name of the serialized member to be customized. The attribute also indicates that a member should be serialized when member serialization is set to opt-in.</p>
<h5>JsonIgnoreAttribute</h5>
<p>Excludes a field or property from serialization.</p>
<h5>JsonConverterAttribute</h5>
<p>The JsonConverterAttribute specifies which JsonSerializer is used to convert an object.</p>
<p>The attribute can be placed on a class or a member. When placed on a class the JsonConverter
specified by the attribute will be the default way of serializing that class. When the attribute is on a field
or property then the specified JsonConverter will always be used to serialize that value.</p>
<p>The priority of which JsonConverter is used is member attribute then class attribute and
finally any converters passed to the JsonSerializer.</p>
<div class="overflowpanel"> <div class="code">
<div style="font-family: Courier New; font-size: 10pt; color: black;">
<pre style="margin: 0px;"><span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">MemberConverterClass</span></pre>
<pre style="margin: 0px;">{</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: blue;">public</span> <span style="color: #2b91af;">DateTime</span> DefaultConverter { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }</pre>
<pre style="margin: 0px;">&nbsp; [<span style="color: #2b91af;">JsonConverter</span>(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">IsoDateTimeConverter</span>))]</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: blue;">public</span> <span style="color: #2b91af;">DateTime</span> MemberConverter { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }</pre>
<pre style="margin: 0px;">}</pre>
</div>
</div></div>
<p>This example shows the JsonConverterAttribute being applied to a property.</p>
<div class="overflowpanel"> <div class="code">
<div style="font-family: Courier New; font-size: 10pt; color: black;">
<pre style="margin: 0px;"><span style="color: #2b91af;">DateTime</span> date = <span style="color: #2b91af;">Convert</span>.ToDateTime(<span style="color: #a31515;">"1970-01-01T00:00:00Z"</span>).ToUniversalTime();</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;"><span style="color: #2b91af;">MemberConverterClass</span> c = <span style="color: blue;">new</span> <span style="color: #2b91af;">MemberConverterClass</span></pre>
<pre style="margin: 0px;">&nbsp; {</pre>
<pre style="margin: 0px;">&nbsp; &nbsp; DefaultConverter = date,</pre>
<pre style="margin: 0px;">&nbsp; &nbsp; MemberConverter = date</pre>
<pre style="margin: 0px;">&nbsp; };</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;"><span style="color: blue;">string</span> json = <span style="color: #2b91af;">JsonConvert</span>.SerializeObject(c, <span style="color: #2b91af;">Formatting</span>.Indented);</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;"><span style="color: #2b91af;">Console</span>.WriteLine(json);</pre>
<pre style="margin: 0px;"><span style="color: green;">//{</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//&nbsp; "DefaultConverter": "\/Date(0)\/",</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//&nbsp; "MemberConverter": "1970-01-01T00:00:00Z"</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//}</span></pre>
</div>
</div></div>
<h3>JsonConverters</h3>
<p>JsonConverters allows JSON to be manually written during serialization and read during deserialization. This is useful for particularly complex JSON structures or for when you want to change how a type is serialized.</p>
<p>To create your own custom converter inherit from the JsonConverter class. Json.NET also comes with a number of JsonConverters:</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
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>
<h5>BinaryConverter</h5>
<p>Converts binary data like a byte array or SqlBinary object to JSON. The binary
data is written as a string in JSON and 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>
</html>
+41 -5
View File
@@ -20,7 +20,7 @@
equivalent and back again.</p>
<p>For simple scenarios the <a href="./html/Overload_Newtonsoft_Json_JsonConvert_SerializeObject.htm">SerializeObject</a> and <a href="./html/Overload_Newtonsoft_Json_JavaScriptConvert_DeserializeObject.htm">DeserializeObject</a> methods on <a href="./html/T_Newtonsoft_Json_JavaScriptConvert.htm">JavaScriptConvert</a> provide an easy to use wrapper over
<p>For simple scenarios the <a href="./html/Overload_Newtonsoft_Json_JsonConvert_SerializeObject.htm">SerializeObject</a> and <a href="./html/Overload_Newtonsoft_Json_JsonConvert_DeserializeObject.htm">DeserializeObject</a> methods on <a href="./html/T_Newtonsoft_Json_JsonConvert.htm">JsonConvert</a> provide an easy to use wrapper over
JsonSerializer.</p>
@@ -132,7 +132,8 @@ the member's DefaultValueAttribute. Include or ignore.</p>
</div></div>
<h5>JsonObjectAttribute</h5>
<p>The MemberSerialization flag on this attribute specifies whether member serialization is opt-in (a member must have the JsonPropertyAttribute to be serialized) or opt-out (everything is serialized by default but can be ignored with the JsonIgnoreAttribute).</p>
<p>The MemberSerialization flag on this attribute specifies whether member serialization is opt-in (a member must have the JsonProperty or DataMember attribute to be serialized) or opt-out (everything is serialized by default but can be ignored with the JsonIgnoreAttribute).</p>
<p>.NET classes that implement IEnumerable are automatically serialized as an array, populated with the IEnumerable values. Placing the JsonPropertyAttribute will override this and force the serializer to serialize the class's fields and properties.</p>
<h5>JsonPropertyAttribute</h5>
<p>Allows the name of the serialized member to be customized. The attribute also indicates that a member should be serialized when member serialization is set to opt-in.</p>
<h5>JsonIgnoreAttribute</h5>
@@ -144,8 +145,43 @@ the member's DefaultValueAttribute. Include or ignore.</p>
or property then the specified JsonConverter will always be used to serialize that value.</p>
<p>The priority of which JsonConverter is used is member attribute then class attribute and
finally any converters passed to the JsonSerializer.</p>
<div class="overflowpanel"> <div class="code">
<div style="font-family: Courier New; font-size: 10pt; color: black;">
<pre style="margin: 0px;"><span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">MemberConverterClass</span></pre>
<pre style="margin: 0px;">{</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: blue;">public</span> <span style="color: #2b91af;">DateTime</span> DefaultConverter { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }</pre>
<pre style="margin: 0px;">&nbsp; [<span style="color: #2b91af;">JsonConverter</span>(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">IsoDateTimeConverter</span>))]</pre>
<pre style="margin: 0px;">&nbsp; <span style="color: blue;">public</span> <span style="color: #2b91af;">DateTime</span> MemberConverter { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }</pre>
<pre style="margin: 0px;">}</pre>
</div>
</div></div>
<p>This example shows the JsonConverterAttribute being applied to a property.</p>
<div class="overflowpanel"> <div class="code">
<div style="font-family: Courier New; font-size: 10pt; color: black;">
<pre style="margin: 0px;"><span style="color: #2b91af;">DateTime</span> date = <span style="color: #2b91af;">Convert</span>.ToDateTime(<span style="color: #a31515;">"1970-01-01T00:00:00Z"</span>).ToUniversalTime();</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;"><span style="color: #2b91af;">MemberConverterClass</span> c = <span style="color: blue;">new</span> <span style="color: #2b91af;">MemberConverterClass</span></pre>
<pre style="margin: 0px;">&nbsp; {</pre>
<pre style="margin: 0px;">&nbsp; &nbsp; DefaultConverter = date,</pre>
<pre style="margin: 0px;">&nbsp; &nbsp; MemberConverter = date</pre>
<pre style="margin: 0px;">&nbsp; };</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;"><span style="color: blue;">string</span> json = <span style="color: #2b91af;">JsonConvert</span>.SerializeObject(c, <span style="color: #2b91af;">Formatting</span>.Indented);</pre>
<pre style="margin: 0px;">&nbsp;</pre>
<pre style="margin: 0px;"><span style="color: #2b91af;">Console</span>.WriteLine(json);</pre>
<pre style="margin: 0px;"><span style="color: green;">//{</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//&nbsp; "DefaultConverter": "\/Date(0)\/",</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//&nbsp; "MemberConverter": "1970-01-01T00:00:00Z"</span></pre>
<pre style="margin: 0px;"><span style="color: green;">//}</span></pre>
</div>
</div></div>
<h3>JsonConverters</h3>
<p>JsonConverters allows JSON to be manually be written during serialization and read during deserialization. This is useful for particularly complex JSON structures or for when you want to change how a type is serialized.</p>
<p>JsonConverters allows JSON to be manually written during serialization and read during deserialization. This is useful for particularly complex JSON structures or for when you want to change how a type is serialized.</p>
<p>To create your own custom converter inherit from the JsonConverter class. Json.NET also comes with a number of JsonConverters:</p>
@@ -162,13 +198,13 @@ finally any converters passed to the JsonSerializer.</p>
<h5>BinaryConverter</h5>
<p>Converts binary data like a byte array or SqlBinary object to JSON. The binary
data is encoded in Base64.</p>
data is written as a string in JSON and 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>
<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">
+3 -1
View File
@@ -7,7 +7,9 @@
<namespaceSummaryItem name="Newtonsoft.Json" isDocumented="True">The &lt;b&gt;Newtonsoft.Json&lt;/b&gt; namespace provides classes that are used to implement the core services of the framework.</namespaceSummaryItem>
<namespaceSummaryItem name="Newtonsoft.Json.Converters" isDocumented="True">The &lt;b&gt;Newtonsoft.Json.Converters&lt;/b&gt; namespace provides classes that inherit from &lt;a href="T_Newtonsoft_Json_JsonConverter.htm"&gt;JsonConverter&lt;/a&gt;.</namespaceSummaryItem>
<namespaceSummaryItem name="Newtonsoft.Json.Linq" isDocumented="True">The &lt;b&gt;Newtonsoft.Json.Linq&lt;/b&gt; namespace provides classes that are used to implement LINQ to JSON.</namespaceSummaryItem>
<namespaceSummaryItem name="Newtonsoft.Json.Utilities" isDocumented="True" />
<namespaceSummaryItem name="Newtonsoft.Json.Schema" isDocumented="True">The &lt;b&gt;Newtonsoft.Json.Schema&lt;/b&gt; namespace provides classes that are used to implement JSON schema.</namespaceSummaryItem>
<namespaceSummaryItem name="Newtonsoft.Json.Serialization" isDocumented="True">The &lt;b&gt;Newtonsoft.Json.Linq&lt;/b&gt; namespace provides classes that are used when serializing and deserializing JSON.</namespaceSummaryItem>
<namespaceSummaryItem name="Newtonsoft.Json.Utilities" isDocumented="False" />
</namespaceSummaries>
<additionalContent contentSiteMap=".\doc.sitemap" topicFileTransform="">
<contentItem sourcePath=".\SerializingJSON.html" destPath="" excludeItems="False" />
+22 -6
View File
@@ -24,13 +24,8 @@
#endregion
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using Newtonsoft.Json.Utilities;
using NUnit.Framework;
using System.IO;
using System.Linq;
namespace Newtonsoft.Json.Tests
{
@@ -252,7 +247,7 @@ now brown cow?", '"', true);
// *** Make string invalid by stripping \" \"
serialized = serialized.Replace(@"\""", "\"");
string result = JsonConvert.DeserializeObject<string>(serialized);
JsonConvert.DeserializeObject<string>(serialized);
}
[Test]
@@ -286,6 +281,8 @@ now brown cow?", '"', true);
Assert.AreEqual("1.11111", JsonConvert.ToString(1.11111));
Assert.AreEqual("1.111111", JsonConvert.ToString(1.111111));
Assert.AreEqual("1.0", JsonConvert.ToString(1.0));
Assert.AreEqual("1.0", JsonConvert.ToString(1d));
Assert.AreEqual("-1.0", JsonConvert.ToString(-1d));
Assert.AreEqual("1.01", JsonConvert.ToString(1.01));
Assert.AreEqual("1.001", JsonConvert.ToString(1.001));
Assert.AreEqual(JsonConvert.PositiveInfinity, JsonConvert.ToString(double.PositiveInfinity));
@@ -293,6 +290,25 @@ now brown cow?", '"', true);
Assert.AreEqual(JsonConvert.NaN, JsonConvert.ToString(double.NaN));
}
[Test]
public void DecimalToString()
{
Assert.AreEqual("1.1", JsonConvert.ToString(1.1m));
Assert.AreEqual("1.11", JsonConvert.ToString(1.11m));
Assert.AreEqual("1.111", JsonConvert.ToString(1.111m));
Assert.AreEqual("1.1111", JsonConvert.ToString(1.1111m));
Assert.AreEqual("1.11111", JsonConvert.ToString(1.11111m));
Assert.AreEqual("1.111111", JsonConvert.ToString(1.111111m));
Assert.AreEqual("1.0", JsonConvert.ToString(1.0m));
Assert.AreEqual("-1.0", JsonConvert.ToString(-1.0m));
Assert.AreEqual("-1.0", JsonConvert.ToString(-1m));
Assert.AreEqual("1.0", JsonConvert.ToString(1m));
Assert.AreEqual("1.01", JsonConvert.ToString(1.01m));
Assert.AreEqual("1.001", JsonConvert.ToString(1.001m));
Assert.AreEqual("79228162514264337593543950335.0", JsonConvert.ToString(decimal.MaxValue));
Assert.AreEqual("-79228162514264337593543950335.0", JsonConvert.ToString(decimal.MinValue));
}
[Test]
public void StringEscaping()
{
+58 -820
View File
@@ -370,7 +370,7 @@ keyword such as type of business.""
}
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"A member with the name 'pie' already exists on Newtonsoft.Json.Tests.TestObjects.BadJsonPropertyClass. Use the JsonPropertyAttribute to specify another name.")]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"A member with the name 'pie' already exists on 'Newtonsoft.Json.Tests.TestObjects.BadJsonPropertyClass'. Use the JsonPropertyAttribute to specify another name.")]
public void BadJsonPropertyClassSerialize()
{
JsonConvert.SerializeObject(new BadJsonPropertyClass());
@@ -559,7 +559,7 @@ keyword such as type of business.""
};
string json = JsonConvert.SerializeObject(anonymous);
Assert.AreEqual(@"{""StringValue"":""I am a string"",""IntValue"":2147483647,""NestedAnonymous"":{""NestedValue"":255},""NestedArray"":[1,2],""Product"":{""Name"":""TestProduct"",""ExpiryDate"":""\/Date(946684800000)\/"",""Price"":0,""Sizes"":null}}", json);
Assert.AreEqual(@"{""StringValue"":""I am a string"",""IntValue"":2147483647,""NestedAnonymous"":{""NestedValue"":255},""NestedArray"":[1,2],""Product"":{""Name"":""TestProduct"",""ExpiryDate"":""\/Date(946684800000)\/"",""Price"":0.0,""Sizes"":null}}", json);
anonymous = JsonConvert.DeserializeAnonymousType(json, anonymous);
Assert.AreEqual("I am a string", anonymous.StringValue);
@@ -588,7 +588,7 @@ keyword such as type of business.""
jsonSerializer.Serialize(sw, collection);
Assert.AreEqual(@"[{""Name"":""Test1"",""ExpiryDate"":""\/Date(946684800000)\/"",""Price"":0,""Sizes"":null},{""Name"":""Test2"",""ExpiryDate"":""\/Date(946684800000)\/"",""Price"":0,""Sizes"":null},{""Name"":""Test3"",""ExpiryDate"":""\/Date(946684800000)\/"",""Price"":0,""Sizes"":null}]",
Assert.AreEqual(@"[{""Name"":""Test1"",""ExpiryDate"":""\/Date(946684800000)\/"",""Price"":0.0,""Sizes"":null},{""Name"":""Test2"",""ExpiryDate"":""\/Date(946684800000)\/"",""Price"":0.0,""Sizes"":null},{""Name"":""Test3"",""ExpiryDate"":""\/Date(946684800000)\/"",""Price"":0.0,""Sizes"":null}]",
sw.GetStringBuilder().ToString());
ProductCollection collectionNew = (ProductCollection)jsonSerializer.Deserialize(new JsonTextReader(new StringReader(sw.GetStringBuilder().ToString())), typeof(ProductCollection));
@@ -609,7 +609,7 @@ keyword such as type of business.""
//JsonConvert.ConvertDateTimeToJavaScriptTicks(s1.Establised.DateTime)
Assert.AreEqual(@"{""Color"":4,""Establised"":""\/Date(1264122061000+0000)\/"",""Width"":1.1,""Employees"":999,""RoomsPerFloor"":[1,2,3,4,5,6,7,8,9],""Open"":false,""Symbol"":""@"",""Mottos"":[""Hello World"",""öäüÖÄÜ\\'{new Date(12345);}[222]_µ@²³~"",null,"" ""],""Cost"":100980.1,""Escape"":""\r\n\t\f\b?{\\r\\n\""'"",""product"":[{""Name"":""Rocket"",""ExpiryDate"":""\/Date(949532490000)\/"",""Price"":0},{""Name"":""Alien"",""ExpiryDate"":""\/Date(946684800000)\/"",""Price"":0}]}", sw.GetStringBuilder().ToString());
Assert.AreEqual(@"{""Color"":4,""Establised"":""\/Date(1264122061000+0000)\/"",""Width"":1.1,""Employees"":999,""RoomsPerFloor"":[1,2,3,4,5,6,7,8,9],""Open"":false,""Symbol"":""@"",""Mottos"":[""Hello World"",""öäüÖÄÜ\\'{new Date(12345);}[222]_µ@²³~"",null,"" ""],""Cost"":100980.1,""Escape"":""\r\n\t\f\b?{\\r\\n\""'"",""product"":[{""Name"":""Rocket"",""ExpiryDate"":""\/Date(949532490000)\/"",""Price"":0.0},{""Name"":""Alien"",""ExpiryDate"":""\/Date(946684800000)\/"",""Price"":0.0}]}", sw.GetStringBuilder().ToString());
Store s2 = (Store)jsonSerializer.Deserialize(new JsonTextReader(new StringReader("{}")), typeof(Store));
Assert.AreEqual("\r\n\t\f\b?{\\r\\n\"\'", s2.Escape);
@@ -617,7 +617,7 @@ keyword such as type of business.""
Store s3 = (Store)jsonSerializer.Deserialize(new JsonTextReader(new StringReader(@"{""Escape"":null}")), typeof(Store));
Assert.AreEqual("\r\n\t\f\b?{\\r\\n\"\'", s3.Escape);
Store s4 = (Store)jsonSerializer.Deserialize(new JsonTextReader(new StringReader(@"{""Color"":2,""Establised"":""\/Date(1264071600000+1300)\/"",""Width"":1.1,""Employees"":999,""RoomsPerFloor"":[1,2,3,4,5,6,7,8,9],""Open"":false,""Symbol"":""@"",""Mottos"":[""Hello World"",""öäüÖÄÜ\\'{new Date(12345);}[222]_µ@²³~"",null,"" ""],""Cost"":100980.1,""Escape"":""\r\n\t\f\b?{\\r\\n\""'"",""product"":[{""Name"":""Rocket"",""ExpiryDate"":""\/Date(949485690000+1300)\/"",""Price"":0},{""Name"":""Alien"",""ExpiryDate"":""\/Date(946638000000)\/"",""Price"":0}]}")), typeof(Store));
Store s4 = (Store)jsonSerializer.Deserialize(new JsonTextReader(new StringReader(@"{""Color"":2,""Establised"":""\/Date(1264071600000+1300)\/"",""Width"":1.1,""Employees"":999,""RoomsPerFloor"":[1,2,3,4,5,6,7,8,9],""Open"":false,""Symbol"":""@"",""Mottos"":[""Hello World"",""öäüÖÄÜ\\'{new Date(12345);}[222]_µ@²³~"",null,"" ""],""Cost"":100980.1,""Escape"":""\r\n\t\f\b?{\\r\\n\""'"",""product"":[{""Name"":""Rocket"",""ExpiryDate"":""\/Date(949485690000+1300)\/"",""Price"":0},{""Name"":""Alien"",""ExpiryDate"":""\/Date(946638000000)\/"",""Price"":0.0}]}")), typeof(Store));
Assert.AreEqual(s1.Establised, s3.Establised);
}
@@ -877,6 +877,26 @@ keyword such as type of business.""
Assert.AreEqual(testDate, m2.MemberConverter);
}
[Test]
public void ConverterAttributeExample()
{
DateTime date = Convert.ToDateTime("1970-01-01T00:00:00Z").ToUniversalTime();
MemberConverterClass c = new MemberConverterClass
{
DefaultConverter = date,
MemberConverter = date
};
string json = JsonConvert.SerializeObject(c, Formatting.Indented);
Console.WriteLine(json);
//{
// "DefaultConverter": "\/Date(0)\/",
// "MemberConverter": "1970-01-01T00:00:00Z"
//}
}
[Test]
public void SerializerShouldUseMemberConverterOverClassAndArgumentConverter()
{
@@ -1656,515 +1676,12 @@ keyword such as type of business.""
Assert.AreEqual("James", p["Name"]);
}
[Test]
public void SerializeEmployeeReference()
{
Employee mikeManager = new Employee
{
Name = "Mike Manager"
};
Employee joeUser = new Employee
{
Name = "Joe User",
Manager = mikeManager
};
List<Employee> employees = new List<Employee>
{
mikeManager,
joeUser
};
string json = JsonConvert.SerializeObject(employees, Formatting.Indented);
Assert.AreEqual(@"[
{
""$id"": ""1"",
""Name"": ""Mike Manager"",
""Manager"": null
},
{
""$id"": ""2"",
""Name"": ""Joe User"",
""Manager"": {
""$ref"": ""1""
}
}
]", json);
}
[Test]
public void DeserializeEmployeeReference()
{
string json = @"[
{
""$id"": ""1"",
""Name"": ""Mike Manager"",
""Manager"": null
},
{
""$id"": ""2"",
""Name"": ""Joe User"",
""Manager"": {
""$ref"": ""1""
}
}
]";
List<Employee> employees = JsonConvert.DeserializeObject<List<Employee>>(json);
Assert.AreEqual(2, employees.Count);
Assert.AreEqual("Mike Manager", employees[0].Name);
Assert.AreEqual("Joe User", employees[1].Name);
Assert.AreEqual(employees[0], employees[1].Manager);
}
[Test]
public void SerializeCircularReference()
{
CircularReferenceClass c1 = new CircularReferenceClass {Name = "c1"};
CircularReferenceClass c2 = new CircularReferenceClass {Name = "c2"};
CircularReferenceClass c3 = new CircularReferenceClass {Name = "c3"};
c1.Child = c2;
c2.Child = c3;
c3.Child = c1;
string json = JsonConvert.SerializeObject(c1, Formatting.Indented, new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects
});
Assert.AreEqual(@"{
""$id"": ""1"",
""Name"": ""c1"",
""Child"": {
""$id"": ""2"",
""Name"": ""c2"",
""Child"": {
""$id"": ""3"",
""Name"": ""c3"",
""Child"": {
""$ref"": ""1""
}
}
}
}", json);
}
[Test]
public void DeserializeCircularReference()
{
string json = @"{
""$id"": ""1"",
""Name"": ""c1"",
""Child"": {
""$id"": ""2"",
""Name"": ""c2"",
""Child"": {
""$id"": ""3"",
""Name"": ""c3"",
""Child"": {
""$ref"": ""1""
}
}
}
}";
CircularReferenceClass c1 =
JsonConvert.DeserializeObject<CircularReferenceClass>(json, new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects
});
Assert.AreEqual("c1", c1.Name);
Assert.AreEqual("c2", c1.Child.Name);
Assert.AreEqual("c3", c1.Child.Child.Name);
Assert.AreEqual("c1", c1.Child.Child.Child.Name);
}
[Test]
public void SerializeReferenceInList()
{
Employee e1 = new Employee { Name = "e1" };
Employee e2 = new Employee { Name = "e2" };
List<Employee> employees = new List<Employee> { e1, e2, e1, e2 };
string json = JsonConvert.SerializeObject(employees, Formatting.Indented);
Assert.AreEqual(@"[
{
""$id"": ""1"",
""Name"": ""e1"",
""Manager"": null
},
{
""$id"": ""2"",
""Name"": ""e2"",
""Manager"": null
},
{
""$ref"": ""1""
},
{
""$ref"": ""2""
}
]", json);
}
[Test]
public void DeserializeReferenceInList()
{
string json = @"[
{
""$id"": ""1"",
""Name"": ""e1"",
""Manager"": null
},
{
""$id"": ""2"",
""Name"": ""e2"",
""Manager"": null
},
{
""$ref"": ""1""
},
{
""$ref"": ""2""
}
]";
List<Employee> employees = JsonConvert.DeserializeObject<List<Employee>>(json);
Assert.AreEqual(4, employees.Count);
Assert.AreEqual("e1", employees[0].Name);
Assert.AreEqual("e2", employees[1].Name);
Assert.AreEqual("e1", employees[2].Name);
Assert.AreEqual("e2", employees[3].Name);
Assert.AreEqual(employees[0], employees[2]);
Assert.AreEqual(employees[1], employees[3]);
}
[Test]
public void SerializeReferenceInDictionary()
{
Employee e1 = new Employee {Name = "e1"};
Employee e2 = new Employee {Name = "e2"};
Dictionary<string, Employee> employees = new Dictionary<string, Employee>
{
{"One", e1},
{"Two", e2},
{"Three", e1},
{"Four", e2}
};
string json = JsonConvert.SerializeObject(employees, Formatting.Indented);
Assert.AreEqual(@"{
""One"": {
""$id"": ""1"",
""Name"": ""e1"",
""Manager"": null
},
""Two"": {
""$id"": ""2"",
""Name"": ""e2"",
""Manager"": null
},
""Three"": {
""$ref"": ""1""
},
""Four"": {
""$ref"": ""2""
}
}", json);
}
[Test]
public void DeserializeReferenceInDictionary()
{
string json = @"{
""One"": {
""$id"": ""1"",
""Name"": ""e1"",
""Manager"": null
},
""Two"": {
""$id"": ""2"",
""Name"": ""e2"",
""Manager"": null
},
""Three"": {
""$ref"": ""1""
},
""Four"": {
""$ref"": ""2""
}
}";
Dictionary<string, Employee> employees = JsonConvert.DeserializeObject<Dictionary<string, Employee>>(json);
Assert.AreEqual(4, employees.Count);
Employee e1 = employees["One"];
Employee e2 = employees["Two"];
Assert.AreEqual("e1", e1.Name);
Assert.AreEqual("e2", e2.Name);
Assert.AreEqual(e1, employees["Three"]);
Assert.AreEqual(e2, employees["Four"]);
}
public class CircularDictionary : Dictionary<string, CircularDictionary>
{
}
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Self referencing loop")]
public void SerializeCircularDictionarysError()
{
CircularDictionary circularDictionary = new CircularDictionary();
circularDictionary.Add("other", new CircularDictionary { { "blah", null } });
circularDictionary.Add("self", circularDictionary);
JsonConvert.SerializeObject(circularDictionary, Formatting.Indented);
}
[Test]
public void SerializeCircularDictionarysIgnore()
{
CircularDictionary circularDictionary = new CircularDictionary();
circularDictionary.Add("other", new CircularDictionary { { "blah", null } });
circularDictionary.Add("self", circularDictionary);
string json = JsonConvert.SerializeObject(circularDictionary, Formatting.Indented,
new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
Assert.AreEqual(@"{
""other"": {
""blah"": null
}
}", json);
}
[Test]
public void SerializeDictionarysWithPreserveObjectReferences()
{
CircularDictionary circularDictionary = new CircularDictionary();
circularDictionary.Add("other", new CircularDictionary { {"blah", null }});
circularDictionary.Add("self", circularDictionary);
string json = JsonConvert.SerializeObject(circularDictionary, Formatting.Indented,
new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });
Assert.AreEqual(@"{
""$id"": ""1"",
""other"": {
""$id"": ""2"",
""blah"": null
},
""self"": {
""$ref"": ""1""
}
}", json);
}
[Test]
public void DeserializeDictionarysWithPreserveObjectReferences()
{
string json = @"{
""$id"": ""1"",
""other"": {
""$id"": ""2"",
""blah"": null
},
""self"": {
""$ref"": ""1""
}
}";
CircularDictionary circularDictionary = JsonConvert.DeserializeObject<CircularDictionary>(json,
new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.All
});
Assert.AreEqual(2, circularDictionary.Count);
Assert.AreEqual(1, circularDictionary["other"].Count);
Assert.AreEqual(circularDictionary, circularDictionary["self"]);
}
public class CircularList : List<CircularList>
{
}
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Self referencing loop")]
public void SerializeCircularListsError()
{
CircularList circularList = new CircularList();
circularList.Add(null);
circularList.Add(new CircularList { null });
circularList.Add(new CircularList { new CircularList { circularList } });
JsonConvert.SerializeObject(circularList, Formatting.Indented);
}
[Test]
public void SerializeCircularListsIgnore()
{
CircularList circularList = new CircularList();
circularList.Add(null);
circularList.Add(new CircularList { null });
circularList.Add(new CircularList { new CircularList { circularList } });
string json = JsonConvert.SerializeObject(circularList,
Formatting.Indented,
new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
Assert.AreEqual(@"[
null,
[
null
],
[
[]
]
]", json);
}
[Test]
public void SerializeListsWithPreserveObjectReferences()
{
CircularList circularList = new CircularList();
circularList.Add(null);
circularList.Add(new CircularList { null });
circularList.Add(new CircularList { new CircularList { circularList }});
string json = JsonConvert.SerializeObject(circularList, Formatting.Indented,
new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });
WriteEscapedJson(json);
Assert.AreEqual(@"{
""$id"": ""1"",
""$values"": [
null,
{
""$id"": ""2"",
""$values"": [
null
]
},
{
""$id"": ""3"",
""$values"": [
{
""$id"": ""4"",
""$values"": [
{
""$ref"": ""1""
}
]
}
]
}
]
}", json);
}
[Test]
public void DeserializeListsWithPreserveObjectReferences()
{
string json = @"{
""$id"": ""1"",
""$values"": [
null,
{
""$id"": ""2"",
""$values"": [
null
]
},
{
""$id"": ""3"",
""$values"": [
{
""$id"": ""4"",
""$values"": [
{
""$ref"": ""1""
}
]
}
]
}
]
}";
CircularList circularList = JsonConvert.DeserializeObject<CircularList>(json,
new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });
Assert.AreEqual(3, circularList.Count);
Assert.AreEqual(null, circularList[0]);
Assert.AreEqual(1, circularList[1].Count);
Assert.AreEqual(1, circularList[2].Count);
Assert.AreEqual(1, circularList[2][0].Count);
Assert.IsTrue(ReferenceEquals(circularList, circularList[2][0][0]));
}
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Cannot preserve reference to array or readonly list: System.String[][]")]
public void DeserializeArraysWithPreserveObjectReferences()
{
string json = @"{
""$id"": ""1"",
""$values"": [
null,
{
""$id"": ""2"",
""$values"": [
null
]
},
{
""$id"": ""3"",
""$values"": [
{
""$id"": ""4"",
""$values"": [
{
""$ref"": ""1""
}
]
}
]
}
]
}";
JsonConvert.DeserializeObject<string[][]>(json,
new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });
}
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Unexpected end when deserializing object.")]
public void UnexpectedEnd()
{
string json = @"{
""$id"":";
JsonConvert.DeserializeObject<string[][]>(json,
new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });
}
public class DictionaryInterfaceClass
{
public string Name { get; set; }
public IDictionary<string, int> Dictionary { get; set; }
public ICollection<int> Collection { get; set; }
public Employee Employee { get; set; }
public EmployeeReference Employee { get; set; }
public object Random { get; set; }
public DictionaryInterfaceClass()
@@ -2179,7 +1696,7 @@ keyword such as type of business.""
2,
3
};
Employee = new Employee
Employee = new EmployeeReference
{
Name = "EmployeeName!"
};
@@ -2240,316 +1757,6 @@ keyword such as type of business.""
Assert.IsNotNull(c.Random);
}
public class CircularReferenceClassConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
CircularReferenceClass circularReferenceClass = (CircularReferenceClass) value;
string reference = serializer.ReferenceResolver.GetReference(circularReferenceClass);
JObject me = new JObject();
me["$id"] = new JValue(reference);
me["$type"] = new JValue(value.GetType().Name);
me["Name"] = new JValue(circularReferenceClass.Name);
JObject o = JObject.FromObject(circularReferenceClass.Child, serializer);
me["Child"] = o;
me.WriteTo(writer);
}
public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer)
{
JObject o = JObject.Load(reader);
string id = (string)o["$id"];
if (id != null)
{
CircularReferenceClass circularReferenceClass = new CircularReferenceClass();
serializer.Populate(o.CreateReader(), circularReferenceClass);
return circularReferenceClass;
}
else
{
string reference = (string)o["$ref"];
return serializer.ReferenceResolver.ResolveReference(reference);
}
}
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(CircularReferenceClass));
}
}
[Test]
public void SerializeCircularReferencesWithConverter()
{
CircularReferenceClass c1 = new CircularReferenceClass { Name = "c1" };
CircularReferenceClass c2 = new CircularReferenceClass { Name = "c2" };
CircularReferenceClass c3 = new CircularReferenceClass { Name = "c3" };
c1.Child = c2;
c2.Child = c3;
c3.Child = c1;
string json = JsonConvert.SerializeObject(c1, Formatting.Indented, new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
Converters = new List<JsonConverter> { new CircularReferenceClassConverter() }
});
Assert.AreEqual(@"{
""$id"": ""1"",
""$type"": ""CircularReferenceClass"",
""Name"": ""c1"",
""Child"": {
""$id"": ""2"",
""$type"": ""CircularReferenceClass"",
""Name"": ""c2"",
""Child"": {
""$id"": ""3"",
""$type"": ""CircularReferenceClass"",
""Name"": ""c3"",
""Child"": {
""$ref"": ""1""
}
}
}
}", json);
}
[Test]
public void DeserializeCircularReferencesWithConverter()
{
string json = @"{
""$id"": ""1"",
""$type"": ""CircularReferenceClass"",
""Name"": ""c1"",
""Child"": {
""$id"": ""2"",
""$type"": ""CircularReferenceClass"",
""Name"": ""c2"",
""Child"": {
""$id"": ""3"",
""$type"": ""CircularReferenceClass"",
""Name"": ""c3"",
""Child"": {
""$ref"": ""1""
}
}
}
}";
CircularReferenceClass c1 = JsonConvert.DeserializeObject<CircularReferenceClass>(json, new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
Converters = new List<JsonConverter> { new CircularReferenceClassConverter() }
});
Assert.AreEqual("c1", c1.Name);
Assert.AreEqual("c2", c1.Child.Name);
Assert.AreEqual("c3", c1.Child.Child.Name);
Assert.AreEqual("c1", c1.Child.Child.Child.Name);
}
[Test]
public void WriteTypeNameForObjects()
{
string employeeRef = typeof(Employee).AssemblyQualifiedName;
Employee employee = new Employee();
string json = JsonConvert.SerializeObject(employee, Formatting.Indented, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects
});
Assert.AreEqual(@"{
""$id"": ""1"",
""$type"": """ + employeeRef + @""",
""Name"": null,
""Manager"": null
}", json);
}
[Test]
public void DeserializeTypeName()
{
string employeeRef = typeof(Employee).AssemblyQualifiedName;
string json = @"{
""$id"": ""1"",
""$type"": """ + employeeRef + @""",
""Name"": ""Name!"",
""Manager"": null
}";
object employee = JsonConvert.DeserializeObject(json, null, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects
});
Assert.IsInstanceOfType(typeof(Employee), employee);
Assert.AreEqual("Name!", ((Employee)employee).Name);
}
[Test]
public void SerializeGenericObjectListWithTypeName()
{
string employeeRef = typeof(Employee).AssemblyQualifiedName;
string personRef = typeof(Person).AssemblyQualifiedName;
List<object> values = new List<object>
{
new Employee
{
Name = "Bob",
Manager = new Employee {Name = "Frank"}
},
new Person
{
Department = "Department",
BirthDate = new DateTime(2000, 12, 30, 0, 0, 0, DateTimeKind.Utc),
LastModified = new DateTime(2000, 12, 30, 0, 0, 0, DateTimeKind.Utc)
},
"String!",
int.MinValue
};
string json = JsonConvert.SerializeObject(values, Formatting.Indented, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects
});
Assert.AreEqual(@"[
{
""$id"": ""1"",
""$type"": """ + employeeRef + @""",
""Name"": ""Bob"",
""Manager"": {
""$id"": ""2"",
""$type"": """ + employeeRef + @""",
""Name"": ""Frank"",
""Manager"": null
}
},
{
""$type"": """ + personRef + @""",
""Name"": null,
""BirthDate"": ""\/Date(978134400000)\/"",
""LastModified"": ""\/Date(978134400000)\/""
},
""String!"",
-2147483648
]", json);
}
[Test]
public void DeserializeGenericObjectListWithTypeName()
{
string employeeRef = typeof (Employee).AssemblyQualifiedName;
string personRef = typeof (Person).AssemblyQualifiedName;
string json = @"[
{
""$id"": ""1"",
""$type"": """ + employeeRef + @""",
""Name"": ""Bob"",
""Manager"": {
""$id"": ""2"",
""$type"": """ + employeeRef + @""",
""Name"": ""Frank"",
""Manager"": null
}
},
{
""$type"": """ + personRef + @""",
""Name"": null,
""BirthDate"": ""\/Date(978134400000)\/"",
""LastModified"": ""\/Date(978134400000)\/""
},
""String!"",
-2147483648
]";
List<object> values = (List<object>)JsonConvert.DeserializeObject(json, typeof(List<object>), new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects
});
Assert.AreEqual(4, values.Count);
Employee e = (Employee) values[0];
Person p = (Person) values[1];
Assert.AreEqual("Bob", e.Name);
Assert.AreEqual("Frank", e.Manager.Name);
Assert.AreEqual(null, p.Name);
Assert.AreEqual(new DateTime(2000, 12, 30, 0, 0, 0, DateTimeKind.Utc), p.BirthDate);
Assert.AreEqual(new DateTime(2000, 12, 30, 0, 0, 0, DateTimeKind.Utc), p.LastModified);
Assert.AreEqual("String!", values[2]);
Assert.AreEqual(int.MinValue, values[3]);
}
[Test]
[ExpectedException(typeof(JsonSerializationException))]
public void DeserializeWithBadTypeName()
{
string employeeRef = typeof(Employee).AssemblyQualifiedName;
string json = @"{
""$id"": ""1"",
""$type"": """ + employeeRef + @""",
""Name"": ""Name!"",
""Manager"": null
}";
JsonConvert.DeserializeObject(json, typeof(Person), new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects
});
}
[Test]
public void DeserializeTypeNameWithNoTypeNameHandling()
{
string employeeRef = typeof(Employee).AssemblyQualifiedName;
string json = @"{
""$id"": ""1"",
""$type"": """ + employeeRef + @""",
""Name"": ""Name!"",
""Manager"": null
}";
JObject o = (JObject)JsonConvert.DeserializeObject(json);
Assert.AreEqual(@"{
""Name"": ""Name!"",
""Manager"": null
}", o.ToString());
}
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Type specified in JSON 'Newtonsoft.Json.Tests.TestObjects.Employee' was not resolved.")]
public void DeserializeTypeNameOnly()
{
string json = @"{
""$id"": ""1"",
""$type"": ""Newtonsoft.Json.Tests.TestObjects.Employee"",
""Name"": ""Name!"",
""Manager"": null
}";
JsonConvert.DeserializeObject(json, null, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects
});
}
[Test]
public void TypedObjectDeserializationWithComments()
{
@@ -2697,5 +1904,36 @@ keyword such as type of business.""
Assert.AreEqual("First", content.Children[0].Text);
Assert.AreEqual("Second", content.Children[1].Text);
}
public enum RoleTransferOperation
{
First,
Second
}
public enum RoleTransferDirection
{
First,
Second
}
public class RoleTransfer
{
public RoleTransferOperation Operation { get; set; } //This is enum type
public string RoleName { get; set; }
public RoleTransferDirection Direction { get; set; } //This is enum type
}
[Test]
public void RoleTransferTest()
{
string json = @"{""Operation"":""1"",""RoleName"":""Admin"",""Direction"":""0""}";
RoleTransfer r = JsonConvert.DeserializeObject<RoleTransfer>(json);
Assert.AreEqual(RoleTransferOperation.Second, r.Operation);
Assert.AreEqual("Admin", r.RoleName);
Assert.AreEqual(RoleTransferDirection.First, r.Direction);
}
}
}
@@ -63,11 +63,14 @@
<Compile Include="Converters\StringEnumConverterTests.cs" />
<Compile Include="Linq\JTokenReaderTest.cs" />
<Compile Include="Linq\JTokenWriterTest.cs" />
<Compile Include="Serialization\CamelCaseMappingResolverTests.cs" />
<Compile Include="JsonValidatingReaderTests.cs" />
<Compile Include="Schema\ExtensionsTests.cs" />
<Compile Include="Schema\JsonSchemaModelBuilderTests.cs" />
<Compile Include="Schema\JsonSchemaNodeTests.cs" />
<Compile Include="Serialization\CamelCasePropertyNamesContractResolverTests.cs" />
<Compile Include="Serialization\PreserveReferencesHandlingTests.cs" />
<Compile Include="Serialization\SerializationEventAttributeTests.cs" />
<Compile Include="Serialization\TypeNameHandlingTests.cs" />
<Compile Include="TestObjects\AbstractGenericBase.cs" />
<Compile Include="TestObjects\ArgumentConverterPrecedenceClassConverter.cs" />
<Compile Include="TestObjects\BadJsonPropertyClass.cs" />
@@ -80,7 +83,7 @@
<Compile Include="TestObjects\CircularReferenceWithIdClass.cs" />
<Compile Include="TestObjects\DefaultValueAttributeTestClass.cs" />
<Compile Include="TestObjects\DoubleClass.cs" />
<Compile Include="TestObjects\Employee.cs" />
<Compile Include="TestObjects\EmployeeReference.cs" />
<Compile Include="TestObjects\GenericImpl.cs" />
<Compile Include="TestObjects\GenericListAndDictionaryInterfaceProperties.cs" />
<Compile Include="TestObjects\GetOnlyPropertyClass.cs" />
@@ -97,6 +100,10 @@
<Compile Include="TestObjects\PhoneNumber.cs" />
<Compile Include="TestObjects\PrivateMembersClass.cs" />
<Compile Include="TestObjects\RequiredMembersClass.cs" />
<Compile Include="TestObjects\SerializationEventTestDictionary.cs" />
<Compile Include="TestObjects\SerializationEventTestList.cs" />
<Compile Include="TestObjects\SerializationEventTestObject.cs" />
<Compile Include="TestObjects\SerializationEventTestObjectWithConstructor.cs" />
<Compile Include="TestObjects\SetOnlyPropertyClass.cs" />
<Compile Include="TestObjects\Article.cs" />
<Compile Include="TestObjects\ArticleCollection.cs" />
@@ -67,11 +67,14 @@
<Compile Include="Converters\StringEnumConverterTests.cs" />
<Compile Include="Linq\JTokenReaderTest.cs" />
<Compile Include="Linq\JTokenWriterTest.cs" />
<Compile Include="Serialization\CamelCaseMappingResolverTests.cs" />
<Compile Include="JsonValidatingReaderTests.cs" />
<Compile Include="Schema\ExtensionsTests.cs" />
<Compile Include="Schema\JsonSchemaModelBuilderTests.cs" />
<Compile Include="Schema\JsonSchemaNodeTests.cs" />
<Compile Include="Serialization\CamelCasePropertyNamesContractResolverTests.cs" />
<Compile Include="Serialization\PreserveReferencesHandlingTests.cs" />
<Compile Include="Serialization\SerializationEventAttributeTests.cs" />
<Compile Include="Serialization\TypeNameHandlingTests.cs" />
<Compile Include="TestObjects\AbstractGenericBase.cs" />
<Compile Include="TestObjects\ArgumentConverterPrecedenceClassConverter.cs" />
<Compile Include="TestObjects\BadJsonPropertyClass.cs" />
@@ -84,7 +87,7 @@
<Compile Include="TestObjects\CircularReferenceWithIdClass.cs" />
<Compile Include="TestObjects\DefaultValueAttributeTestClass.cs" />
<Compile Include="TestObjects\DoubleClass.cs" />
<Compile Include="TestObjects\Employee.cs" />
<Compile Include="TestObjects\EmployeeReference.cs" />
<Compile Include="TestObjects\GenericImpl.cs" />
<Compile Include="TestObjects\GenericListAndDictionaryInterfaceProperties.cs" />
<Compile Include="TestObjects\GetOnlyPropertyClass.cs" />
@@ -101,6 +104,10 @@
<Compile Include="TestObjects\PhoneNumber.cs" />
<Compile Include="TestObjects\PrivateMembersClass.cs" />
<Compile Include="TestObjects\RequiredMembersClass.cs" />
<Compile Include="TestObjects\SerializationEventTestDictionary.cs" />
<Compile Include="TestObjects\SerializationEventTestList.cs" />
<Compile Include="TestObjects\SerializationEventTestObject.cs" />
<Compile Include="TestObjects\SerializationEventTestObjectWithConstructor.cs" />
<Compile Include="TestObjects\SetOnlyPropertyClass.cs" />
<Compile Include="TestObjects\Article.cs" />
<Compile Include="TestObjects\ArticleCollection.cs" />
@@ -98,10 +98,13 @@
</Compile>
<Compile Include="LinqToSql\LinqToSqlClassesSerializationTests.cs" />
<Compile Include="LinqToSql\Person.cs" />
<Compile Include="Serialization\SerializationEventAttributeTests.cs" />
<Compile Include="Schema\ExtensionsTests.cs" />
<Compile Include="Schema\JsonSchemaModelBuilderTests.cs" />
<Compile Include="Schema\JsonSchemaNodeTests.cs" />
<Compile Include="Serialization\CamelCaseMappingResolverTests.cs" />
<Compile Include="Serialization\CamelCasePropertyNamesContractResolverTests.cs" />
<Compile Include="Serialization\PreserveReferencesHandlingTests.cs" />
<Compile Include="Serialization\TypeNameHandlingTests.cs" />
<Compile Include="TestObjects\AbstractGenericBase.cs" />
<Compile Include="TestObjects\ArgumentConverterPrecedenceClassConverter.cs" />
<Compile Include="TestObjects\BadJsonPropertyClass.cs" />
@@ -112,7 +115,7 @@
<Compile Include="TestObjects\ConverterPrecedenceClass.cs" />
<Compile Include="TestObjects\ConverterPrecedenceClassConverter.cs" />
<Compile Include="TestObjects\CircularReferenceWithIdClass.cs" />
<Compile Include="TestObjects\Employee.cs" />
<Compile Include="TestObjects\EmployeeReference.cs" />
<Compile Include="TestObjects\JsonPropertyWithHandlingValues.cs" />
<Compile Include="TestObjects\DefaultValueAttributeTestClass.cs" />
<Compile Include="TestObjects\DoubleClass.cs" />
@@ -131,6 +134,10 @@
<Compile Include="TestObjects\PhoneNumber.cs" />
<Compile Include="TestObjects\PrivateMembersClass.cs" />
<Compile Include="TestObjects\RequiredMembersClass.cs" />
<Compile Include="TestObjects\SerializationEventTestDictionary.cs" />
<Compile Include="TestObjects\SerializationEventTestList.cs" />
<Compile Include="TestObjects\SerializationEventTestObject.cs" />
<Compile Include="TestObjects\SerializationEventTestObjectWithConstructor.cs" />
<Compile Include="TestObjects\SetOnlyPropertyClass.cs" />
<Compile Include="TestObjects\Article.cs" />
<Compile Include="TestObjects\ArticleCollection.cs" />
@@ -281,27 +281,14 @@ namespace Newtonsoft.Json.Tests.Schema
Assert.AreEqual(JsonSchemaType.String, schema.Type);
}
//public class CustomDirectoryInfoSerializer : JsonSerializer
//{
// protected override Newtonsoft.Json.Serialization.JsonMemberMappingCollection GetMemberMappings(Type objectType)
// {
// JsonMemberMappingCollection mappings = base.GetMemberMappings(objectType);
// JsonMemberMappingCollection c = new JsonMemberMappingCollection();
// CollectionUtils.AddRange(c, (IEnumerable) mappings.Where(m => m.MappingName != "Root"));
// return c;
// }
//}
public class CustomDirectoryInfoMapper : DefaultMappingResolver
public class CustomDirectoryInfoMapper : DefaultContractResolver
{
public override JsonMemberMappingCollection ResolveMappings(Type type)
protected override IList<JsonProperty> CreateProperties(JsonObjectContract contract)
{
JsonMemberMappingCollection mappings = base.ResolveMappings(type);
IList<JsonProperty> properties = base.CreateProperties(contract);
JsonMemberMappingCollection c = new JsonMemberMappingCollection();
CollectionUtils.AddRange(c, (IEnumerable)mappings.Where(m => m.PropertyName != "Root"));
JsonPropertyCollection c = new JsonPropertyCollection();
CollectionUtils.AddRange(c, (IEnumerable)properties.Where(m => m.PropertyName != "Root"));
return c;
}
@@ -381,7 +368,7 @@ namespace Newtonsoft.Json.Tests.Schema
JTokenWriter jsonWriter = new JTokenWriter();
JsonSerializer serializer = new JsonSerializer();
serializer.Converters.Add(new IsoDateTimeConverter());
serializer.MappingResolver = new CustomDirectoryInfoMapper();
serializer.ContractResolver = new CustomDirectoryInfoMapper();
serializer.Serialize(jsonWriter, temp);
List<string> errors = new List<string>();
@@ -397,7 +384,7 @@ namespace Newtonsoft.Json.Tests.Schema
{
JsonSchemaGenerator generator = new JsonSchemaGenerator();
generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
generator.MappingResolver = new CamelCaseMappingResolver();
generator.ContractResolver = new CamelCasePropertyNamesContractResolver();
JsonSchema schema = generator.Generate(typeof (DirectoryInfo), true);
@@ -1,4 +1,4 @@
#region License
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
@@ -36,7 +36,7 @@ using Newtonsoft.Json.Utilities;
namespace Newtonsoft.Json.Tests.Serialization
{
public class CamelCaseMappingResolverTests : TestFixtureBase
public class CamelCasePropertyNamesContractResolverTests : TestFixtureBase
{
[Test]
public void JsonConvertSerializerSettings()
@@ -48,7 +48,7 @@ namespace Newtonsoft.Json.Tests.Serialization
string json = JsonConvert.SerializeObject(person, Formatting.Indented, new JsonSerializerSettings
{
MappingResolver = new CamelCaseMappingResolver()
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
Assert.AreEqual(@"{
@@ -59,7 +59,7 @@ namespace Newtonsoft.Json.Tests.Serialization
Person deserializedPerson = JsonConvert.DeserializeObject<Person>(json, new JsonSerializerSettings
{
MappingResolver = new CamelCaseMappingResolver()
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
Assert.AreEqual(person.BirthDate, deserializedPerson.BirthDate);
@@ -74,7 +74,7 @@ namespace Newtonsoft.Json.Tests.Serialization
ignoreAttributeOnClassTestClass.Field = int.MinValue;
JsonSerializer serializer = new JsonSerializer();
serializer.MappingResolver = new CamelCaseMappingResolver();
serializer.ContractResolver = new CamelCasePropertyNamesContractResolver();
JTokenWriter writer = new JTokenWriter();
@@ -96,7 +96,7 @@ namespace Newtonsoft.Json.Tests.Serialization
string json = JsonConvert.SerializeObject(privateMembersClass, Formatting.Indented, new JsonSerializerSettings
{
MappingResolver = new CamelCaseMappingResolver { DefaultMembersSearchFlags = BindingFlags.NonPublic | BindingFlags.Instance }
ContractResolver = new CamelCasePropertyNamesContractResolver { DefaultMembersSearchFlags = BindingFlags.NonPublic | BindingFlags.Instance }
});
Assert.AreEqual(@"{
@@ -111,7 +111,7 @@ namespace Newtonsoft.Json.Tests.Serialization
""_internalString"": ""Internal!""
}", new JsonSerializerSettings
{
MappingResolver = new CamelCaseMappingResolver { DefaultMembersSearchFlags = BindingFlags.NonPublic | BindingFlags.Instance }
ContractResolver = new CamelCasePropertyNamesContractResolver { DefaultMembersSearchFlags = BindingFlags.NonPublic | BindingFlags.Instance }
});
Assert.AreEqual("Private!", ReflectionUtils.GetMemberValue(typeof(PrivateMembersClass).GetField("_privateString", BindingFlags.Instance | BindingFlags.NonPublic), deserializedPrivateMembersClass));
@@ -134,7 +134,7 @@ namespace Newtonsoft.Json.Tests.Serialization
JsonConvert.SerializeObject(
product,
Formatting.Indented,
new JsonSerializerSettings { MappingResolver = new CamelCaseMappingResolver() }
new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }
);
//{
@@ -0,0 +1,654 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Tests.TestObjects;
using NUnit.Framework;
namespace Newtonsoft.Json.Tests.Serialization
{
public class PreserveReferencesHandlingTests : TestFixtureBase
{
[Test]
public void SerializeDictionarysWithPreserveObjectReferences()
{
CircularDictionary circularDictionary = new CircularDictionary();
circularDictionary.Add("other", new CircularDictionary { { "blah", null } });
circularDictionary.Add("self", circularDictionary);
string json = JsonConvert.SerializeObject(circularDictionary, Formatting.Indented,
new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });
Assert.AreEqual(@"{
""$id"": ""1"",
""other"": {
""$id"": ""2"",
""blah"": null
},
""self"": {
""$ref"": ""1""
}
}", json);
}
[Test]
public void DeserializeDictionarysWithPreserveObjectReferences()
{
string json = @"{
""$id"": ""1"",
""other"": {
""$id"": ""2"",
""blah"": null
},
""self"": {
""$ref"": ""1""
}
}";
CircularDictionary circularDictionary = JsonConvert.DeserializeObject<CircularDictionary>(json,
new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.All
});
Assert.AreEqual(2, circularDictionary.Count);
Assert.AreEqual(1, circularDictionary["other"].Count);
Assert.AreEqual(circularDictionary, circularDictionary["self"]);
}
public class CircularList : List<CircularList>
{
}
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Self referencing loop")]
public void SerializeCircularListsError()
{
CircularList circularList = new CircularList();
circularList.Add(null);
circularList.Add(new CircularList { null });
circularList.Add(new CircularList { new CircularList { circularList } });
JsonConvert.SerializeObject(circularList, Formatting.Indented);
}
[Test]
public void SerializeCircularListsIgnore()
{
CircularList circularList = new CircularList();
circularList.Add(null);
circularList.Add(new CircularList { null });
circularList.Add(new CircularList { new CircularList { circularList } });
string json = JsonConvert.SerializeObject(circularList,
Formatting.Indented,
new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
Assert.AreEqual(@"[
null,
[
null
],
[
[]
]
]", json);
}
[Test]
public void SerializeListsWithPreserveObjectReferences()
{
CircularList circularList = new CircularList();
circularList.Add(null);
circularList.Add(new CircularList { null });
circularList.Add(new CircularList { new CircularList { circularList } });
string json = JsonConvert.SerializeObject(circularList, Formatting.Indented,
new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });
WriteEscapedJson(json);
Assert.AreEqual(@"{
""$id"": ""1"",
""$values"": [
null,
{
""$id"": ""2"",
""$values"": [
null
]
},
{
""$id"": ""3"",
""$values"": [
{
""$id"": ""4"",
""$values"": [
{
""$ref"": ""1""
}
]
}
]
}
]
}", json);
}
[Test]
public void DeserializeListsWithPreserveObjectReferences()
{
string json = @"{
""$id"": ""1"",
""$values"": [
null,
{
""$id"": ""2"",
""$values"": [
null
]
},
{
""$id"": ""3"",
""$values"": [
{
""$id"": ""4"",
""$values"": [
{
""$ref"": ""1""
}
]
}
]
}
]
}";
CircularList circularList = JsonConvert.DeserializeObject<CircularList>(json,
new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });
Assert.AreEqual(3, circularList.Count);
Assert.AreEqual(null, circularList[0]);
Assert.AreEqual(1, circularList[1].Count);
Assert.AreEqual(1, circularList[2].Count);
Assert.AreEqual(1, circularList[2][0].Count);
Assert.IsTrue(ReferenceEquals(circularList, circularList[2][0][0]));
}
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Cannot preserve reference to array or readonly list: System.String[][]")]
public void DeserializeArraysWithPreserveObjectReferences()
{
string json = @"{
""$id"": ""1"",
""$values"": [
null,
{
""$id"": ""2"",
""$values"": [
null
]
},
{
""$id"": ""3"",
""$values"": [
{
""$id"": ""4"",
""$values"": [
{
""$ref"": ""1""
}
]
}
]
}
]
}";
JsonConvert.DeserializeObject<string[][]>(json,
new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });
}
public class CircularDictionary : Dictionary<string, CircularDictionary>
{
}
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Self referencing loop")]
public void SerializeCircularDictionarysError()
{
CircularDictionary circularDictionary = new CircularDictionary();
circularDictionary.Add("other", new CircularDictionary { { "blah", null } });
circularDictionary.Add("self", circularDictionary);
JsonConvert.SerializeObject(circularDictionary, Formatting.Indented);
}
[Test]
public void SerializeCircularDictionarysIgnore()
{
CircularDictionary circularDictionary = new CircularDictionary();
circularDictionary.Add("other", new CircularDictionary { { "blah", null } });
circularDictionary.Add("self", circularDictionary);
string json = JsonConvert.SerializeObject(circularDictionary, Formatting.Indented,
new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
Assert.AreEqual(@"{
""other"": {
""blah"": null
}
}", json);
}
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Unexpected end when deserializing object.")]
public void UnexpectedEnd()
{
string json = @"{
""$id"":";
JsonConvert.DeserializeObject<string[][]>(json,
new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });
}
public class CircularReferenceClassConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
CircularReferenceClass circularReferenceClass = (CircularReferenceClass)value;
string reference = serializer.ReferenceResolver.GetReference(circularReferenceClass);
JObject me = new JObject();
me["$id"] = new JValue(reference);
me["$type"] = new JValue(value.GetType().Name);
me["Name"] = new JValue(circularReferenceClass.Name);
JObject o = JObject.FromObject(circularReferenceClass.Child, serializer);
me["Child"] = o;
me.WriteTo(writer);
}
public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer)
{
JObject o = JObject.Load(reader);
string id = (string)o["$id"];
if (id != null)
{
CircularReferenceClass circularReferenceClass = new CircularReferenceClass();
serializer.Populate(o.CreateReader(), circularReferenceClass);
return circularReferenceClass;
}
else
{
string reference = (string)o["$ref"];
return serializer.ReferenceResolver.ResolveReference(reference);
}
}
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(CircularReferenceClass));
}
}
[Test]
public void SerializeCircularReferencesWithConverter()
{
CircularReferenceClass c1 = new CircularReferenceClass { Name = "c1" };
CircularReferenceClass c2 = new CircularReferenceClass { Name = "c2" };
CircularReferenceClass c3 = new CircularReferenceClass { Name = "c3" };
c1.Child = c2;
c2.Child = c3;
c3.Child = c1;
string json = JsonConvert.SerializeObject(c1, Formatting.Indented, new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
Converters = new List<JsonConverter> { new CircularReferenceClassConverter() }
});
Assert.AreEqual(@"{
""$id"": ""1"",
""$type"": ""CircularReferenceClass"",
""Name"": ""c1"",
""Child"": {
""$id"": ""2"",
""$type"": ""CircularReferenceClass"",
""Name"": ""c2"",
""Child"": {
""$id"": ""3"",
""$type"": ""CircularReferenceClass"",
""Name"": ""c3"",
""Child"": {
""$ref"": ""1""
}
}
}
}", json);
}
[Test]
public void DeserializeCircularReferencesWithConverter()
{
string json = @"{
""$id"": ""1"",
""$type"": ""CircularReferenceClass"",
""Name"": ""c1"",
""Child"": {
""$id"": ""2"",
""$type"": ""CircularReferenceClass"",
""Name"": ""c2"",
""Child"": {
""$id"": ""3"",
""$type"": ""CircularReferenceClass"",
""Name"": ""c3"",
""Child"": {
""$ref"": ""1""
}
}
}
}";
CircularReferenceClass c1 = JsonConvert.DeserializeObject<CircularReferenceClass>(json, new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
Converters = new List<JsonConverter> { new CircularReferenceClassConverter() }
});
Assert.AreEqual("c1", c1.Name);
Assert.AreEqual("c2", c1.Child.Name);
Assert.AreEqual("c3", c1.Child.Child.Name);
Assert.AreEqual("c1", c1.Child.Child.Child.Name);
}
[Test]
public void SerializeEmployeeReference()
{
EmployeeReference mikeManager = new EmployeeReference
{
Name = "Mike Manager"
};
EmployeeReference joeUser = new EmployeeReference
{
Name = "Joe User",
Manager = mikeManager
};
List<EmployeeReference> employees = new List<EmployeeReference>
{
mikeManager,
joeUser
};
string json = JsonConvert.SerializeObject(employees, Formatting.Indented);
Assert.AreEqual(@"[
{
""$id"": ""1"",
""Name"": ""Mike Manager"",
""Manager"": null
},
{
""$id"": ""2"",
""Name"": ""Joe User"",
""Manager"": {
""$ref"": ""1""
}
}
]", json);
}
[Test]
public void DeserializeEmployeeReference()
{
string json = @"[
{
""$id"": ""1"",
""Name"": ""Mike Manager"",
""Manager"": null
},
{
""$id"": ""2"",
""Name"": ""Joe User"",
""Manager"": {
""$ref"": ""1""
}
}
]";
List<EmployeeReference> employees = JsonConvert.DeserializeObject<List<EmployeeReference>>(json);
Assert.AreEqual(2, employees.Count);
Assert.AreEqual("Mike Manager", employees[0].Name);
Assert.AreEqual("Joe User", employees[1].Name);
Assert.AreEqual(employees[0], employees[1].Manager);
}
[Test]
public void SerializeCircularReference()
{
CircularReferenceClass c1 = new CircularReferenceClass { Name = "c1" };
CircularReferenceClass c2 = new CircularReferenceClass { Name = "c2" };
CircularReferenceClass c3 = new CircularReferenceClass { Name = "c3" };
c1.Child = c2;
c2.Child = c3;
c3.Child = c1;
string json = JsonConvert.SerializeObject(c1, Formatting.Indented, new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects
});
Assert.AreEqual(@"{
""$id"": ""1"",
""Name"": ""c1"",
""Child"": {
""$id"": ""2"",
""Name"": ""c2"",
""Child"": {
""$id"": ""3"",
""Name"": ""c3"",
""Child"": {
""$ref"": ""1""
}
}
}
}", json);
}
[Test]
public void DeserializeCircularReference()
{
string json = @"{
""$id"": ""1"",
""Name"": ""c1"",
""Child"": {
""$id"": ""2"",
""Name"": ""c2"",
""Child"": {
""$id"": ""3"",
""Name"": ""c3"",
""Child"": {
""$ref"": ""1""
}
}
}
}";
CircularReferenceClass c1 =
JsonConvert.DeserializeObject<CircularReferenceClass>(json, new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects
});
Assert.AreEqual("c1", c1.Name);
Assert.AreEqual("c2", c1.Child.Name);
Assert.AreEqual("c3", c1.Child.Child.Name);
Assert.AreEqual("c1", c1.Child.Child.Child.Name);
}
[Test]
public void SerializeReferenceInList()
{
EmployeeReference e1 = new EmployeeReference { Name = "e1" };
EmployeeReference e2 = new EmployeeReference { Name = "e2" };
List<EmployeeReference> employees = new List<EmployeeReference> { e1, e2, e1, e2 };
string json = JsonConvert.SerializeObject(employees, Formatting.Indented);
Assert.AreEqual(@"[
{
""$id"": ""1"",
""Name"": ""e1"",
""Manager"": null
},
{
""$id"": ""2"",
""Name"": ""e2"",
""Manager"": null
},
{
""$ref"": ""1""
},
{
""$ref"": ""2""
}
]", json);
}
[Test]
public void DeserializeReferenceInList()
{
string json = @"[
{
""$id"": ""1"",
""Name"": ""e1"",
""Manager"": null
},
{
""$id"": ""2"",
""Name"": ""e2"",
""Manager"": null
},
{
""$ref"": ""1""
},
{
""$ref"": ""2""
}
]";
List<EmployeeReference> employees = JsonConvert.DeserializeObject<List<EmployeeReference>>(json);
Assert.AreEqual(4, employees.Count);
Assert.AreEqual("e1", employees[0].Name);
Assert.AreEqual("e2", employees[1].Name);
Assert.AreEqual("e1", employees[2].Name);
Assert.AreEqual("e2", employees[3].Name);
Assert.AreEqual(employees[0], employees[2]);
Assert.AreEqual(employees[1], employees[3]);
}
[Test]
public void SerializeReferenceInDictionary()
{
EmployeeReference e1 = new EmployeeReference { Name = "e1" };
EmployeeReference e2 = new EmployeeReference { Name = "e2" };
Dictionary<string, EmployeeReference> employees = new Dictionary<string, EmployeeReference>
{
{"One", e1},
{"Two", e2},
{"Three", e1},
{"Four", e2}
};
string json = JsonConvert.SerializeObject(employees, Formatting.Indented);
Assert.AreEqual(@"{
""One"": {
""$id"": ""1"",
""Name"": ""e1"",
""Manager"": null
},
""Two"": {
""$id"": ""2"",
""Name"": ""e2"",
""Manager"": null
},
""Three"": {
""$ref"": ""1""
},
""Four"": {
""$ref"": ""2""
}
}", json);
}
[Test]
public void DeserializeReferenceInDictionary()
{
string json = @"{
""One"": {
""$id"": ""1"",
""Name"": ""e1"",
""Manager"": null
},
""Two"": {
""$id"": ""2"",
""Name"": ""e2"",
""Manager"": null
},
""Three"": {
""$ref"": ""1""
},
""Four"": {
""$ref"": ""2""
}
}";
Dictionary<string, EmployeeReference> employees = JsonConvert.DeserializeObject<Dictionary<string, EmployeeReference>>(json);
Assert.AreEqual(4, employees.Count);
EmployeeReference e1 = employees["One"];
EmployeeReference e2 = employees["Two"];
Assert.AreEqual("e1", e1.Name);
Assert.AreEqual("e2", e2.Name);
Assert.AreEqual(e1, employees["Three"]);
Assert.AreEqual(e2, employees["Four"]);
}
}
}
@@ -0,0 +1,220 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
#if !PocketPC && !SILVERLIGHT
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using Newtonsoft.Json.Tests;
using Newtonsoft.Json.Tests.TestObjects;
using NUnit.Framework;
namespace Newtonsoft.Json.Tests.Serialization
{
public class SerializationEventAttributeTests : TestFixtureBase
{
[Test]
public void ObjectEvents()
{
SerializationEventTestObject obj = new SerializationEventTestObject();
Assert.AreEqual(11, obj.Member1);
Assert.AreEqual("Hello World!", obj.Member2);
Assert.AreEqual("This is a nonserialized value", obj.Member3);
Assert.AreEqual(null, obj.Member4);
string json = JsonConvert.SerializeObject(obj, Formatting.Indented);
Assert.AreEqual(@"{
""Member1"": 11,
""Member2"": ""This value went into the data file during serialization."",
""Member4"": null
}", json);
Assert.AreEqual(11, obj.Member1);
Assert.AreEqual("This value was reset after serialization.", obj.Member2);
Assert.AreEqual("This is a nonserialized value", obj.Member3);
Assert.AreEqual(null, obj.Member4);
obj = JsonConvert.DeserializeObject<SerializationEventTestObject>(json);
Assert.AreEqual(11, obj.Member1);
Assert.AreEqual("This value went into the data file during serialization.", obj.Member2);
Assert.AreEqual("This value was set during deserialization", obj.Member3);
Assert.AreEqual("This value was set after deserialization.", obj.Member4);
}
[Test]
public void ObjectWithConstructorEvents()
{
SerializationEventTestObjectWithConstructor obj = new SerializationEventTestObjectWithConstructor(11, "Hello World!", null);
Assert.AreEqual(11, obj.Member1);
Assert.AreEqual("Hello World!", obj.Member2);
Assert.AreEqual("This is a nonserialized value", obj.Member3);
Assert.AreEqual(null, obj.Member4);
string json = JsonConvert.SerializeObject(obj, Formatting.Indented);
Assert.AreEqual(@"{
""Member1"": 11,
""Member2"": ""This value went into the data file during serialization."",
""Member4"": null
}", json);
Assert.AreEqual(11, obj.Member1);
Assert.AreEqual("This value was reset after serialization.", obj.Member2);
Assert.AreEqual("This is a nonserialized value", obj.Member3);
Assert.AreEqual(null, obj.Member4);
obj = JsonConvert.DeserializeObject<SerializationEventTestObjectWithConstructor>(json);
Assert.AreEqual(11, obj.Member1);
Assert.AreEqual("This value went into the data file during serialization.", obj.Member2);
Assert.AreEqual("This value was set during deserialization", obj.Member3);
Assert.AreEqual("This value was set after deserialization.", obj.Member4);
}
[Test]
public void ListEvents()
{
SerializationEventTestList obj = new SerializationEventTestList
{
1.1m,
2.222222222m,
int.MaxValue,
Convert.ToDecimal(Math.PI)
};
Assert.AreEqual(11, obj.Member1);
Assert.AreEqual("Hello World!", obj.Member2);
Assert.AreEqual("This is a nonserialized value", obj.Member3);
Assert.AreEqual(null, obj.Member4);
string json = JsonConvert.SerializeObject(obj, Formatting.Indented);
Assert.AreEqual(@"[
-1.0,
1.1,
2.222222222,
2147483647.0,
3.14159265358979
]", json);
Assert.AreEqual(11, obj.Member1);
Assert.AreEqual("This value was reset after serialization.", obj.Member2);
Assert.AreEqual("This is a nonserialized value", obj.Member3);
Assert.AreEqual(null, obj.Member4);
obj = JsonConvert.DeserializeObject<SerializationEventTestList>(json);
Assert.AreEqual(11, obj.Member1);
Assert.AreEqual("Hello World!", obj.Member2);
Assert.AreEqual("This value was set during deserialization", obj.Member3);
Assert.AreEqual("This value was set after deserialization.", obj.Member4);
}
[Test]
public void DictionaryEvents()
{
SerializationEventTestDictionary obj = new SerializationEventTestDictionary
{
{ 1.1m, "first" },
{ 2.222222222m, "second" },
{ int.MaxValue, "third" },
{ Convert.ToDecimal(Math.PI), "fourth" }
};
Assert.AreEqual(11, obj.Member1);
Assert.AreEqual("Hello World!", obj.Member2);
Assert.AreEqual("This is a nonserialized value", obj.Member3);
Assert.AreEqual(null, obj.Member4);
string json = JsonConvert.SerializeObject(obj, Formatting.Indented);
Assert.AreEqual(@"{
""1.1"": ""first"",
""2.222222222"": ""second"",
""2147483647"": ""third"",
""3.14159265358979"": ""fourth"",
""79228162514264337593543950335"": ""Inserted on serializing""
}", json);
Assert.AreEqual(11, obj.Member1);
Assert.AreEqual("This value was reset after serialization.", obj.Member2);
Assert.AreEqual("This is a nonserialized value", obj.Member3);
Assert.AreEqual(null, obj.Member4);
obj = JsonConvert.DeserializeObject<SerializationEventTestDictionary>(json);
Assert.AreEqual(11, obj.Member1);
Assert.AreEqual("Hello World!", obj.Member2);
Assert.AreEqual("This value was set during deserialization", obj.Member3);
Assert.AreEqual("This value was set after deserialization.", obj.Member4);
}
[Test]
public void ObjectEventsDocumentationExample()
{
SerializationEventTestObject obj = new SerializationEventTestObject();
Console.WriteLine(obj.Member1);
// 11
Console.WriteLine(obj.Member2);
// Hello World!
Console.WriteLine(obj.Member3);
// This is a nonserialized value
Console.WriteLine(obj.Member4);
// null
string json = JsonConvert.SerializeObject(obj, Formatting.Indented);
// {
// "Member1": 11,
// "Member2": "This value went into the data file during serialization.",
// "Member4": null
// }
Console.WriteLine(obj.Member1);
// 11
Console.WriteLine(obj.Member2);
// This value was reset after serialization.
Console.WriteLine(obj.Member3);
// This is a nonserialized value
Console.WriteLine(obj.Member4);
// null
obj = JsonConvert.DeserializeObject<SerializationEventTestObject>(json);
Console.WriteLine(obj.Member1);
// 11
Console.WriteLine(obj.Member2);
// This value went into the data file during serialization.
Console.WriteLine(obj.Member3);
// This value was set during deserialization
Console.WriteLine(obj.Member4);
// This value was set after deserialization.
}
}
}
#endif
@@ -0,0 +1,235 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Tests.TestObjects;
using NUnit.Framework;
namespace Newtonsoft.Json.Tests.Serialization
{
public class TypeNameHandlingTests : TestFixtureBase
{
[Test]
public void WriteTypeNameForObjects()
{
string employeeRef = typeof(EmployeeReference).AssemblyQualifiedName;
EmployeeReference employee = new EmployeeReference();
string json = JsonConvert.SerializeObject(employee, Formatting.Indented, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects
});
Assert.AreEqual(@"{
""$id"": ""1"",
""$type"": """ + employeeRef + @""",
""Name"": null,
""Manager"": null
}", json);
}
[Test]
public void DeserializeTypeName()
{
string employeeRef = typeof(EmployeeReference).AssemblyQualifiedName;
string json = @"{
""$id"": ""1"",
""$type"": """ + employeeRef + @""",
""Name"": ""Name!"",
""Manager"": null
}";
object employee = JsonConvert.DeserializeObject(json, null, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects
});
Assert.IsInstanceOfType(typeof(EmployeeReference), employee);
Assert.AreEqual("Name!", ((EmployeeReference)employee).Name);
}
[Test]
public void SerializeGenericObjectListWithTypeName()
{
string employeeRef = typeof(EmployeeReference).AssemblyQualifiedName;
string personRef = typeof(Person).AssemblyQualifiedName;
List<object> values = new List<object>
{
new EmployeeReference
{
Name = "Bob",
Manager = new EmployeeReference {Name = "Frank"}
},
new Person
{
Department = "Department",
BirthDate = new DateTime(2000, 12, 30, 0, 0, 0, DateTimeKind.Utc),
LastModified = new DateTime(2000, 12, 30, 0, 0, 0, DateTimeKind.Utc)
},
"String!",
int.MinValue
};
string json = JsonConvert.SerializeObject(values, Formatting.Indented, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects
});
Assert.AreEqual(@"[
{
""$id"": ""1"",
""$type"": """ + employeeRef + @""",
""Name"": ""Bob"",
""Manager"": {
""$id"": ""2"",
""$type"": """ + employeeRef + @""",
""Name"": ""Frank"",
""Manager"": null
}
},
{
""$type"": """ + personRef + @""",
""Name"": null,
""BirthDate"": ""\/Date(978134400000)\/"",
""LastModified"": ""\/Date(978134400000)\/""
},
""String!"",
-2147483648
]", json);
}
[Test]
public void DeserializeGenericObjectListWithTypeName()
{
string employeeRef = typeof(EmployeeReference).AssemblyQualifiedName;
string personRef = typeof(Person).AssemblyQualifiedName;
string json = @"[
{
""$id"": ""1"",
""$type"": """ + employeeRef + @""",
""Name"": ""Bob"",
""Manager"": {
""$id"": ""2"",
""$type"": """ + employeeRef + @""",
""Name"": ""Frank"",
""Manager"": null
}
},
{
""$type"": """ + personRef + @""",
""Name"": null,
""BirthDate"": ""\/Date(978134400000)\/"",
""LastModified"": ""\/Date(978134400000)\/""
},
""String!"",
-2147483648
]";
List<object> values = (List<object>)JsonConvert.DeserializeObject(json, typeof(List<object>), new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects
});
Assert.AreEqual(4, values.Count);
EmployeeReference e = (EmployeeReference)values[0];
Person p = (Person)values[1];
Assert.AreEqual("Bob", e.Name);
Assert.AreEqual("Frank", e.Manager.Name);
Assert.AreEqual(null, p.Name);
Assert.AreEqual(new DateTime(2000, 12, 30, 0, 0, 0, DateTimeKind.Utc), p.BirthDate);
Assert.AreEqual(new DateTime(2000, 12, 30, 0, 0, 0, DateTimeKind.Utc), p.LastModified);
Assert.AreEqual("String!", values[2]);
Assert.AreEqual(int.MinValue, values[3]);
}
[Test]
[ExpectedException(typeof(JsonSerializationException))]
public void DeserializeWithBadTypeName()
{
string employeeRef = typeof(EmployeeReference).AssemblyQualifiedName;
string json = @"{
""$id"": ""1"",
""$type"": """ + employeeRef + @""",
""Name"": ""Name!"",
""Manager"": null
}";
JsonConvert.DeserializeObject(json, typeof(Person), new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects
});
}
[Test]
public void DeserializeTypeNameWithNoTypeNameHandling()
{
string employeeRef = typeof(EmployeeReference).AssemblyQualifiedName;
string json = @"{
""$id"": ""1"",
""$type"": """ + employeeRef + @""",
""Name"": ""Name!"",
""Manager"": null
}";
JObject o = (JObject)JsonConvert.DeserializeObject(json);
Assert.AreEqual(@"{
""Name"": ""Name!"",
""Manager"": null
}", o.ToString());
}
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Type specified in JSON 'Newtonsoft.Json.Tests.TestObjects.Employee' was not resolved.")]
public void DeserializeTypeNameOnly()
{
string json = @"{
""$id"": ""1"",
""$type"": ""Newtonsoft.Json.Tests.TestObjects.Employee"",
""Name"": ""Name!"",
""Manager"": null
}";
JsonConvert.DeserializeObject(json, null, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects
});
}
}
}
@@ -31,9 +31,9 @@ using System.Text;
namespace Newtonsoft.Json.Tests.TestObjects
{
[JsonObject(IsReference = true)]
public class Employee
public class EmployeeReference
{
public string Name { get; set; }
public Employee Manager { get; set; }
public EmployeeReference Manager { get; set; }
}
}
@@ -1,4 +1,29 @@
using System;
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -19,7 +44,12 @@ namespace Newtonsoft.Json.Tests.TestObjects
}
private string _privateString;
private int i;
private readonly int i;
internal string _internalString;
public int UseValue()
{
return i;
}
}
}
@@ -0,0 +1,82 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
#if !PocketPC && !SILVERLIGHT
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace Newtonsoft.Json.Tests.TestObjects
{
public class SerializationEventTestDictionary : Dictionary<decimal, string>
{
// This member is serialized and deserialized with no change.
public int Member1 { get; private set; }
// The value of this field is set and reset during and
// after serialization.
public string Member2 { get; private set; }
// This field is not serialized. The OnDeserializedAttribute
// is used to set the member value after serialization.
public string Member3 { get; private set; }
// This field is set to null, but populated after deserialization.
public string Member4 { get; private set; }
public SerializationEventTestDictionary()
{
Member1 = 11;
Member2 = "Hello World!";
Member3 = "This is a nonserialized value";
Member4 = null;
}
[OnSerializing]
internal void OnSerializingMethod(StreamingContext context)
{
Member2 = "This value went into the data file during serialization.";
Add(decimal.MaxValue, "Inserted on serializing");
}
[OnSerialized]
internal void OnSerializedMethod(StreamingContext context)
{
Member2 = "This value was reset after serialization.";
}
[OnDeserializing]
internal void OnDeserializingMethod(StreamingContext context)
{
Member3 = "This value was set during deserialization";
}
[OnDeserialized]
internal void OnDeserializedMethod(StreamingContext context)
{
Member4 = "This value was set after deserialization.";
}
}
}
#endif
@@ -0,0 +1,82 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
#if !PocketPC && !SILVERLIGHT
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
namespace Newtonsoft.Json.Tests.TestObjects
{
public class SerializationEventTestList : Collection<decimal>
{
// This member is serialized and deserialized with no change.
public int Member1 { get; private set; }
// The value of this field is set and reset during and
// after serialization.
public string Member2 { get; private set; }
// This field is not serialized. The OnDeserializedAttribute
// is used to set the member value after serialization.
public string Member3 { get; private set; }
// This field is set to null, but populated after deserialization.
public string Member4 { get; private set; }
public SerializationEventTestList()
{
Member1 = 11;
Member2 = "Hello World!";
Member3 = "This is a nonserialized value";
Member4 = null;
}
[OnSerializing]
internal void OnSerializingMethod(StreamingContext context)
{
Member2 = "This value went into the data file during serialization.";
Insert(0, -1);
}
[OnSerialized]
internal void OnSerializedMethod(StreamingContext context)
{
Member2 = "This value was reset after serialization.";
}
[OnDeserializing]
internal void OnDeserializingMethod(StreamingContext context)
{
Member3 = "This value was set during deserialization";
}
[OnDeserialized]
internal void OnDeserializedMethod(StreamingContext context)
{
Member4 = "This value was set after deserialization.";
}
}
}
#endif
@@ -0,0 +1,84 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
#if !PocketPC && !SILVERLIGHT
using System;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
namespace Newtonsoft.Json.Tests.TestObjects
{
public class SerializationEventTestObject
{
// This member is serialized and deserialized with no change.
public int Member1 { get; set; }
// The value of this field is set and reset during and
// after serialization.
public string Member2 { get; set; }
// This field is not serialized. The OnDeserializedAttribute
// is used to set the member value after serialization.
[JsonIgnore]
public string Member3 { get; set; }
// This field is set to null, but populated after deserialization.
public string Member4 { get; set; }
public SerializationEventTestObject()
{
Member1 = 11;
Member2 = "Hello World!";
Member3 = "This is a nonserialized value";
Member4 = null;
}
[OnSerializing]
internal void OnSerializingMethod(StreamingContext context)
{
Member2 = "This value went into the data file during serialization.";
}
[OnSerialized]
internal void OnSerializedMethod(StreamingContext context)
{
Member2 = "This value was reset after serialization.";
}
[OnDeserializing]
internal void OnDeserializingMethod(StreamingContext context)
{
Member3 = "This value was set during deserialization";
}
[OnDeserialized]
internal void OnDeserializedMethod(StreamingContext context)
{
Member4 = "This value was set after deserialization.";
}
}
}
#endif
@@ -0,0 +1,83 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
#if !PocketPC && !SILVERLIGHT
using System.Runtime.Serialization;
namespace Newtonsoft.Json.Tests.TestObjects
{
public class SerializationEventTestObjectWithConstructor
{
// This member is serialized and deserialized with no change.
public int Member1 { get; private set; }
// The value of this field is set and reset during and
// after serialization.
public string Member2 { get; private set; }
// This field is not serialized. The OnDeserializedAttribute
// is used to set the member value after serialization.
[JsonIgnore]
public string Member3 { get; private set; }
// This field is set to null, but populated after deserialization.
public string Member4 { get; private set; }
public SerializationEventTestObjectWithConstructor(int member1,
string member2,
string member4)
{
Member1 = member1;
Member2 = member2;
Member3 = "This is a nonserialized value";
Member4 = member4;
}
[OnSerializing]
internal void OnSerializingMethod(StreamingContext context)
{
Member2 = "This value went into the data file during serialization.";
}
[OnSerialized]
internal void OnSerializedMethod(StreamingContext context)
{
Member2 = "This value was reset after serialization.";
}
[OnDeserializing]
internal void OnDeserializingMethod(StreamingContext context)
{
Member3 = "This value was set during deserialization";
}
[OnDeserialized]
internal void OnDeserializedMethod(StreamingContext context)
{
Member4 = "This value was set after deserialization.";
}
}
}
#endif
+1
View File
@@ -22,6 +22,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Doc", "Doc", "{8F9E13D9-418
Doc\donate.gif = Doc\donate.gif
Doc\Introduction.html = Doc\Introduction.html
Doc\LINQtoJSON.html = Doc\LINQtoJSON.html
Doc\PreserveObjectReferences.html = Doc\PreserveObjectReferences.html
Doc\ReadingWritingJSON.html = Doc\ReadingWritingJSON.html
Doc\SerializingJSON.html = Doc\SerializingJSON.html
Doc\styles.css = Doc\styles.css
+9 -1
View File
@@ -276,6 +276,14 @@ namespace Newtonsoft.Json
return text + ".0";
}
private static string EnsureDecimalPlace(string text)
{
if (text.IndexOf('.') != -1)
return text;
return text + ".0";
}
/// <summary>
/// Converts the <see cref="Byte"/> to it's JavaScript string representation.
/// </summary>
@@ -303,7 +311,7 @@ namespace Newtonsoft.Json
/// <returns>A Json string representation of the <see cref="SByte"/>.</returns>
public static string ToString(decimal value)
{
return value.ToString(null, CultureInfo.InvariantCulture);
return EnsureDecimalPlace(value.ToString(null, CultureInfo.InvariantCulture));
}
/// <summary>
@@ -24,9 +24,6 @@
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Newtonsoft.Json
{
+17 -21
View File
@@ -47,7 +47,7 @@ namespace Newtonsoft.Json
private NullValueHandling _nullValueHandling;
private DefaultValueHandling _defaultValueHandling;
private JsonConverterCollection _converters;
private IMappingResolver _mappingResolver;
private IContractResolver _contractResolver;
private IReferenceResolver _referenceResolver;
private SerializationBinder _binder;
@@ -212,13 +212,19 @@ namespace Newtonsoft.Json
}
/// <summary>
/// Gets or sets the mapping resolver used by the serializer when
/// mapping JSON properties to .NET objet members.
/// Gets or sets the contract resolver used by the serializer when
/// serializing .NET objects to JSON and vice versa.
/// </summary>
public virtual IMappingResolver MappingResolver
public virtual IContractResolver ContractResolver
{
get { return _mappingResolver; }
set { _mappingResolver = value; }
get
{
if (_contractResolver == null)
_contractResolver = DefaultContractResolver.Instance;
return _contractResolver;
}
set { _contractResolver = value; }
}
#endregion
@@ -238,10 +244,10 @@ namespace Newtonsoft.Json
}
/// <summary>
/// Creates a new <see cref="JsonSerializer"/> instance using the specified <see cref="JsonSerializerSettings"/> objects.
/// Creates a new <see cref="JsonSerializer"/> instance using the specified <see cref="JsonSerializerSettings"/>.
/// </summary>
/// <param name="settings">The settings.</param>
/// <returns></returns>
/// <param name="settings">The settings to be applied to the <see cref="JsonSerializer"/>.</param>
/// <returns>A new <see cref="JsonSerializer"/> instance using the specified <see cref="JsonSerializerSettings"/>.</returns>
public static JsonSerializer Create(JsonSerializerSettings settings)
{
JsonSerializer jsonSerializer = new JsonSerializer();
@@ -259,8 +265,8 @@ namespace Newtonsoft.Json
jsonSerializer.NullValueHandling = settings.NullValueHandling;
jsonSerializer.DefaultValueHandling = settings.DefaultValueHandling;
if (settings.MappingResolver != null)
jsonSerializer.MappingResolver = settings.MappingResolver;
if (settings.ContractResolver != null)
jsonSerializer.ContractResolver = settings.ContractResolver;
if (settings.ReferenceResolver != null)
jsonSerializer.ReferenceResolver = settings.ReferenceResolver;
if (settings.Binder != null)
@@ -380,16 +386,6 @@ namespace Newtonsoft.Json
return (converter != null);
}
internal JsonMemberMappingCollection GetMemberMappings(Type objectType)
{
ValidationUtils.ArgumentNotNull(objectType, "objectType");
if (_mappingResolver != null)
return _mappingResolver.ResolveMappings(objectType);
return DefaultMappingResolver.Instance.ResolveMappings(objectType);
}
internal bool HasMatchingConverter(Type type, out JsonConverter matchingConverter)
{
return HasMatchingConverter(_converters, type, out matchingConverter);
@@ -63,11 +63,11 @@ namespace Newtonsoft.Json
public TypeNameHandling TypeNameHandling { get; set; }
/// <summary>
/// Gets or sets the mapping resolver used by the serializer when
/// mapping JSON properties to .NET objet members.
/// Gets or sets the contract resolver used by the serializer when
/// serializing .NET objects to JSON and vice versa.
/// </summary>
/// <value>The mapping resolver.</value>
public IMappingResolver MappingResolver { get; set; }
/// <value>The contract resolver.</value>
public IContractResolver ContractResolver { get; set; }
/// <summary>
/// Gets or sets the <see cref="IReferenceResolver"/> used by the serializer when resolving references.
/// </summary>
+1 -1
View File
@@ -54,7 +54,7 @@ namespace Newtonsoft.Json.Linq
/// Gets or sets the property value.
/// </summary>
/// <value>The property value.</value>
public new JToken Value
public JToken Value
{
[DebuggerStepThrough]
get { return Last; }
+2 -2
View File
@@ -342,7 +342,7 @@ namespace Newtonsoft.Json.Linq
/// Returns the indented JSON for this token.
/// </summary>
/// <returns>
/// A <see cref="T:System.String"/> containing the indented JSON.
/// The indented JSON for this token.
/// </returns>
public override string ToString()
{
@@ -354,7 +354,7 @@ namespace Newtonsoft.Json.Linq
/// </summary>
/// <param name="formatting">Indicates how the output is formatted.</param>
/// <param name="converters">A collection of <see cref="JsonConverter"/> which will be used when writing the token.</param>
/// <returns></returns>
/// <returns>The JSON for this token using the given formatting and converters.</returns>
public string ToString(Formatting formatting, params JsonConverter[] converters)
{
using (StringWriter sw = new StringWriter(CultureInfo.InvariantCulture))
@@ -114,14 +114,15 @@
<Compile Include="Schema\ValidationEventHandler.cs" />
<Compile Include="SerializationBinder.cs" />
<Compile Include="Serialization\CachedAttributeGetter.cs" />
<Compile Include="Serialization\CamelCaseMappingResolver.cs" />
<Compile Include="Serialization\DefaultMappingResolver.cs" />
<Compile Include="Serialization\CamelCasePropertyNamesContractResolver.cs" />
<Compile Include="Serialization\DefaultContractResolver.cs" />
<Compile Include="Serialization\DefaultReferenceResolver.cs" />
<Compile Include="Serialization\DefaultSerializationBinder.cs" />
<Compile Include="Serialization\IMappingResolver.cs" />
<Compile Include="Serialization\IContractResolver.cs" />
<Compile Include="Serialization\IReferenceResolver.cs" />
<Compile Include="Serialization\JsonMemberMapping.cs" />
<Compile Include="Serialization\JsonMemberMappingCollection.cs" />
<Compile Include="Serialization\JsonArrayContract.cs" />
<Compile Include="Serialization\JsonContract.cs" />
<Compile Include="Serialization\JsonDictionaryContract.cs" />
<Compile Include="MissingMemberHandling.cs" />
<Compile Include="NullValueHandling.cs" />
<Compile Include="ReferenceLoopHandling.cs" />
@@ -131,6 +132,9 @@
<Compile Include="Schema\JsonSchemaGenerator.cs" />
<Compile Include="Schema\JsonSchemaResolver.cs" />
<Compile Include="Schema\JsonSchemaType.cs" />
<Compile Include="Serialization\JsonObjectContract.cs" />
<Compile Include="Serialization\JsonProperty.cs" />
<Compile Include="Serialization\JsonPropertyCollection.cs" />
<Compile Include="Serialization\JsonSerializerProxy.cs" />
<Compile Include="Serialization\JsonSerializerReader.cs" />
<Compile Include="Serialization\JsonSerializerWriter.cs" />
@@ -104,12 +104,18 @@
<Compile Include="ReferenceLoopHandling.cs" />
<Compile Include="SerializationBinder.cs" />
<Compile Include="Serialization\CachedAttributeGetter.cs" />
<Compile Include="Serialization\CamelCaseMappingResolver.cs" />
<Compile Include="Serialization\DefaultMappingResolver.cs" />
<Compile Include="Serialization\CamelCasePropertyNamesContractResolver.cs" />
<Compile Include="Serialization\DefaultContractResolver.cs" />
<Compile Include="Serialization\DefaultReferenceResolver.cs" />
<Compile Include="Serialization\DefaultSerializationBinder.cs" />
<Compile Include="Serialization\IMappingResolver.cs" />
<Compile Include="Serialization\IContractResolver.cs" />
<Compile Include="Serialization\IReferenceResolver.cs" />
<Compile Include="Serialization\JsonArrayContract.cs" />
<Compile Include="Serialization\JsonContract.cs" />
<Compile Include="Serialization\JsonDictionaryContract.cs" />
<Compile Include="Serialization\JsonObjectContract.cs" />
<Compile Include="Serialization\JsonProperty.cs" />
<Compile Include="Serialization\JsonPropertyCollection.cs" />
<Compile Include="Serialization\JsonSerializerProxy.cs" />
<Compile Include="Serialization\JsonSerializerReader.cs" />
<Compile Include="Serialization\JsonSerializerWriter.cs" />
@@ -149,8 +155,6 @@
<Compile Include="Schema\JsonSchemaResolver.cs" />
<Compile Include="Schema\JsonSchemaType.cs" />
<Compile Include="Serialization\JsonTypeReflector.cs" />
<Compile Include="Serialization\JsonMemberMapping.cs" />
<Compile Include="Serialization\JsonMemberMappingCollection.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight\v2.0\Microsoft.Silverlight.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+9 -5
View File
@@ -141,12 +141,15 @@
<Compile Include="Schema\UndefinedSchemaIdHandling.cs" />
<Compile Include="Schema\ValidationEventArgs.cs" />
<Compile Include="Schema\ValidationEventHandler.cs" />
<Compile Include="Serialization\CamelCaseMappingResolver.cs" />
<Compile Include="Serialization\DefaultMappingResolver.cs" />
<Compile Include="Serialization\CamelCasePropertyNamesContractResolver.cs" />
<Compile Include="Serialization\DefaultContractResolver.cs" />
<Compile Include="Serialization\DefaultSerializationBinder.cs" />
<Compile Include="Serialization\IMappingResolver.cs" />
<Compile Include="Serialization\JsonMemberMapping.cs" />
<Compile Include="Serialization\JsonMemberMappingCollection.cs" />
<Compile Include="Serialization\IContractResolver.cs" />
<Compile Include="Serialization\JsonArrayContract.cs" />
<Compile Include="Serialization\JsonContract.cs" />
<Compile Include="Serialization\JsonDictionaryContract.cs" />
<Compile Include="Serialization\JsonProperty.cs" />
<Compile Include="Serialization\JsonPropertyCollection.cs" />
<Compile Include="MissingMemberHandling.cs" />
<Compile Include="NullValueHandling.cs" />
<Compile Include="ReferenceLoopHandling.cs" />
@@ -156,6 +159,7 @@
<Compile Include="Schema\JsonSchemaGenerator.cs" />
<Compile Include="Serialization\IReferenceResolver.cs" />
<Compile Include="Schema\JsonSchemaType.cs" />
<Compile Include="Serialization\JsonObjectContract.cs" />
<Compile Include="Serialization\JsonSerializerProxy.cs" />
<Compile Include="Serialization\JsonSerializerReader.cs" />
<Compile Include="Serialization\JsonSerializerWriter.cs" />
+1 -1
View File
@@ -231,7 +231,7 @@ namespace Newtonsoft.Json.Schema
/// </summary>
/// <param name="json">The json.</param>
/// <param name="resolver">The resolver.</param>
/// <returns></returns>
/// <returns>A <see cref="JsonSchema"/> populated from the string that contains JSON.</returns>
public static JsonSchema Parse(string json, JsonSchemaResolver resolver)
{
ValidationUtils.ArgumentNotNull(json, "json");
@@ -1,4 +1,4 @@
#region License
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
@@ -43,11 +43,23 @@ namespace Newtonsoft.Json.Schema
/// Gets or sets how undefined schemas are handled by the serializer.
/// </summary>
public UndefinedSchemaIdHandling UndefinedSchemaIdHandling { get; set; }
private IContractResolver _contractResolver;
/// <summary>
/// Gets or sets the mapping resolver used by the generator when
/// mapping JSON properties to .NET objet members.
/// Gets or sets the contract resolver.
/// </summary>
public IMappingResolver MappingResolver { get; set; }
/// <value>The contract resolver.</value>
public IContractResolver ContractResolver
{
get
{
if (_contractResolver == null)
return DefaultContractResolver.Instance;
return _contractResolver;
}
set { _contractResolver = value; }
}
private class TypeSchema
{
@@ -271,25 +283,23 @@ namespace Newtonsoft.Json.Schema
{
CurrentSchema.Id = GetTypeId(type, false);
JsonMemberMappingCollection mappings;
JsonObjectContract contract = ContractResolver.ResolveContract(type) as JsonObjectContract;
if (MappingResolver != null)
mappings = MappingResolver.ResolveMappings(type);
else
mappings = DefaultMappingResolver.Instance.ResolveMappings(type);
if (contract == null)
throw new Exception("Could not resolve contract for '{0}'.".FormatWith(CultureInfo.InvariantCulture, type));
CurrentSchema.Properties = new Dictionary<string, JsonSchema>();
foreach (JsonMemberMapping mapping in mappings)
foreach (JsonProperty property in contract.Properties)
{
if (!mapping.Ignored)
if (!property.Ignored)
{
Type propertyMemberType = ReflectionUtils.GetMemberUnderlyingType(mapping.Member);
JsonSchema propertySchema = GenerateInternal(propertyMemberType, mapping.Required);
Type propertyMemberType = ReflectionUtils.GetMemberUnderlyingType(property.Member);
JsonSchema propertySchema = GenerateInternal(propertyMemberType, property.Required);
if (mapping.DefaultValue != null)
propertySchema.Default = JToken.FromObject(mapping.DefaultValue);
if (property.DefaultValue != null)
propertySchema.Default = JToken.FromObject(property.DefaultValue);
CurrentSchema.Properties.Add(mapping.PropertyName, propertySchema);
CurrentSchema.Properties.Add(property.PropertyName, propertySchema);
}
}
@@ -1,4 +1,4 @@
#region License
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
@@ -23,10 +23,6 @@
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
namespace Newtonsoft.Json.Serialization
@@ -34,13 +30,13 @@ namespace Newtonsoft.Json.Serialization
/// <summary>
/// Resolves member mappings for a type, camel casing property names.
/// </summary>
public class CamelCaseMappingResolver : DefaultMappingResolver
public class CamelCasePropertyNamesContractResolver : DefaultContractResolver
{
/// <summary>
/// Resolves the name of the property.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
/// <returns></returns>
/// <returns>The property name camel cased.</returns>
protected override string ResolvePropertyName(string propertyName)
{
// lower case the first letter of the passed in name
@@ -0,0 +1,340 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Runtime.Serialization;
using Newtonsoft.Json.Utilities;
namespace Newtonsoft.Json.Serialization
{
/// <summary>
/// Used by <see cref="JsonSerializer"/> to resolves a <see cref="JsonContract"/> for a given <see cref="Type"/>.
/// </summary>
public class DefaultContractResolver : IContractResolver
{
internal static readonly IContractResolver Instance = new DefaultContractResolver();
private readonly ThreadSafeStore<Type, JsonContract> _typeContractCache;
/// <summary>
/// Gets or sets the default members search flags.
/// </summary>
/// <value>The default members search flags.</value>
public BindingFlags DefaultMembersSearchFlags { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="DefaultContractResolver"/> class.
/// </summary>
public DefaultContractResolver()
{
DefaultMembersSearchFlags = BindingFlags.Public | BindingFlags.Instance;
_typeContractCache = new ThreadSafeStore<Type, JsonContract>(CreateContract);
}
/// <summary>
/// Resolves the contract for a given type.
/// </summary>
/// <param name="type">The type to resolve a contract for.</param>
/// <returns>The contract for a given type.</returns>
public virtual JsonContract ResolveContract(Type type)
{
return _typeContractCache.Get(type);
}
/// <summary>
/// Gets the serializable members for the type.
/// </summary>
/// <param name="objectType">The type to get serializable members for.</param>
/// <returns>The serializable members for the type.</returns>
protected virtual List<MemberInfo> GetSerializableMembers(Type objectType)
{
#if !PocketPC
DataContractAttribute dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(objectType);
#endif
List<MemberInfo> defaultMembers = ReflectionUtils.GetFieldsAndProperties(objectType, DefaultMembersSearchFlags);
List<MemberInfo> allMembers = ReflectionUtils.GetFieldsAndProperties(objectType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
List<MemberInfo> serializableMembers = new List<MemberInfo>();
foreach (MemberInfo member in allMembers)
{
if (defaultMembers.Contains(member))
{
serializableMembers.Add(member);
}
else
{
if (JsonTypeReflector.GetAttribute<JsonPropertyAttribute>(member) != null)
serializableMembers.Add(member);
#if !PocketPC
else if (dataContractAttribute != null && JsonTypeReflector.GetAttribute<DataMemberAttribute>(member) != null)
serializableMembers.Add(member);
#endif
}
}
return serializableMembers;
}
/// <summary>
/// Creates a <see cref="JsonObjectContract"/> for the given type.
/// </summary>
/// <param name="objectType">Type of the object.</param>
/// <returns>A <see cref="JsonObjectContract"/> for the given type.</returns>
protected virtual JsonObjectContract CreateObjectContract(Type objectType)
{
JsonObjectContract contract = new JsonObjectContract(objectType);
InitializeContract(contract);
contract.MemberSerialization = JsonTypeReflector.GetObjectMemberSerialization(objectType);
contract.Properties.AddRange(CreateProperties(contract));
return contract;
}
private void InitializeContract(JsonContract contract)
{
JsonContainerAttribute containerAttribute = JsonTypeReflector.GetJsonContainerAttribute(contract.UnderlyingType);
if (containerAttribute != null)
contract.IsReference = containerAttribute._isReference;
#if !PocketPC && !SILVERLIGHT
foreach (MethodInfo method in contract.UnderlyingType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
{
Type prevAttributeType = null;
ParameterInfo[] parameters = method.GetParameters();
if (IsValidCallback(method, parameters, typeof(OnSerializingAttribute), contract.OnSerializing, ref prevAttributeType))
{
contract.OnSerializing = method;
}
if (IsValidCallback(method, parameters, typeof(OnSerializedAttribute), contract.OnSerialized, ref prevAttributeType))
{
contract.OnSerialized = method;
}
if (IsValidCallback(method, parameters, typeof(OnDeserializingAttribute), contract.OnDeserializing, ref prevAttributeType))
{
contract.OnDeserializing = method;
}
if (IsValidCallback(method, parameters, typeof(OnDeserializedAttribute), contract.OnDeserialized, ref prevAttributeType))
{
contract.OnDeserialized = method;
}
}
#endif
}
/// <summary>
/// Creates a <see cref="JsonDictionaryContract"/> for the given type.
/// </summary>
/// <param name="objectType">Type of the object.</param>
/// <returns>A <see cref="JsonDictionaryContract"/> for the given type.</returns>
protected virtual JsonDictionaryContract CreateDictionaryContract(Type objectType)
{
JsonDictionaryContract contract = new JsonDictionaryContract(objectType);
InitializeContract(contract);
return contract;
}
/// <summary>
/// Creates a <see cref="JsonArrayContract"/> for the given type.
/// </summary>
/// <param name="objectType">Type of the object.</param>
/// <returns>A <see cref="JsonArrayContract"/> for the given type.</returns>
protected virtual JsonArrayContract CreateArrayContract(Type objectType)
{
JsonArrayContract contract = new JsonArrayContract(objectType);
InitializeContract(contract);
return contract;
}
private JsonContract CreateContract(Type objectType)
{
if (JsonTypeReflector.GetJsonObjectAttribute(objectType) != null)
{
return CreateObjectContract(objectType);
}
if (CollectionUtils.IsDictionaryType(objectType))
{
return CreateDictionaryContract(objectType);
}
if (typeof(IEnumerable).IsAssignableFrom(objectType))
{
return CreateArrayContract(objectType);
}
return CreateObjectContract(objectType);
}
#if !PocketPC && !SILVERLIGHT
private static bool IsValidCallback(MethodInfo method, ParameterInfo[] parameters, Type attributeType, MethodInfo currentCallback, ref Type prevAttributeType)
{
if (!method.IsDefined(attributeType, false))
return false;
if (currentCallback != null)
throw new Exception("Invalid attribute. Both '{0}' and '{1}' in type '{2}' have '{3}'.".FormatWith(CultureInfo.InvariantCulture, method, currentCallback, GetClrTypeFullName(method.DeclaringType), attributeType));
if (prevAttributeType != null)
throw new Exception("Invalid Callback. Method '{3}' in type '{2}' has both '{0}' and '{1}'.".FormatWith(CultureInfo.InvariantCulture, prevAttributeType, attributeType, GetClrTypeFullName(method.DeclaringType), method));
if (method.IsVirtual)
throw new Exception("Virtual Method '{0}' of type '{1}' cannot be marked with '{2}' attribute.".FormatWith(CultureInfo.InvariantCulture, method, GetClrTypeFullName(method.DeclaringType), attributeType));
if (method.ReturnType != typeof(void))
throw new Exception("Serialization Callback '{1}' in type '{0}' must return void.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType), method));
if (parameters == null || parameters.Length != 1 || parameters[0].ParameterType != typeof(StreamingContext))
throw new Exception("Serialization Callback '{1}' in type '{0}' must have a single parameter of type '{2}'.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType), method, typeof(StreamingContext)));
prevAttributeType = attributeType;
return true;
}
#endif
internal static string GetClrTypeFullName(Type type)
{
if (type.IsGenericTypeDefinition || !type.ContainsGenericParameters)
return type.FullName;
return string.Format(CultureInfo.InvariantCulture, "{0}.{1}", new object[] { type.Namespace, type.Name });
}
/// <summary>
/// Creates properties for the given <see cref="JsonObjectContract"/>.
/// </summary>
/// <param name="contract">The contract to create properties for.</param>
/// <returns>Properties for the given <see cref="JsonObjectContract"/>.</returns>
protected virtual IList<JsonProperty> CreateProperties(JsonObjectContract contract)
{
List<MemberInfo> members = GetSerializableMembers(contract.UnderlyingType);
if (members == null)
throw new JsonSerializationException("Null collection of seralizable members returned.");
JsonPropertyCollection properties = new JsonPropertyCollection();
foreach (MemberInfo member in members)
{
JsonProperty property = CreateProperty(contract, member);
if (property != null)
properties.AddProperty(property);
}
return properties;
}
/// <summary>
/// Creates a <see cref="JsonProperty"/> for the given <see cref="MemberInfo"/>.
/// </summary>
/// <param name="contract">The member's declaring types <see cref="JsonObjectContract"/>.</param>
/// <param name="member">The member to create a <see cref="JsonProperty"/> for.</param>
/// <returns>A created <see cref="JsonProperty"/> for the given <see cref="MemberInfo"/>.</returns>
protected virtual JsonProperty CreateProperty(JsonObjectContract contract, MemberInfo member)
{
JsonProperty property = new JsonProperty();
property.Member = member;
JsonObjectAttribute jsonObjectAttribute = JsonTypeReflector.GetJsonObjectAttribute(member.DeclaringType);
#if !PocketPC
DataContractAttribute dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(member.DeclaringType);
DataMemberAttribute dataMemberAttribute;
if (dataContractAttribute != null)
dataMemberAttribute = JsonTypeReflector.GetAttribute<DataMemberAttribute>(member);
else
dataMemberAttribute = null;
#endif
JsonPropertyAttribute propertyAttribute = JsonTypeReflector.GetAttribute<JsonPropertyAttribute>(member);
bool hasIgnoreAttribute = (JsonTypeReflector.GetAttribute<JsonIgnoreAttribute>(member) != null);
string mappedName;
if (propertyAttribute != null && propertyAttribute.PropertyName != null)
mappedName = propertyAttribute.PropertyName;
#if !PocketPC
else if (dataMemberAttribute != null && dataMemberAttribute.Name != null)
mappedName = dataMemberAttribute.Name;
#endif
else
mappedName = member.Name;
property.PropertyName = ResolvePropertyName(mappedName);
if (propertyAttribute != null)
property.Required = propertyAttribute.IsRequired;
#if !PocketPC
else if (dataMemberAttribute != null)
property.Required = dataMemberAttribute.IsRequired;
#endif
else
property.Required = false;
property.Ignored = (hasIgnoreAttribute ||
(contract.MemberSerialization == MemberSerialization.OptIn
&& propertyAttribute == null
#if !PocketPC
&& dataMemberAttribute == null
#endif
));
property.Readable = ReflectionUtils.CanReadMemberValue(member);
property.Writable = ReflectionUtils.CanSetMemberValue(member);
property.MemberConverter = JsonTypeReflector.GetConverter(member, ReflectionUtils.GetMemberUnderlyingType(member));
DefaultValueAttribute defaultValueAttribute = JsonTypeReflector.GetAttribute<DefaultValueAttribute>(member);
property.DefaultValue = (defaultValueAttribute != null) ? defaultValueAttribute.Value : null;
property.NullValueHandling = (propertyAttribute != null) ? propertyAttribute._nullValueHandling : null;
property.DefaultValueHandling = (propertyAttribute != null) ? propertyAttribute._defaultValueHandling : null;
property.ReferenceLoopHandling = (propertyAttribute != null) ? propertyAttribute._referenceLoopHandling : null;
property.IsReference = (jsonObjectAttribute != null) ? jsonObjectAttribute._isReference : null;
return property;
}
/// <summary>
/// Resolves the name of the property.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
/// <returns>Name of the property.</returns>
protected virtual string ResolvePropertyName(string propertyName)
{
return propertyName;
}
}
}
@@ -1,207 +0,0 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Runtime.Serialization;
using Newtonsoft.Json.Utilities;
namespace Newtonsoft.Json.Serialization
{
/// <summary>
/// Resolves member mappings for a type.
/// </summary>
public class DefaultMappingResolver : IMappingResolver
{
internal static readonly IMappingResolver Instance = new DefaultMappingResolver();
private readonly ThreadSafeStore<Type, JsonMemberMappingCollection> _typeMemberMappingsCache;
/// <summary>
/// Gets or sets the default members search flags.
/// </summary>
/// <value>The default members search flags.</value>
public BindingFlags DefaultMembersSearchFlags { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="DefaultMappingResolver"/> class.
/// </summary>
public DefaultMappingResolver()
{
DefaultMembersSearchFlags = BindingFlags.Public | BindingFlags.Instance;
_typeMemberMappingsCache = new ThreadSafeStore<Type, JsonMemberMappingCollection>(CreateMemberMappings);
}
/// <summary>
/// Returns a collection of <see cref="JsonMemberMapping"/> for the specified <see cref="Type"/>
/// to be used during serialization.
/// </summary>
/// <param name="type">The type to be resolved.</param>
/// <returns>A collection of <see cref="JsonMemberMapping"/> to be used during serialization.</returns>
public virtual JsonMemberMappingCollection ResolveMappings(Type type)
{
return _typeMemberMappingsCache.Get(type);
}
/// <summary>
/// Gets the serializable members for the type.
/// </summary>
/// <param name="objectType">The type to get serializable members for.</param>
/// <returns>The serializable members for the type.</returns>
protected virtual List<MemberInfo> GetSerializableMembers(Type objectType)
{
#if !PocketPC
DataContractAttribute dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(objectType);
#endif
List<MemberInfo> defaultMembers = ReflectionUtils.GetFieldsAndProperties(objectType, DefaultMembersSearchFlags);
List<MemberInfo> allMembers = ReflectionUtils.GetFieldsAndProperties(objectType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
List<MemberInfo> serializableMembers = new List<MemberInfo>();
foreach (MemberInfo member in allMembers)
{
if (defaultMembers.Contains(member))
{
serializableMembers.Add(member);
}
else
{
if (JsonTypeReflector.GetAttribute<JsonPropertyAttribute>(member) != null)
serializableMembers.Add(member);
#if !PocketPC
else if (dataContractAttribute != null && JsonTypeReflector.GetAttribute<DataMemberAttribute>(member) != null)
serializableMembers.Add(member);
#endif
}
}
return serializableMembers;
}
private JsonMemberMappingCollection CreateMemberMappings(Type objectType)
{
MemberSerialization memberSerialization = JsonTypeReflector.GetObjectMemberSerialization(objectType);
List<MemberInfo> members = GetSerializableMembers(objectType);
if (members == null)
throw new JsonSerializationException("Null collection of seralizable members returned.");
JsonMemberMappingCollection memberMappings = new JsonMemberMappingCollection();
foreach (MemberInfo member in members)
{
JsonMemberMapping memberMapping = CreateMemberMapping(memberSerialization, member);
if (memberMapping != null)
memberMappings.AddMapping(memberMapping);
}
return memberMappings;
}
/// <summary>
/// Creates a <see cref="JsonMemberMapping"/> for the given <see cref="MemberInfo"/>.
/// </summary>
/// <param name="memberSerialization">The member's declaring type member serialization mode.</param>
/// <param name="member">The member to create a <see cref="JsonMemberMapping"/> for.</param>
/// <returns>A created <see cref="JsonMemberMapping"/> for the given <see cref="MemberInfo"/>.</returns>
protected virtual JsonMemberMapping CreateMemberMapping(MemberSerialization memberSerialization, MemberInfo member)
{
JsonObjectAttribute jsonObjectAttribute = JsonTypeReflector.GetJsonObjectAttribute(member.DeclaringType);
#if !PocketPC
DataContractAttribute dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(member.DeclaringType);
DataMemberAttribute dataMemberAttribute;
if (dataContractAttribute != null)
dataMemberAttribute = JsonTypeReflector.GetAttribute<DataMemberAttribute>(member);
else
dataMemberAttribute = null;
#endif
JsonPropertyAttribute propertyAttribute = JsonTypeReflector.GetAttribute<JsonPropertyAttribute>(member);
bool hasIgnoreAttribute = (JsonTypeReflector.GetAttribute<JsonIgnoreAttribute>(member) != null);
string mappedName;
if (propertyAttribute != null && propertyAttribute.PropertyName != null)
mappedName = propertyAttribute.PropertyName;
#if !PocketPC
else if (dataMemberAttribute != null && dataMemberAttribute.Name != null)
mappedName = dataMemberAttribute.Name;
#endif
else
mappedName = member.Name;
string resolvedMappedName = ResolvePropertyName(mappedName);
bool required;
if (propertyAttribute != null)
required = propertyAttribute.IsRequired;
#if !PocketPC
else if (dataMemberAttribute != null)
required = dataMemberAttribute.IsRequired;
#endif
else
required = false;
bool ignored = (hasIgnoreAttribute ||
(memberSerialization == MemberSerialization.OptIn
&& propertyAttribute == null
#if !PocketPC
&& dataMemberAttribute == null
#endif
));
bool readable = ReflectionUtils.CanReadMemberValue(member);
bool writable = ReflectionUtils.CanSetMemberValue(member);
JsonConverter memberConverter = JsonTypeReflector.GetConverter(member, ReflectionUtils.GetMemberUnderlyingType(member));
DefaultValueAttribute defaultValueAttribute = JsonTypeReflector.GetAttribute<DefaultValueAttribute>(member);
object defaultValue = (defaultValueAttribute != null) ? defaultValueAttribute.Value : null;
NullValueHandling? nullValueHandling = (propertyAttribute != null) ? propertyAttribute._nullValueHandling : null;
DefaultValueHandling? defaultValueHandling = (propertyAttribute != null) ? propertyAttribute._defaultValueHandling : null;
ReferenceLoopHandling? referenceLoopHandling = (propertyAttribute != null) ? propertyAttribute._referenceLoopHandling : null;
bool? isReference = (jsonObjectAttribute != null) ? jsonObjectAttribute._isReference : null;
return new JsonMemberMapping(resolvedMappedName, member, ignored, readable, writable, memberConverter, defaultValue, required, isReference, nullValueHandling, defaultValueHandling, referenceLoopHandling);
}
/// <summary>
/// Resolves the name of the property.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
/// <returns></returns>
protected virtual string ResolvePropertyName(string propertyName)
{
return propertyName;
}
}
}
@@ -31,16 +31,15 @@ using System.Text;
namespace Newtonsoft.Json.Serialization
{
/// <summary>
/// Resolves member mappings for a type.
/// Used by <see cref="JsonSerializer"/> to resolves a <see cref="JsonContract"/> for a given <see cref="Type"/>.
/// </summary>
public interface IMappingResolver
public interface IContractResolver
{
/// <summary>
/// Returns a collection of <see cref="JsonMemberMapping"/> for the specified <see cref="Type"/>
/// to be used during serialization.
/// Resolves the contract for a given type.
/// </summary>
/// <param name="type">The type to be resolved.</param>
/// <returns>A collection of <see cref="JsonMemberMapping"/> to be used during serialization.</returns>
JsonMemberMappingCollection ResolveMappings(Type type);
/// <param name="type">The type to resolve a contract for.</param>
/// <returns>The contract for a given type.</returns>
JsonContract ResolveContract(Type type);
}
}
@@ -0,0 +1,72 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Collections.Generic;
using Newtonsoft.Json.Utilities;
namespace Newtonsoft.Json.Serialization
{
/// <summary>
/// Contract details for a <see cref="Type"/> used by the <see cref="JsonSerializer"/>.
/// </summary>
public class JsonArrayContract : JsonContract
{
internal Type CollectionTypeToCreate { get; private set; }
internal Type CollectionItemType { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="JsonArrayContract"/> class.
/// </summary>
/// <param name="underlyingType">The underlying type for the contract.</param>
public JsonArrayContract(Type underlyingType)
: base(underlyingType)
{
CollectionItemType = ReflectionUtils.GetCollectionItemType(UnderlyingType);
if (IsTypeGenericCollectionInterface(UnderlyingType))
{
Type itemType = ReflectionUtils.GetCollectionItemType(UnderlyingType);
CollectionTypeToCreate = ReflectionUtils.MakeGenericType(typeof(List<>), itemType);
}
else
{
CollectionTypeToCreate = UnderlyingType;
}
}
private bool IsTypeGenericCollectionInterface(Type type)
{
if (!type.IsGenericType)
return false;
Type genericDefinition = type.GetGenericTypeDefinition();
return (genericDefinition == typeof(IList<>)
|| genericDefinition == typeof(ICollection<>)
|| genericDefinition == typeof(IEnumerable<>));
}
}
}
@@ -0,0 +1,113 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Reflection;
using System.Runtime.Serialization;
using Newtonsoft.Json.Utilities;
namespace Newtonsoft.Json.Serialization
{
/// <summary>
/// Contract details for a <see cref="Type"/> used by the <see cref="JsonSerializer"/>.
/// </summary>
public abstract class JsonContract
{
/// <summary>
/// Gets the underlying type for the contract.
/// </summary>
/// <value>The underlying type for the contract.</value>
public Type UnderlyingType { get; private set; }
/// <summary>
/// Gets or sets whether this type contract is serialized as a reference.
/// </summary>
/// <value>Whether this type contract is serialized as a reference.</value>
public bool? IsReference { get; set; }
#if !PocketPC && !SILVERLIGHT
private static readonly object[] SerializationEventParameterValues = new object[] { new StreamingContext(StreamingContextStates.All) };
/// <summary>
/// Gets or sets the method called immediately after deserialization of the object.
/// </summary>
/// <value>The method called immediately after deserialization of the object.</value>
public MethodInfo OnDeserialized { get; set; }
/// <summary>
/// Gets or sets the method called during deserialization of the object.
/// </summary>
/// <value>The method called during deserialization of the object.</value>
public MethodInfo OnDeserializing { get; set; }
/// <summary>
/// Gets or sets the method called after serialization of the object graph.
/// </summary>
/// <value>The method called after serialization of the object graph.</value>
public MethodInfo OnSerialized { get; set; }
/// <summary>
/// Gets or sets the method called before serialization of the object.
/// </summary>
/// <value>The method called before serialization of the object.</value>
public MethodInfo OnSerializing { get; set; }
#endif
internal void InvokeOnSerializing(object o)
{
#if !PocketPC && !SILVERLIGHT
if (OnSerializing != null)
OnSerializing.Invoke(o, SerializationEventParameterValues);
#endif
}
internal void InvokeOnSerialized(object o)
{
#if !PocketPC && !SILVERLIGHT
if (OnSerialized != null)
OnSerialized.Invoke(o, SerializationEventParameterValues);
#endif
}
internal void InvokeOnDeserializing(object o)
{
#if !PocketPC && !SILVERLIGHT
if (OnDeserializing != null)
OnDeserializing.Invoke(o, SerializationEventParameterValues);
#endif
}
internal void InvokeOnDeserialized(object o)
{
#if !PocketPC && !SILVERLIGHT
if (OnDeserialized != null)
OnDeserialized.Invoke(o, SerializationEventParameterValues);
#endif
}
internal JsonContract(Type underlyingType)
{
ValidationUtils.ArgumentNotNull(underlyingType, "underlyingType");
UnderlyingType = underlyingType;
}
}
}
@@ -0,0 +1,75 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Collections.Generic;
using Newtonsoft.Json.Utilities;
namespace Newtonsoft.Json.Serialization
{
/// <summary>
/// Contract details for a <see cref="Type"/> used by the <see cref="JsonSerializer"/>.
/// </summary>
public class JsonDictionaryContract : JsonContract
{
internal Type DictionaryTypeToCreate { get; private set; }
internal Type DictionaryKeyType { get; private set; }
internal Type DictionaryValueType { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="JsonDictionaryContract"/> class.
/// </summary>
/// <param name="underlyingType">The underlying type for the contract.</param>
public JsonDictionaryContract(Type underlyingType)
: base(underlyingType)
{
Type keyType;
Type valueType;
ReflectionUtils.GetDictionaryKeyValueTypes(UnderlyingType, out keyType, out valueType);
DictionaryKeyType = keyType;
DictionaryValueType = valueType;
if (IsTypeGenericDictionaryInterface(UnderlyingType))
{
DictionaryTypeToCreate = ReflectionUtils.MakeGenericType(typeof(Dictionary<,>), keyType, valueType);
}
else
{
DictionaryTypeToCreate = underlyingType;
}
}
private bool IsTypeGenericDictionaryInterface(Type type)
{
if (!type.IsGenericType)
return false;
Type genericDefinition = type.GetGenericTypeDefinition();
return (genericDefinition == typeof(IDictionary<,>));
}
}
}
@@ -1,189 +0,0 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
using System.Reflection;
namespace Newtonsoft.Json.Serialization
{
/// <summary>
/// Maps a JSON property to a .NET member.
/// </summary>
public class JsonMemberMapping
{
private readonly string _propertyName;
private readonly MemberInfo _member;
private readonly bool _ignored;
private readonly bool _readable;
private readonly bool _writable;
private readonly JsonConverter _memberConverter;
private readonly object _defaultValue;
private readonly bool _required;
private readonly bool? _isReference;
private readonly NullValueHandling? _nullValueHandling;
private readonly DefaultValueHandling? _defaultValueHandling;
private readonly ReferenceLoopHandling? _referenceLoopHandling;
/// <summary>
/// Initializes a new instance of the <see cref="JsonMemberMapping"/> class.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
/// <param name="member">The member.</param>
/// <param name="ignored">If set to <c>true</c> mapping is ignored during serialization.</param>
/// <param name="readable">If set to <c>true</c> mapping is readable.</param>
/// <param name="writable">If set to <c>true</c> mapping is writable.</param>
/// <param name="memberConverter">The member converter to use during serialization.</param>
/// <param name="defaultValue">The mapping default value.</param>
/// <param name="required">If set to <c>true</c> mapping is required during serialization.</param>
/// <param name="isReference">If set to <c>true</c> mapping preserve reference.</param>
/// <param name="nullValueHandling">Mapping null value handling.</param>
/// <param name="defaultValueHandling">Mapping default value handling.</param>
/// <param name="referenceLoopHandling">Mapping reference loop handling.</param>
public JsonMemberMapping(string propertyName, MemberInfo member, bool ignored, bool readable, bool writable, JsonConverter memberConverter, object defaultValue, bool required, bool? isReference, NullValueHandling? nullValueHandling, DefaultValueHandling? defaultValueHandling, ReferenceLoopHandling? referenceLoopHandling)
{
_propertyName = propertyName;
_member = member;
_ignored = ignored;
_readable = readable;
_writable = writable;
_memberConverter = memberConverter;
_defaultValue = defaultValue;
_required = required;
_isReference = isReference;
_nullValueHandling = nullValueHandling;
_defaultValueHandling = defaultValueHandling;
_referenceLoopHandling = referenceLoopHandling;
}
/// <summary>
/// Gets the name of the property.
/// </summary>
/// <value>The name of the property.</value>
public string PropertyName
{
get { return _propertyName; }
}
/// <summary>
/// Gets the member.
/// </summary>
/// <value>The member.</value>
public MemberInfo Member
{
get { return _member; }
}
/// <summary>
/// Gets a value indicating whether this <see cref="JsonMemberMapping"/> is ignored.
/// </summary>
/// <value><c>true</c> if ignored; otherwise, <c>false</c>.</value>
public bool Ignored
{
get { return _ignored; }
}
/// <summary>
/// Gets a value indicating whether this <see cref="JsonMemberMapping"/> is readable.
/// </summary>
/// <value><c>true</c> if readable; otherwise, <c>false</c>.</value>
public bool Readable
{
get { return _readable; }
}
/// <summary>
/// Gets a value indicating whether this <see cref="JsonMemberMapping"/> is writable.
/// </summary>
/// <value><c>true</c> if writable; otherwise, <c>false</c>.</value>
public bool Writable
{
get { return _writable; }
}
/// <summary>
/// Gets the member converter.
/// </summary>
/// <value>The member converter.</value>
public JsonConverter MemberConverter
{
get { return _memberConverter; }
}
/// <summary>
/// Gets the default value.
/// </summary>
/// <value>The default value.</value>
public object DefaultValue
{
get { return _defaultValue; }
}
/// <summary>
/// Gets a value indicating whether this <see cref="JsonMemberMapping"/> is required.
/// </summary>
/// <value><c>true</c> if required; otherwise, <c>false</c>.</value>
public bool Required
{
get { return _required; }
}
/// <summary>
/// Gets a value indicating whether this mapping preserves object references.
/// </summary>
/// <value>
/// <c>true</c> if this instance is reference; otherwise, <c>false</c>.
/// </value>
public bool? IsReference
{
get { return _isReference; }
}
/// <summary>
/// Gets the mapping null value handling.
/// </summary>
/// <value>The null value handling.</value>
public NullValueHandling? NullValueHandling
{
get { return _nullValueHandling; }
}
/// <summary>
/// Gets the mapping default value handling.
/// </summary>
/// <value>The default value handling.</value>
public DefaultValueHandling? DefaultValueHandling
{
get { return _defaultValueHandling; }
}
/// <summary>
/// Gets the mapping reference loop handling.
/// </summary>
/// <value>The reference loop handling.</value>
public ReferenceLoopHandling? ReferenceLoopHandling
{
get { return _referenceLoopHandling; }
}
}
}
@@ -1,119 +0,0 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.ObjectModel;
using Newtonsoft.Json.Utilities;
using System.Globalization;
namespace Newtonsoft.Json.Serialization
{
/// <summary>
/// A collection of <see cref="JsonMemberMapping"/> objects.
/// </summary>
public class JsonMemberMappingCollection : KeyedCollection<string, JsonMemberMapping>
{
/// <summary>
/// When implemented in a derived class, extracts the key from the specified element.
/// </summary>
/// <param name="item">The element from which to extract the key.</param>
/// <returns>The key for the specified element.</returns>
protected override string GetKeyForItem(JsonMemberMapping item)
{
return item.PropertyName;
}
/// <summary>
/// Adds a <see cref="JsonMemberMapping"/> object.
/// </summary>
/// <param name="memberMapping">The member mapping to add to the collection.</param>
public void AddMapping(JsonMemberMapping memberMapping)
{
if (Contains(memberMapping.PropertyName))
{
// don't overwrite existing mapping with ignored mapping
if (memberMapping.Ignored)
return;
JsonMemberMapping existingMemberMapping = this[memberMapping.PropertyName];
if (!existingMemberMapping.Ignored)
{
throw new JsonSerializationException(
"A member with the name '{0}' already exists on {1}. Use the JsonPropertyAttribute to specify another name.".FormatWith(CultureInfo.InvariantCulture, memberMapping.PropertyName, memberMapping.Member.DeclaringType));
}
else
{
// remove ignored mapping so it can be replaced in collection
Remove(existingMemberMapping);
}
}
Add(memberMapping);
}
/// <summary>
/// Tries to get the closest matching <see cref="JsonMemberMapping"/> object.
/// First attempts to get an exact case match of propertyName and then
/// a case insensitive match.
/// </summary>
/// <param name="propertyName">Name of the mapping.</param>
/// <param name="memberMapping">The member mapping.</param>
/// <returns></returns>
public bool TryGetClosestMatchMapping(string propertyName, out JsonMemberMapping memberMapping)
{
if (TryGetMapping(propertyName, StringComparison.Ordinal, out memberMapping))
return true;
if (TryGetMapping(propertyName, StringComparison.OrdinalIgnoreCase, out memberMapping))
return true;
return false;
}
/// <summary>
/// Tries to get a member mapping by property name.
/// </summary>
/// <param name="propertyName">The property name of the member mapping to get.</param>
/// <param name="comparisonType">Type property name compare string comparison.</param>
/// <param name="memberMapping">The member mapping.</param>
/// <returns></returns>
public bool TryGetMapping(string propertyName, StringComparison comparisonType, out JsonMemberMapping memberMapping)
{
foreach (JsonMemberMapping mapping in this)
{
if (string.Compare(propertyName, mapping.PropertyName, comparisonType) == 0)
{
memberMapping = mapping;
return true;
}
}
memberMapping = default(JsonMemberMapping);
return false;
}
}
}
@@ -0,0 +1,57 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
using System;
namespace Newtonsoft.Json.Serialization
{
/// <summary>
/// Contract details for a <see cref="Type"/> used by the <see cref="JsonSerializer"/>.
/// </summary>
public class JsonObjectContract : JsonContract
{
/// <summary>
/// Gets or sets the object member serialization.
/// </summary>
/// <value>The member object serialization.</value>
public MemberSerialization MemberSerialization { get; set; }
/// <summary>
/// Gets the object's properties.
/// </summary>
/// <value>The object's properties.</value>
public JsonPropertyCollection Properties { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="JsonObjectContract"/> class.
/// </summary>
/// <param name="underlyingType">The underlying type for the contract.</param>
public JsonObjectContract(Type underlyingType)
: base(underlyingType)
{
Properties = new JsonPropertyCollection();
}
}
}
@@ -0,0 +1,109 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
using System.Reflection;
namespace Newtonsoft.Json.Serialization
{
/// <summary>
/// Maps a JSON property to a .NET member.
/// </summary>
public class JsonProperty
{
/// <summary>
/// Gets the name of the property.
/// </summary>
/// <value>The name of the property.</value>
public string PropertyName { get; set; }
/// <summary>
/// Gets the member.
/// </summary>
/// <value>The member.</value>
public MemberInfo Member { get; set; }
/// <summary>
/// Gets a value indicating whether this <see cref="JsonProperty"/> is ignored.
/// </summary>
/// <value><c>true</c> if ignored; otherwise, <c>false</c>.</value>
public bool Ignored { get; set; }
/// <summary>
/// Gets a value indicating whether this <see cref="JsonProperty"/> is readable.
/// </summary>
/// <value><c>true</c> if readable; otherwise, <c>false</c>.</value>
public bool Readable { get; set; }
/// <summary>
/// Gets a value indicating whether this <see cref="JsonProperty"/> is writable.
/// </summary>
/// <value><c>true</c> if writable; otherwise, <c>false</c>.</value>
public bool Writable { get; set; }
/// <summary>
/// Gets the member converter.
/// </summary>
/// <value>The member converter.</value>
public JsonConverter MemberConverter { get; set; }
/// <summary>
/// Gets the default value.
/// </summary>
/// <value>The default value.</value>
public object DefaultValue { get; set; }
/// <summary>
/// Gets a value indicating whether this <see cref="JsonProperty"/> is required.
/// </summary>
/// <value><c>true</c> if required; otherwise, <c>false</c>.</value>
public bool Required { get; set; }
/// <summary>
/// Gets a value indicating whether this property preserves object references.
/// </summary>
/// <value>
/// <c>true</c> if this instance is reference; otherwise, <c>false</c>.
/// </value>
public bool? IsReference { get; set; }
/// <summary>
/// Gets the property null value handling.
/// </summary>
/// <value>The null value handling.</value>
public NullValueHandling? NullValueHandling { get; set; }
/// <summary>
/// Gets the property default value handling.
/// </summary>
/// <value>The default value handling.</value>
public DefaultValueHandling? DefaultValueHandling { get; set; }
/// <summary>
/// Gets the property reference loop handling.
/// </summary>
/// <value>The reference loop handling.</value>
public ReferenceLoopHandling? ReferenceLoopHandling { get; set; }
}
}
@@ -0,0 +1,115 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.ObjectModel;
using Newtonsoft.Json.Utilities;
using System.Globalization;
namespace Newtonsoft.Json.Serialization
{
/// <summary>
/// A collection of <see cref="JsonProperty"/> objects.
/// </summary>
public class JsonPropertyCollection : KeyedCollection<string, JsonProperty>
{
/// <summary>
/// When implemented in a derived class, extracts the key from the specified element.
/// </summary>
/// <param name="item">The element from which to extract the key.</param>
/// <returns>The key for the specified element.</returns>
protected override string GetKeyForItem(JsonProperty item)
{
return item.PropertyName;
}
/// <summary>
/// Adds a <see cref="JsonProperty"/> object.
/// </summary>
/// <param name="property">The property to add to the collection.</param>
public void AddProperty(JsonProperty property)
{
if (Contains(property.PropertyName))
{
// don't overwrite existing property with ignored property
if (property.Ignored)
return;
JsonProperty existingProperty = this[property.PropertyName];
if (!existingProperty.Ignored)
throw new JsonSerializationException(
"A member with the name '{0}' already exists on '{1}'. Use the JsonPropertyAttribute to specify another name.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName, property.Member.DeclaringType));
// remove ignored property so it can be replaced in collection
Remove(existingProperty);
}
Add(property);
}
/// <summary>
/// Tries to get the closest matching <see cref="JsonProperty"/> object.
/// First attempts to get an exact case match of propertyName and then
/// a case insensitive match.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
/// <param name="property">A matching property if found.</param>
/// <returns>A flag indicating whether a match was found.</returns>
public bool TryGetClosestMatchProperty(string propertyName, out JsonProperty property)
{
if (TryGetProperty(propertyName, StringComparison.Ordinal, out property))
return true;
if (TryGetProperty(propertyName, StringComparison.OrdinalIgnoreCase, out property))
return true;
return false;
}
/// <summary>
/// Tries to get a property by property name.
/// </summary>
/// <param name="propertyName">The name of the property to get.</param>
/// <param name="comparisonType">Type property name string comparison.</param>
/// <param name="matchingProperty">A matching property if found.</param>
/// <returns>A flag indicating whether a match was found.</returns>
public bool TryGetProperty(string propertyName, StringComparison comparisonType, out JsonProperty matchingProperty)
{
foreach (JsonProperty property in this)
{
if (string.Compare(propertyName, property.PropertyName, comparisonType) == 0)
{
matchingProperty = property;
return true;
}
}
matchingProperty = default(JsonProperty);
return false;
}
}
}
@@ -1,4 +1,4 @@
#region License
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
@@ -52,10 +52,10 @@ namespace Newtonsoft.Json.Serialization
set { _serializer.DefaultValueHandling = value; }
}
public override IMappingResolver MappingResolver
public override IContractResolver ContractResolver
{
get { return _serializer.MappingResolver; }
set { _serializer.MappingResolver = value; }
get { return _serializer.ContractResolver; }
set { _serializer.ContractResolver = value; }
}
public override MissingMemberHandling MissingMemberHandling
@@ -53,12 +53,14 @@ namespace Newtonsoft.Json.Serialization
Type objectType = target.GetType();
JsonContract contract = _serializer.ContractResolver.ResolveContract(objectType);
if (reader.TokenType == JsonToken.None)
reader.Read();
if (reader.TokenType == JsonToken.StartArray)
{
PopulateList(CollectionUtils.CreateCollectionWrapper(target), ReflectionUtils.GetCollectionItemType(objectType), reader, null);
PopulateList(CollectionUtils.CreateCollectionWrapper(target), reader, null, GetArrayContract(objectType));
}
else if (reader.TokenType == JsonToken.StartObject)
{
@@ -72,10 +74,12 @@ namespace Newtonsoft.Json.Serialization
CheckedRead(reader);
}
if (CollectionUtils.IsDictionaryType(objectType))
PopulateDictionary(CollectionUtils.CreateDictionaryWrapper(target), reader, id);
if (contract is JsonDictionaryContract)
PopulateDictionary(CollectionUtils.CreateDictionaryWrapper(target), reader, (JsonDictionaryContract) contract, id);
else if (contract is JsonObjectContract)
PopulateObject(target, reader, (JsonObjectContract) contract, id);
else
PopulateObject(target, reader, objectType, id);
throw new Exception("dfsdfsdf");
}
}
@@ -139,173 +143,184 @@ namespace Newtonsoft.Json.Serialization
JsonConverter converter;
if (memberConverter != null)
{
return memberConverter.ReadJson(reader, objectType, GetInternalSerializer());
}
else if (objectType != null && _serializer.HasClassConverter(objectType, out converter))
{
if (objectType != null && _serializer.HasClassConverter(objectType, out converter))
return converter.ReadJson(reader, objectType, GetInternalSerializer());
}
else if (objectType != null && _serializer.HasMatchingConverter(objectType, out converter))
{
if (objectType != null && _serializer.HasMatchingConverter(objectType, out converter))
return converter.ReadJson(reader, objectType, GetInternalSerializer());
}
else if (objectType == typeof(JsonRaw))
{
if (objectType == typeof (JsonRaw))
return JsonRaw.Create(reader);
do
{
switch (reader.TokenType)
{
// populate a typed object or generic dictionary/array
// depending upon whether an objectType was supplied
case JsonToken.StartObject:
return CreateObject(reader, objectType, existingValue);
case JsonToken.StartArray:
return CreateList(reader, objectType, existingValue, null);
case JsonToken.Integer:
case JsonToken.Float:
case JsonToken.String:
case JsonToken.Boolean:
case JsonToken.Date:
return EnsureType(reader.Value, objectType);
case JsonToken.StartConstructor:
case JsonToken.EndConstructor:
string constructorName = reader.Value.ToString();
return constructorName;
case JsonToken.Null:
case JsonToken.Undefined:
if (objectType == typeof (DBNull))
return DBNull.Value;
return null;
case JsonToken.Comment:
// ignore
break;
default:
throw new JsonSerializationException("Unexpected token while deserializing object: " + reader.TokenType);
}
} while (reader.Read());
throw new JsonSerializationException("Unexpected end when deserializing object.");
}
private object CreateObject(JsonReader reader, Type objectType, object existingValue)
{
CheckedRead(reader);
string id = null;
if (reader.TokenType == JsonToken.PropertyName)
{
bool specialProperty;
do
{
string propertyName = reader.Value.ToString();
if (string.Equals(propertyName, JsonTypeReflector.RefPropertyName, StringComparison.Ordinal))
{
CheckedRead(reader);
string reference = reader.Value.ToString();
CheckedRead(reader);
return _serializer.ReferenceResolver.ResolveReference(reference);
}
else if (string.Equals(propertyName, JsonTypeReflector.TypePropertyName, StringComparison.Ordinal))
{
CheckedRead(reader);
string qualifiedTypeName = reader.Value.ToString();
CheckedRead(reader);
if (_serializer.TypeNameHandling != TypeNameHandling.None)
{
int delimiterIndex = qualifiedTypeName.IndexOf(',');
string typeName;
string assemblyName;
if (delimiterIndex != -1)
{
typeName = qualifiedTypeName.Substring(0, delimiterIndex).Trim();
assemblyName = qualifiedTypeName.Substring(delimiterIndex + 1, qualifiedTypeName.Length - delimiterIndex - 1).Trim();
}
else
{
typeName = qualifiedTypeName;
assemblyName = null;
}
Type specifiedType;
try
{
specifiedType = _serializer.Binder.BindToType(assemblyName, typeName);
}
catch (Exception ex)
{
throw new JsonSerializationException("Error resolving type specified in JSON '{0}'.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName), ex);
}
if (specifiedType == null)
throw new JsonSerializationException("Type specified in JSON '{0}' was not resolved.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName));
if (objectType != null && !objectType.IsAssignableFrom(specifiedType))
throw new JsonSerializationException("Type specified in JSON '{0}' is not compatible with '{1}'.".FormatWith(CultureInfo.InvariantCulture, specifiedType.AssemblyQualifiedName, objectType.AssemblyQualifiedName));
objectType = specifiedType;
}
specialProperty = true;
}
else if (string.Equals(propertyName, JsonTypeReflector.IdPropertyName, StringComparison.Ordinal))
{
CheckedRead(reader);
id = reader.Value.ToString();
CheckedRead(reader);
specialProperty = true;
}
else if (string.Equals(propertyName, JsonTypeReflector.ArrayValuesPropertyName, StringComparison.Ordinal))
{
CheckedRead(reader);
object list = CreateList(reader, objectType, existingValue, id);
CheckedRead(reader);
return list;
}
else
{
specialProperty = false;
}
} while (specialProperty
&& reader.TokenType == JsonToken.PropertyName);
}
if (objectType == null)
return CreateJObject(reader);
JsonContract contract = _serializer.ContractResolver.ResolveContract(objectType);
if (contract == null)
throw new JsonSerializationException("Could not resolve type '{0}' to a JsonContract.".FormatWith(CultureInfo.InvariantCulture, objectType));
if (contract is JsonDictionaryContract)
{
if (existingValue == null)
return CreateAndPopulateDictionary(reader, (JsonDictionaryContract) contract, id);
return PopulateDictionary(CollectionUtils.CreateDictionaryWrapper(existingValue), reader, (JsonDictionaryContract) contract, id);
}
else if (contract is JsonObjectContract)
{
if (existingValue == null)
return CreateAndPopulateObject(reader, (JsonObjectContract) contract, id);
return PopulateObject(existingValue, reader, (JsonObjectContract) contract, id);
}
else
{
do
{
switch (reader.TokenType)
{
// populate a typed object or generic dictionary/array
// depending upon whether an objectType was supplied
case JsonToken.StartObject:
CheckedRead(reader);
string id = null;
if (reader.TokenType == JsonToken.PropertyName)
{
bool specialProperty;
do
{
string propertyName = reader.Value.ToString();
if (string.Equals(propertyName, JsonTypeReflector.RefPropertyName, StringComparison.Ordinal))
{
CheckedRead(reader);
string reference = reader.Value.ToString();
CheckedRead(reader);
return _serializer.ReferenceResolver.ResolveReference(reference);
}
else if (string.Equals(propertyName, JsonTypeReflector.TypePropertyName, StringComparison.Ordinal))
{
CheckedRead(reader);
string qualifiedTypeName = reader.Value.ToString();
CheckedRead(reader);
if (_serializer.TypeNameHandling != TypeNameHandling.None)
{
int delimiterIndex = qualifiedTypeName.IndexOf(',');
string typeName;
string assemblyName;
if (delimiterIndex != -1)
{
typeName = qualifiedTypeName.Substring(0, delimiterIndex).Trim();
assemblyName = qualifiedTypeName.Substring(delimiterIndex + 1, qualifiedTypeName.Length - delimiterIndex - 1).Trim();
}
else
{
typeName = qualifiedTypeName;
assemblyName = null;
}
Type specifiedType;
try
{
specifiedType = _serializer.Binder.BindToType(assemblyName, typeName);
}
catch (Exception ex)
{
throw new JsonSerializationException("Error resolving type specified in JSON '{0}'.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName), ex);
}
if (specifiedType == null)
throw new JsonSerializationException("Type specified in JSON '{0}' was not resolved.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName));
if (objectType != null && !objectType.IsAssignableFrom(specifiedType))
throw new JsonSerializationException("Type specified in JSON '{0}' is not compatible with '{1}'.".FormatWith(CultureInfo.InvariantCulture, specifiedType.AssemblyQualifiedName, objectType.AssemblyQualifiedName));
objectType = specifiedType;
}
specialProperty = true;
}
else if (string.Equals(propertyName, JsonTypeReflector.IdPropertyName, StringComparison.Ordinal))
{
CheckedRead(reader);
id = reader.Value.ToString();
CheckedRead(reader);
specialProperty = true;
}
else if (string.Equals(propertyName, JsonTypeReflector.ArrayValuesPropertyName, StringComparison.Ordinal))
{
CheckedRead(reader);
object list = CreateList(reader, objectType, existingValue, id);
CheckedRead(reader);
return list;
}
else
{
specialProperty = false;
}
} while (specialProperty
&& reader.TokenType == JsonToken.PropertyName);
}
if (objectType == null)
{
return CreateJObject(reader);
}
else
{
if (CollectionUtils.IsDictionaryType(objectType))
{
if (existingValue == null)
return CreateAndPopulateDictionary(reader, objectType, id);
else
return PopulateDictionary(CollectionUtils.CreateDictionaryWrapper(existingValue), reader, id);
}
else
{
if (existingValue == null)
return CreateAndPopulateObject(reader, objectType, id);
else
return PopulateObject(existingValue, reader, objectType, id);
}
}
break;
case JsonToken.StartArray:
return CreateList(reader, objectType, existingValue, null);
break;
case JsonToken.Integer:
case JsonToken.Float:
case JsonToken.String:
case JsonToken.Boolean:
case JsonToken.Date:
return EnsureType(reader.Value, objectType);
break;
case JsonToken.StartConstructor:
case JsonToken.EndConstructor:
string constructorName = reader.Value.ToString();
return constructorName;
break;
case JsonToken.Null:
case JsonToken.Undefined:
if (objectType == typeof(DBNull))
return DBNull.Value;
else
return null;
break;
case JsonToken.Comment:
// ignore
break;
default:
throw new JsonSerializationException("Unexpected token while deserializing object: " + reader.TokenType);
}
} while (reader.Read());
throw new JsonSerializationException("Unexpected end when deserializing object.");
throw new JsonSerializationException("Expected a JsonObjectContract or JsonDictionaryContract for type '{0}', got '{1}'.".FormatWith(CultureInfo.InvariantCulture, objectType, contract.GetType()));
}
}
private JsonArrayContract GetArrayContract(Type objectType)
{
JsonContract contract = _serializer.ContractResolver.ResolveContract(objectType);
if (contract == null)
throw new JsonSerializationException("Could not resolve type '{0}' to a JsonContract.".FormatWith(CultureInfo.InvariantCulture, objectType));
JsonArrayContract arrayContract = contract as JsonArrayContract;
if (arrayContract == null)
throw new JsonSerializationException("Expected a JsonObjectContract or JsonDictionaryContract for type '{0}', got '{1}'.".FormatWith(CultureInfo.InvariantCulture, objectType, contract.GetType()));
return arrayContract;
}
private void CheckedRead(JsonReader reader)
{
if (!reader.Read())
@@ -317,10 +332,12 @@ namespace Newtonsoft.Json.Serialization
object value;
if (objectType != null)
{
JsonArrayContract contract = GetArrayContract(objectType);
if (existingValue == null)
value = CreateAndPopulateList(reader, objectType, reference);
value = CreateAndPopulateList(reader, reference, contract);
else
value = PopulateList(CollectionUtils.CreateCollectionWrapper(existingValue), ReflectionUtils.GetCollectionItemType(objectType), reader, reference);
value = PopulateList(CollectionUtils.CreateCollectionWrapper(existingValue), reader, reference, contract);
}
else
{
@@ -343,45 +360,39 @@ namespace Newtonsoft.Json.Serialization
// type of value and type of target don't match
// attempt to convert value's type to target's type
if (valueType != targetType)
{
return ConvertUtils.ConvertOrCast(value, CultureInfo.InvariantCulture, targetType);
}
else
{
return value;
}
return value;
}
private void SetObjectMember(JsonReader reader, object target, Type targetType, string memberName)
private void SetObjectMember(JsonReader reader, object target, JsonObjectContract contract, string memberName)
{
JsonMemberMappingCollection memberMappings = _serializer.GetMemberMappings(targetType);
JsonMemberMapping memberMapping;
JsonProperty property;
// attempt exact case match first
// then try match ignoring case
if (memberMappings.TryGetClosestMatchMapping(memberName, out memberMapping))
if (contract.Properties.TryGetClosestMatchProperty(memberName, out property))
{
SetMappingValue(memberMapping, reader, target);
SetPropertyValue(property, reader, target);
}
else
{
if (_serializer.MissingMemberHandling == MissingMemberHandling.Error)
throw new JsonSerializationException("Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, targetType.Name));
throw new JsonSerializationException("Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType.Name));
reader.Skip();
}
}
private void SetMappingValue(JsonMemberMapping memberMapping, JsonReader reader, object target)
private void SetPropertyValue(JsonProperty property, JsonReader reader, object target)
{
if (memberMapping.Ignored)
if (property.Ignored)
{
reader.Skip();
return;
}
// get the member's underlying type
Type memberType = ReflectionUtils.GetMemberUnderlyingType(memberMapping.Member);
Type memberType = ReflectionUtils.GetMemberUnderlyingType(property.Member);
object currentValue = null;
bool useExistingValue = false;
@@ -389,74 +400,66 @@ namespace Newtonsoft.Json.Serialization
if ((_serializer.ObjectCreationHandling == ObjectCreationHandling.Auto || _serializer.ObjectCreationHandling == ObjectCreationHandling.Reuse)
&& (reader.TokenType == JsonToken.StartArray || reader.TokenType == JsonToken.StartObject))
{
currentValue = ReflectionUtils.GetMemberValue(memberMapping.Member, target);
currentValue = ReflectionUtils.GetMemberValue(property.Member, target);
useExistingValue = (currentValue != null && !memberType.IsArray && !ReflectionUtils.InheritsGenericDefinition(memberType, typeof(ReadOnlyCollection<>)));
}
if (!memberMapping.Writable && !useExistingValue)
if (!property.Writable && !useExistingValue)
{
reader.Skip();
return;
}
object value = CreateValue(reader, memberType, (useExistingValue) ? currentValue : null, JsonTypeReflector.GetConverter(memberMapping.Member, memberType));
object value = CreateValue(reader, memberType, (useExistingValue) ? currentValue : null, JsonTypeReflector.GetConverter(property.Member, memberType));
if (!useExistingValue && ShouldSetMappingValue(memberMapping, value))
ReflectionUtils.SetMemberValue(memberMapping.Member, target, value);
if (!useExistingValue && ShouldSetPropertyValue(property, value))
ReflectionUtils.SetMemberValue(property.Member, target, value);
}
private bool ShouldSetMappingValue(JsonMemberMapping memberMapping, object value)
private bool ShouldSetPropertyValue(JsonProperty property, object value)
{
if (memberMapping.NullValueHandling.GetValueOrDefault(_serializer.NullValueHandling) == NullValueHandling.Ignore && value == null)
if (property.NullValueHandling.GetValueOrDefault(_serializer.NullValueHandling) == NullValueHandling.Ignore && value == null)
return false;
if (memberMapping.DefaultValueHandling.GetValueOrDefault(_serializer.DefaultValueHandling) == DefaultValueHandling.Ignore && Equals(value, memberMapping.DefaultValue))
if (property.DefaultValueHandling.GetValueOrDefault(_serializer.DefaultValueHandling) == DefaultValueHandling.Ignore && Equals(value, property.DefaultValue))
return false;
if (!memberMapping.Writable)
if (!property.Writable)
return false;
return true;
}
private object CreateAndPopulateDictionary(JsonReader reader, Type objectType, string id)
private object CreateAndPopulateDictionary(JsonReader reader, JsonDictionaryContract contract, string id)
{
if (IsTypeGenericDictionaryInterface(objectType))
{
Type keyType;
Type valueType;
ReflectionUtils.GetDictionaryKeyValueTypes(objectType, out keyType, out valueType);
objectType = ReflectionUtils.MakeGenericType(typeof(Dictionary<,>), keyType, valueType);
}
IWrappedDictionary dictionary = CollectionUtils.CreateDictionaryWrapper(Activator.CreateInstance(contract.DictionaryTypeToCreate));
IWrappedDictionary dictionary = CollectionUtils.CreateDictionaryWrapper(Activator.CreateInstance(objectType));
PopulateDictionary(dictionary, reader, id);
PopulateDictionary(dictionary, reader, contract, id);
return dictionary.UnderlyingDictionary;
}
private IDictionary PopulateDictionary(IWrappedDictionary dictionary, JsonReader reader, string id)
private IDictionary PopulateDictionary(IWrappedDictionary dictionary, JsonReader reader, JsonDictionaryContract contract, string id)
{
Type dictionaryType = dictionary.UnderlyingDictionary.GetType();
Type dictionaryKeyType = ReflectionUtils.GetDictionaryKeyType(dictionaryType);
Type dictionaryValueType = ReflectionUtils.GetDictionaryValueType(dictionaryType);
if (id != null)
_serializer.ReferenceResolver.AddReference(id, dictionary.UnderlyingDictionary);
contract.InvokeOnDeserializing(dictionary.UnderlyingDictionary);
do
{
switch (reader.TokenType)
{
case JsonToken.PropertyName:
object keyValue = EnsureType(reader.Value, dictionaryKeyType);
object keyValue = EnsureType(reader.Value, contract.DictionaryKeyType);
CheckedRead(reader);
dictionary.Add(keyValue, CreateValue(reader, dictionaryValueType, null, null));
dictionary.Add(keyValue, CreateValue(reader, contract.DictionaryValueType, null, null));
break;
case JsonToken.EndObject:
contract.InvokeOnDeserialized(dictionary.UnderlyingDictionary);
return dictionary;
default:
throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
@@ -466,38 +469,41 @@ namespace Newtonsoft.Json.Serialization
throw new JsonSerializationException("Unexpected end when deserializing object.");
}
private object CreateAndPopulateList(JsonReader reader, Type objectType, string reference)
private object CreateAndPopulateList(JsonReader reader, string reference, JsonArrayContract contract)
{
if (IsTypeGenericCollectionInterface(objectType))
{
Type itemType = ReflectionUtils.GetCollectionItemType(objectType);
objectType = ReflectionUtils.MakeGenericType(typeof(List<>), itemType);
}
return CollectionUtils.CreateAndPopulateList(objectType, (l, isTemporaryListReference) =>
return CollectionUtils.CreateAndPopulateList(contract.CollectionTypeToCreate, (l, isTemporaryListReference) =>
{
if (reference != null && isTemporaryListReference)
throw new JsonSerializationException("Cannot preserve reference to array or readonly list: {0}".FormatWith(CultureInfo.InvariantCulture, objectType));
throw new JsonSerializationException("Cannot preserve reference to array or readonly list: {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
PopulateList(l, ReflectionUtils.GetCollectionItemType(objectType), reader, reference);
#if !PocketPC && !SILVERLIGHT
if (contract.OnSerializing != null && isTemporaryListReference)
throw new JsonSerializationException("Cannot call OnSerializing on an array or readonly list: {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
#endif
PopulateList(l, reader, reference, contract);
});
}
private IList PopulateList(IList list, Type listItemType, JsonReader reader, string reference)
private IList PopulateList(IList list, JsonReader reader, string reference, JsonArrayContract contract)
{
if (reference != null)
_serializer.ReferenceResolver.AddReference(reference, list);
contract.InvokeOnDeserializing(list);
while (reader.Read())
{
switch (reader.TokenType)
{
case JsonToken.EndArray:
contract.InvokeOnDeserialized(list);
return list;
case JsonToken.Comment:
break;
default:
object value = CreateValue(reader, listItemType, null, null);
object value = CreateValue(reader, contract.CollectionItemType, null, null);
list.Add(value);
break;
@@ -507,48 +513,28 @@ namespace Newtonsoft.Json.Serialization
throw new JsonSerializationException("Unexpected end when deserializing array.");
}
private bool IsTypeGenericDictionaryInterface(Type type)
{
if (!type.IsGenericType)
return false;
Type genericDefinition = type.GetGenericTypeDefinition();
return (genericDefinition == typeof(IDictionary<,>));
}
private bool IsTypeGenericCollectionInterface(Type type)
{
if (!type.IsGenericType)
return false;
Type genericDefinition = type.GetGenericTypeDefinition();
return (genericDefinition == typeof(IList<>)
|| genericDefinition == typeof(ICollection<>)
|| genericDefinition == typeof(IEnumerable<>));
}
private object CreateAndPopulateObject(JsonReader reader, Type objectType, string id)
private object CreateAndPopulateObject(JsonReader reader, JsonObjectContract contract, string id)
{
object newObject;
if (objectType.IsInterface || objectType.IsAbstract)
throw new JsonSerializationException("Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantated.".FormatWith(CultureInfo.InvariantCulture, objectType));
if (contract.UnderlyingType.IsInterface || contract.UnderlyingType.IsAbstract)
throw new JsonSerializationException("Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantated.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
if (ReflectionUtils.HasDefaultConstructor(objectType))
if (ReflectionUtils.HasDefaultConstructor(contract.UnderlyingType))
{
newObject = Activator.CreateInstance(objectType);
newObject = Activator.CreateInstance(contract.UnderlyingType);
PopulateObject(newObject, reader, objectType, id);
PopulateObject(newObject, reader, contract, id);
return newObject;
}
return CreateObjectFromNonDefaultConstructor(objectType, reader);
return CreateObjectFromNonDefaultConstructor(contract, reader);
}
private object CreateObjectFromNonDefaultConstructor(Type objectType, JsonReader reader)
private object CreateObjectFromNonDefaultConstructor(JsonObjectContract contract, JsonReader reader)
{
Type objectType = contract.UnderlyingType;
// object should have a single constructor
ConstructorInfo c = objectType.GetConstructors(BindingFlags.Public | BindingFlags.Instance).SingleOrDefault();
@@ -556,8 +542,7 @@ namespace Newtonsoft.Json.Serialization
throw new JsonSerializationException("Could not find a public constructor for type {0}.".FormatWith(CultureInfo.InvariantCulture, objectType));
// create a dictionary to put retrieved values into
JsonMemberMappingCollection memberMappings = _serializer.GetMemberMappings(objectType);
IDictionary<JsonMemberMapping, object> mappingValues = memberMappings.ToDictionary(kv => kv, kv => (object)null);
IDictionary<JsonProperty, object> propertyValues = contract.Properties.Where(p => !p.Ignored).ToDictionary(kv => kv, kv => (object)null);
bool exit = false;
do
@@ -569,15 +554,15 @@ namespace Newtonsoft.Json.Serialization
if (!reader.Read())
throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
JsonMemberMapping memberMapping;
JsonProperty property;
// attempt exact case match first
// then try match ignoring case
if (memberMappings.TryGetClosestMatchMapping(memberName, out memberMapping))
if (contract.Properties.TryGetClosestMatchProperty(memberName, out property))
{
if (!memberMapping.Ignored)
if (!property.Ignored)
{
Type memberType = ReflectionUtils.GetMemberUnderlyingType(memberMapping.Member);
mappingValues[memberMapping] = CreateValue(reader, memberType, null, memberMapping.MemberConverter);
Type memberType = ReflectionUtils.GetMemberUnderlyingType(property.Member);
propertyValues[property] = CreateValue(reader, memberType, null, property.MemberConverter);
}
}
else
@@ -597,34 +582,37 @@ namespace Newtonsoft.Json.Serialization
} while (!exit && reader.Read());
IDictionary<ParameterInfo, object> constructorParameters = c.GetParameters().ToDictionary(p => p, p => (object)null);
IDictionary<JsonMemberMapping, object> remainingMappingValues = new Dictionary<JsonMemberMapping, object>();
IDictionary<JsonProperty, object> remainingPropertyValues = new Dictionary<JsonProperty, object>();
foreach (KeyValuePair<JsonMemberMapping, object> mappingValue in mappingValues)
foreach (KeyValuePair<JsonProperty, object> propertyValue in propertyValues)
{
ParameterInfo matchingConstructorParameter = constructorParameters.ForgivingCaseSensitiveFind(kv => kv.Key.Name, mappingValue.Key.PropertyName).Key;
ParameterInfo matchingConstructorParameter = constructorParameters.ForgivingCaseSensitiveFind(kv => kv.Key.Name, propertyValue.Key.PropertyName).Key;
if (matchingConstructorParameter != null)
constructorParameters[matchingConstructorParameter] = mappingValue.Value;
constructorParameters[matchingConstructorParameter] = propertyValue.Value;
else
remainingMappingValues.Add(mappingValue);
remainingPropertyValues.Add(propertyValue);
}
object createdObject = ReflectionUtils.CreateInstance(objectType, constructorParameters.Values.ToArray());
contract.InvokeOnDeserializing(createdObject);
// go through unused values and set the newly created object's properties
foreach (KeyValuePair<JsonMemberMapping, object> remainingMappingValue in remainingMappingValues)
foreach (KeyValuePair<JsonProperty, object> remainingPropertyValue in remainingPropertyValues)
{
if (ShouldSetMappingValue(remainingMappingValue.Key, remainingMappingValue.Value))
ReflectionUtils.SetMemberValue(remainingMappingValue.Key.Member, createdObject, remainingMappingValue.Value);
if (ShouldSetPropertyValue(remainingPropertyValue.Key, remainingPropertyValue.Value))
ReflectionUtils.SetMemberValue(remainingPropertyValue.Key.Member, createdObject, remainingPropertyValue.Value);
}
contract.InvokeOnDeserialized(createdObject);
return createdObject;
}
private object PopulateObject(object newObject, JsonReader reader, Type objectType, string id)
private object PopulateObject(object newObject, JsonReader reader, JsonObjectContract contract, string id)
{
JsonMemberMappingCollection memberMappings = _serializer.GetMemberMappings(objectType);
Dictionary<string, bool> requiredMappings =
memberMappings.Where(m => m.Required).ToDictionary(m => m.PropertyName, m => false);
contract.InvokeOnDeserializing(newObject);
Dictionary<string, bool> requiredProperties =
contract.Properties.Where(m => m.Required).ToDictionary(m => m.PropertyName, m => false);
if (id != null)
_serializer.ReferenceResolver.AddReference(id, newObject);
@@ -640,16 +628,18 @@ namespace Newtonsoft.Json.Serialization
throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
if (reader.TokenType != JsonToken.Null)
SetRequiredMapping(memberName, requiredMappings);
SetRequiredProperty(memberName, requiredProperties);
SetObjectMember(reader, newObject, objectType, memberName);
SetObjectMember(reader, newObject, contract, memberName);
break;
case JsonToken.EndObject:
foreach (KeyValuePair<string, bool> requiredMapping in requiredMappings)
foreach (KeyValuePair<string, bool> requiredProperty in requiredProperties)
{
if (!requiredMapping.Value)
throw new JsonSerializationException("Required property '{0}' not found in JSON.".FormatWith(CultureInfo.InvariantCulture, requiredMapping.Key));
if (!requiredProperty.Value)
throw new JsonSerializationException("Required property '{0}' not found in JSON.".FormatWith(CultureInfo.InvariantCulture, requiredProperty.Key));
}
contract.InvokeOnDeserialized(newObject);
return newObject;
case JsonToken.Comment:
// ignore
@@ -662,21 +652,21 @@ namespace Newtonsoft.Json.Serialization
throw new JsonSerializationException("Unexpected end when deserializing object.");
}
private void SetRequiredMapping(string memberName, Dictionary<string, bool> requiredMappings)
private void SetRequiredProperty(string memberName, Dictionary<string, bool> requiredProperties)
{
// first attempt to find exact case match
// then attempt case insensitive match
if (requiredMappings.ContainsKey(memberName))
if (requiredProperties.ContainsKey(memberName))
{
requiredMappings[memberName] = true;
requiredProperties[memberName] = true;
}
else
{
foreach (KeyValuePair<string, bool> requiredMapping in requiredMappings)
foreach (KeyValuePair<string, bool> requiredProperty in requiredProperties)
{
if (string.Compare(requiredMapping.Key, requiredMapping.Key, StringComparison.OrdinalIgnoreCase) == 0)
if (string.Compare(requiredProperty.Key, requiredProperty.Key, StringComparison.OrdinalIgnoreCase) == 0)
{
requiredMappings[requiredMapping.Key] = true;
requiredProperties[requiredProperty.Key] = true;
break;
}
}
@@ -32,6 +32,7 @@ using System.Linq;
using System.Reflection;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Utilities;
using System.Runtime.Serialization;
namespace Newtonsoft.Json.Serialization
{
@@ -97,48 +98,61 @@ namespace Newtonsoft.Json.Serialization
{
((JToken)value).WriteTo(writer, (_serializer.Converters != null) ? _serializer.Converters.ToArray() : null);
}
else if (JsonTypeReflector.GetJsonObjectAttribute(value.GetType()) != null)
{
// for collection objects that have a JsonObject attribute
SerializeObject(writer, value);
}
else if (value is IList)
{
SerializeList(writer, (IList)value);
}
else if (value is IDictionary)
{
SerializeDictionary(writer, (IDictionary)value);
}
else if (value is IEnumerable)
{
SerializeEnumerable(writer, (IEnumerable)value);
}
else if (value is JsonRaw)
{
writer.WriteRawValue(((JsonRaw)value).Content);
}
else
{
SerializeObject(writer, value);
JsonContract contract = _serializer.ContractResolver.ResolveContract(value.GetType());
if (contract is JsonObjectContract)
{
SerializeObject(writer, value, (JsonObjectContract)contract);
}
else if (contract is JsonDictionaryContract)
{
SerializeDictionary(writer, (IDictionary)value, (JsonDictionaryContract)contract);
}
else if (contract is JsonArrayContract)
{
if (value is IList)
{
SerializeList(writer, (IList)value, (JsonArrayContract)contract);
}
else if (value is IEnumerable)
{
SerializeEnumerable(writer, (IEnumerable)value, (JsonArrayContract)contract);
}
else
{
throw new Exception("Cannot serialize '{0}' into a JSON array. Type does not implement IEnumerable.".FormatWith(CultureInfo.InvariantCulture, value.GetType()));
}
}
}
}
private bool ShouldWriteReference(object value, JsonMemberMapping mapping)
private bool ShouldWriteReference(object value, JsonProperty property)
{
if (value == null)
return false;
if (JsonConvert.IsJsonPrimitive(value))
return false;
Type t = value.GetType();
// value could be coming from a dictionary or array and not have a mapping
// value could be coming from a dictionary or array and not have a property
bool? isReference;
if (mapping != null)
isReference = mapping.IsReference;
if (property != null)
{
isReference = property.IsReference;
}
else
isReference = IsReference(t);
{
JsonContract memberTypeContract = _serializer.ContractResolver.ResolveContract(value.GetType());
if (memberTypeContract != null)
isReference = memberTypeContract.IsReference;
else
isReference = null;
}
if (isReference == null)
{
@@ -158,31 +172,31 @@ namespace Newtonsoft.Json.Serialization
return _serializer.ReferenceResolver.IsReferenced(value);
}
private void WriteMemberInfoProperty(JsonWriter writer, object value, JsonMemberMapping memberMapping)
private void WriteMemberInfoProperty(JsonWriter writer, object value, JsonProperty property)
{
MemberInfo member = memberMapping.Member;
string propertyName = memberMapping.PropertyName;
JsonConverter memberConverter = memberMapping.MemberConverter;
object defaultValue = memberMapping.DefaultValue;
MemberInfo member = property.Member;
string propertyName = property.PropertyName;
JsonConverter memberConverter = property.MemberConverter;
object defaultValue = property.DefaultValue;
if (!ReflectionUtils.IsIndexedProperty(member))
{
object memberValue = ReflectionUtils.GetMemberValue(member, value);
if (memberMapping.NullValueHandling.GetValueOrDefault(_serializer.NullValueHandling) == NullValueHandling.Ignore && memberValue == null)
if (property.NullValueHandling.GetValueOrDefault(_serializer.NullValueHandling) == NullValueHandling.Ignore && memberValue == null)
return;
if (memberMapping.DefaultValueHandling.GetValueOrDefault(_serializer.DefaultValueHandling) == DefaultValueHandling.Ignore && Equals(memberValue, defaultValue))
if (property.DefaultValueHandling.GetValueOrDefault(_serializer.DefaultValueHandling) == DefaultValueHandling.Ignore && Equals(memberValue, defaultValue))
return;
if (ShouldWriteReference(memberValue, memberMapping))
if (ShouldWriteReference(memberValue, property))
{
writer.WritePropertyName(propertyName ?? member.Name);
WriteReference(writer, memberValue);
return;
}
if (!CheckForCircularReference(memberValue, memberMapping.ReferenceLoopHandling))
if (!CheckForCircularReference(memberValue, property.ReferenceLoopHandling))
return;
writer.WritePropertyName(propertyName ?? member.Name);
@@ -218,12 +232,12 @@ namespace Newtonsoft.Json.Serialization
writer.WriteEndObject();
}
private void SerializeObject(JsonWriter writer, object value)
private void SerializeObject(JsonWriter writer, object value, JsonObjectContract contract)
{
Type objectType = value.GetType();
contract.InvokeOnSerializing(value);
#if !SILVERLIGHT && !PocketPC
TypeConverter converter = TypeDescriptor.GetConverter(objectType);
TypeConverter converter = TypeDescriptor.GetConverter(contract.UnderlyingType);
// use the objectType's TypeConverter if it has one and can convert to a string
if (converter != null && !(converter is ComponentConverter) && (converter.GetType() != typeof (TypeConverter) || value is Type))
@@ -231,6 +245,8 @@ namespace Newtonsoft.Json.Serialization
if (converter.CanConvertTo(typeof (string)))
{
writer.WriteValue(converter.ConvertToInvariantString(value));
contract.InvokeOnSerialized(value);
return;
}
}
@@ -242,12 +258,10 @@ namespace Newtonsoft.Json.Serialization
}
#endif
SerializeStack.Add(value);
writer.WriteStartObject();
bool isReference = IsReference(objectType) ?? HasFlag(_serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects);
bool isReference = contract.IsReference ?? HasFlag(_serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects);
if (isReference)
{
writer.WritePropertyName(JsonTypeReflector.IdPropertyName);
@@ -255,19 +269,19 @@ namespace Newtonsoft.Json.Serialization
}
if (HasFlag(_serializer.TypeNameHandling, TypeNameHandling.Objects))
{
WriteTypeProperty(writer, objectType);
WriteTypeProperty(writer, contract.UnderlyingType);
}
JsonMemberMappingCollection memberMappings = _serializer.GetMemberMappings(objectType);
foreach (JsonMemberMapping memberMapping in memberMappings)
foreach (JsonProperty property in contract.Properties)
{
if (!memberMapping.Ignored && memberMapping.Readable)
WriteMemberInfoProperty(writer, value, memberMapping);
if (!property.Ignored && property.Readable)
WriteMemberInfoProperty(writer, value, property);
}
writer.WriteEndObject();
SerializeStack.RemoveAt(SerializeStack.Count - 1);
contract.InvokeOnSerialized(value);
}
private void WriteTypeProperty(JsonWriter writer, Type type)
@@ -286,15 +300,6 @@ namespace Newtonsoft.Json.Serialization
return ((value & flag) == flag);
}
private bool? IsReference(Type t)
{
JsonContainerAttribute containerAttribute = JsonTypeReflector.GetJsonContainerAttribute(t);
if (containerAttribute == null)
return null;
return containerAttribute._isReference;
}
private void SerializeConvertable(JsonWriter writer, JsonConverter converter, object value)
{
if (ShouldWriteReference(value, null))
@@ -314,16 +319,18 @@ namespace Newtonsoft.Json.Serialization
}
}
private void SerializeEnumerable(JsonWriter writer, IEnumerable values)
private void SerializeEnumerable(JsonWriter writer, IEnumerable values, JsonArrayContract contract)
{
SerializeList(writer, values.Cast<object>().ToList());
SerializeList(writer, values.Cast<object>().ToList(), contract);
}
private void SerializeList(JsonWriter writer, IList values)
private void SerializeList(JsonWriter writer, IList values, JsonArrayContract contract)
{
contract.InvokeOnSerializing(values);
SerializeStack.Add(values);
bool isReference = IsReference(values.GetType()) ?? HasFlag(_serializer.PreserveReferencesHandling, PreserveReferencesHandling.Arrays);
bool isReference = contract.IsReference ?? HasFlag(_serializer.PreserveReferencesHandling, PreserveReferencesHandling.Arrays);
bool includeTypeDetails = HasFlag(_serializer.TypeNameHandling, TypeNameHandling.Arrays);
if (isReference || includeTypeDetails)
@@ -369,14 +376,18 @@ namespace Newtonsoft.Json.Serialization
}
SerializeStack.RemoveAt(SerializeStack.Count - 1);
contract.InvokeOnSerialized(values);
}
private void SerializeDictionary(JsonWriter writer, IDictionary values)
private void SerializeDictionary(JsonWriter writer, IDictionary values, JsonDictionaryContract contract)
{
contract.InvokeOnSerializing(values);
SerializeStack.Add(values);
writer.WriteStartObject();
bool isReference = IsReference(values.GetType()) ?? HasFlag(_serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects);
bool isReference = contract.IsReference ?? HasFlag(_serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects);
if (isReference)
{
writer.WritePropertyName(JsonTypeReflector.IdPropertyName);
@@ -409,6 +420,8 @@ namespace Newtonsoft.Json.Serialization
writer.WriteEndObject();
SerializeStack.RemoveAt(SerializeStack.Count - 1);
contract.InvokeOnSerialized(values);
}
}
}
@@ -24,7 +24,6 @@
#endregion
using System;
using System.Collections.Generic;
#if !SILVERLIGHT && !PocketPC
using System.ComponentModel.DataAnnotations;
#endif
@@ -231,7 +231,7 @@ namespace Newtonsoft.Json.Utilities
return genericListType.GetGenericArguments()[0];
}
else if (typeof(ICollection).IsAssignableFrom(type))
else if (typeof(IEnumerable).IsAssignableFrom(type))
{
return null;
}
@@ -1,13 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json.Utilities;
namespace Newtonsoft.Json.Utilities
{
internal class ThreadSafeStore<TKey, TValue>
{
private readonly object _lock = new object();
private Dictionary<TKey, TValue> _store;
private readonly Func<TKey, TValue> _creator;
@@ -33,24 +31,23 @@ namespace Newtonsoft.Json.Utilities
private TValue AddValue(TKey key)
{
lock (this)
{
TValue value;
TValue value = _creator(key);
lock (_lock)
{
if (_store == null)
{
_store = new Dictionary<TKey, TValue>();
value = _creator(key);
_store[key] = value;
}
else
{
// double check locking
if (_store.TryGetValue(key, out value))
return value;
TValue checkValue;
if (_store.TryGetValue(key, out checkValue))
return checkValue;
Dictionary<TKey, TValue> newStore = new Dictionary<TKey, TValue>(_store);
value = _creator(key);
newStore[key] = value;
_store = newStore;