-Documentation
-Fixed JObject loading JSON with comments -Fixed error when using a Specified property with no setter -Fixed transient constructor error on Windows Phone 7 -Fixed deserializing null values into nullable generic dictionaries
This commit is contained in:
+35
-21
@@ -211,12 +211,12 @@
|
||||
<h4>
|
||||
<strong>Objects</strong></h4>
|
||||
<p>
|
||||
.NET types that don’t fall into any other category listed below (i.e. aren’t lists,
|
||||
.NET types that don't fall into any other category listed below (i.e. aren't lists,
|
||||
dictionaries, dynamic, implement ISerializable, etc) are serialized as JSON objects.</p>
|
||||
<p>
|
||||
By default types are serialized in opt-out mode. What that means is all public fields
|
||||
and properties with getters are automatically serialized to JSON and members that
|
||||
shouldn’t be serialized are opted-out using the JsonIgnoreAttribute. To serialize
|
||||
shouldn't be serialized are opted-out using the JsonIgnoreAttribute. To serialize
|
||||
private members the JsonPropertyAttribute can be placed on private fields and properties
|
||||
or the DefaultMembersSearchFlags can be changed on DefaultContractResolver to change
|
||||
how members are serialized on all types.</p>
|
||||
@@ -251,7 +251,7 @@
|
||||
<p>
|
||||
.NET dictionaries (types that inherit from IDictionary) are converted to JSON objects.
|
||||
Note that only the dictionary name/values will be written to the JSON object when
|
||||
serializing and properties on the JSON object will be added to the dictionary’s
|
||||
serializing and properties on the JSON object will be added to the dictionary's
|
||||
name/values when deserializing. Additional members on the .NET dictionary are ignored
|
||||
during serialization.</p>
|
||||
<p>
|
||||
@@ -263,40 +263,54 @@
|
||||
<h4>
|
||||
<strong>Untyped Objects</strong></h4>
|
||||
<p>
|
||||
.NET properties on a class that don’t specify a type (i.e. they are just object)
|
||||
.NET properties on a class that don't specify a type (i.e. they are just object)
|
||||
are serialized as usual. When untyped properties are deserialized the serializer
|
||||
has no way to know what type to create (unless type name handling is enabled and
|
||||
the JSON contains the type names).</p>
|
||||
<p>
|
||||
For these untyped properties the Json.NET serializer will read the JSON into LINQ
|
||||
to JSON objects and set them to the property.
|
||||
to JSON objects and set them to the property. JObject will be created for JSON objects,
|
||||
JArray will be created for JSON arrays and JValue for primitive JSON values.
|
||||
</p>
|
||||
<h4>
|
||||
<strong>Dynamic</strong></h4>
|
||||
<p>
|
||||
.NET dynamic objects (introduced in .NET 4) are serialized as JSON objects. A property
|
||||
is written for every member name returned by IDynamicMetaObjectProvider.GetDynamicMemberNames.</p>
|
||||
<p>
|
||||
When deserializing the serializer first attempts to set JSON property values on
|
||||
a normal .NET member with the matching name. If no .NET member is found with the
|
||||
property name then the serializer will call SetMember on the dynamic object.</p>
|
||||
<p>
|
||||
Because a dynamic property on a class doesn’t specify a type, Json.NET has no way
|
||||
to know what type to create for it when deserializing (unless type name handling
|
||||
is enabled and the JSON contains the type name). LINQ to JSON objects will be created
|
||||
for the JSON.
|
||||
There are two different usages of dynamic (introduced in .NET 4) in .NET. The first
|
||||
are .NET properties with a type of dynamic. Dynamic proeprties behave like properties
|
||||
declared as object, any value can be assigned to it, but the difference being that
|
||||
properties and methods can be called on a dynamic property without casting. In Json.NET
|
||||
dynamic properties are serialized and deserialized exactly the same as untyped objects:
|
||||
because dynamic isn't an actual type Json.NET falls back to deserializing the JSON
|
||||
as LINQ to JSON objects.
|
||||
</p>
|
||||
<p>
|
||||
The second usage of dynamic in .NET are classes that implement <a href="http://msdn.microsoft.com/en-us/library/system.dynamic.idynamicmetaobjectprovider.aspx"
|
||||
target="_blank">IDynamicMetaObjectProvider</a>. This interface lets the implementor
|
||||
create dynamic objects that intercept the property and method calls on an object
|
||||
and use them. <a href="http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject.aspx"
|
||||
target="_blank">ExpandoObject</a> is a good example of a dynamic object.
|
||||
</p>
|
||||
<p>
|
||||
Dynamic objects are serialized as JSON objects. A property is written for every
|
||||
member name returned by <a href="http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicmetaobject.getdynamicmembernames.aspx"
|
||||
target="_blank">DynamicMetaObject.GetDynamicMemberNames</a>.</p>
|
||||
<p>
|
||||
When deserializing dynamic objects the serializer first attempts to set JSON property
|
||||
values on a normal .NET member with the matching name. If no .NET member is found
|
||||
with the property name then the serializer will call SetMember on the dynamic object.
|
||||
Because there is no type information for dynamic members on a dynamic object the
|
||||
values assigned to them will be LINQ to JSON objects</p>
|
||||
<h4>
|
||||
<strong>ISerializable</strong></h4>
|
||||
<p>
|
||||
Types that implement ISerializable are serialized as JSON objects. When serializing
|
||||
only the values returned from ISerializable.GetObjectData are used; members on the
|
||||
type are ignored. When deserializing the constructor with a SerializationInfo and
|
||||
StreamingContext is called, passing the JSON object’s values.</p>
|
||||
StreamingContext is called, passing the JSON object's values.</p>
|
||||
<p>
|
||||
In situations where this behaviour is not wanted the JsonObjectAttribute can be
|
||||
placed on a .NET type that implements ISerializable to force it to be serialized
|
||||
as a normal JSON object.
|
||||
In situations where this behavior is not wanted the JsonObjectAttribute can be placed
|
||||
on a .NET type that implements ISerializable to force it to be serialized as a normal
|
||||
JSON object.
|
||||
</p>
|
||||
<h4>
|
||||
<strong>LINQ to JSON</strong></h4>
|
||||
@@ -313,7 +327,7 @@
|
||||
all other tests.</p>
|
||||
<p>
|
||||
JsonConverters can be defined and specified in a number of places: in an attribute
|
||||
on a member, in an attribute on a class and added to the JsonSerializer’s converters
|
||||
on a member, in an attribute on a class and added to the JsonSerializer's converters
|
||||
collection. The priority of which JsonConverter is used is the JsonConverter defined
|
||||
by attribute on a member then the JsonConverter defined by an attribute on a class
|
||||
and finally any converters passed to the JsonSerializer.</p>
|
||||
|
||||
@@ -178,7 +178,7 @@ DefaultValueHandling controls how Json.NET uses default values set using the .NE
|
||||
<td>
|
||||
<div class="summary">
|
||||
By default Json.NET will write a field/property value
|
||||
to JSON when serializing if the value is the same as the field/property’s
|
||||
to JSON when serializing if the value is the same as the field/property's
|
||||
default value. The Json.NET deserializer will continue setting a field/property
|
||||
if the JSON value is the same as the default value.
|
||||
</div>
|
||||
@@ -192,8 +192,8 @@ DefaultValueHandling controls how Json.NET uses default values set using the .NE
|
||||
<td>
|
||||
<div class="summary">
|
||||
Json.NET will skip writing a field/property value to
|
||||
JSON if the value is the same as the field/property’s default value. The
|
||||
Json.NET deserializer will skip setting a .NET object’s field/property if the
|
||||
JSON if the value is the same as the field/property's default value. The
|
||||
Json.NET deserializer will skip setting a .NET object's field/property if the
|
||||
JSON value is the same as the default value.
|
||||
</div>
|
||||
<br>
|
||||
@@ -315,7 +315,7 @@ DefaultValueHandling controls how Json.NET uses default values set using the .NE
|
||||
Json.NET will check whether an object/collection matches
|
||||
its declared property and writes the type name if they do not match, e.g. a
|
||||
property with a type of Mammal has a derived instance of Dog assigned. Auto will
|
||||
ensure that type information isn’t lost when serializing/deserializing
|
||||
ensure that type information isn't lost when serializing/deserializing
|
||||
automatically without having to write type names for every object.
|
||||
</div>
|
||||
<br>
|
||||
@@ -405,7 +405,7 @@ DefaultValueHandling controls how Json.NET uses default values set using the .NE
|
||||
<div class="summary">
|
||||
By default Json.NET will first look for a constructor
|
||||
marked with the JsonConstructorAttribute, then look for a public default
|
||||
constructor (a constructor that doesn’t take any arguments) and finally check if
|
||||
constructor (a constructor that doesn't take any arguments) and finally check if
|
||||
the class has a single public constructor with arguments. If the class has
|
||||
multiple public constructors with arguments an error will be thrown. This can be
|
||||
fixed by marking one of the constructors with the JsonConstructorAttribute.
|
||||
|
||||
@@ -1591,6 +1591,12 @@ Parameter name: arrayIndex")]
|
||||
Assert.AreEqual(false, prop4.ShouldSerializeValue(o));
|
||||
}
|
||||
#endif
|
||||
[Test]
|
||||
public void ParseEmptyObjectWithComment()
|
||||
{
|
||||
JObject o = JObject.Parse("{ /* A Comment */ }");
|
||||
Assert.AreEqual(0, o.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FromObjectTimeSpan()
|
||||
|
||||
@@ -41,5 +41,5 @@ using System.Runtime.InteropServices;
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("4.0.2.0")]
|
||||
#if !PocketPC
|
||||
[assembly: AssemblyFileVersion("4.0.2.14003")]
|
||||
[assembly: AssemblyFileVersion("4.0.2.14201")]
|
||||
#endif
|
||||
|
||||
@@ -3426,6 +3426,7 @@ keyword such as type of business.""
|
||||
public int Age { get; set; }
|
||||
public int Weight { get; set; }
|
||||
public int Height { get; set; }
|
||||
public int FavoriteNumber { get; set; }
|
||||
|
||||
// dummy. should never be used because it isn't of type bool
|
||||
[JsonIgnore]
|
||||
@@ -3444,6 +3445,14 @@ keyword such as type of business.""
|
||||
[JsonIgnore]
|
||||
[System.Xml.Serialization.XmlIgnoreAttribute]
|
||||
public bool HeightSpecified;
|
||||
|
||||
[JsonIgnore]
|
||||
|
||||
public bool FavoriteNumberSpecified
|
||||
{
|
||||
// get only example
|
||||
get { return FavoriteNumber != 0; }
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -3465,18 +3474,21 @@ keyword such as type of business.""
|
||||
Assert.IsFalse(deserialized.NameSpecified);
|
||||
Assert.IsFalse(deserialized.WeightSpecified);
|
||||
Assert.IsFalse(deserialized.HeightSpecified);
|
||||
Assert.IsFalse(deserialized.FavoriteNumberSpecified);
|
||||
Assert.AreEqual(27, deserialized.Age);
|
||||
|
||||
c.NameSpecified = true;
|
||||
c.WeightSpecified = true;
|
||||
c.HeightSpecified = true;
|
||||
c.FavoriteNumber = 23;
|
||||
json = JsonConvert.SerializeObject(c, Formatting.Indented);
|
||||
|
||||
Assert.AreEqual(@"{
|
||||
""Name"": ""James"",
|
||||
""Age"": 27,
|
||||
""Weight"": 0,
|
||||
""Height"": 0
|
||||
""Height"": 0,
|
||||
""FavoriteNumber"": 23
|
||||
}", json);
|
||||
|
||||
deserialized = JsonConvert.DeserializeObject<SpecifiedTestClass>(json);
|
||||
@@ -3484,7 +3496,9 @@ keyword such as type of business.""
|
||||
Assert.IsTrue(deserialized.NameSpecified);
|
||||
Assert.IsTrue(deserialized.WeightSpecified);
|
||||
Assert.IsTrue(deserialized.HeightSpecified);
|
||||
Assert.IsTrue(deserialized.FavoriteNumberSpecified);
|
||||
Assert.AreEqual(27, deserialized.Age);
|
||||
Assert.AreEqual(23, deserialized.FavoriteNumber);
|
||||
}
|
||||
|
||||
// [Test]
|
||||
@@ -4844,6 +4858,31 @@ keyword such as type of business.""
|
||||
Assert.AreEqual(c1.NullableTimeSpan, c2.NullableTimeSpan);
|
||||
Assert.AreEqual(c1.Uri, c2.Uri);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NullableValueGenericDictionary()
|
||||
{
|
||||
IDictionary<string, int?> v1 = new Dictionary<string, int?>
|
||||
{
|
||||
{ "First", 1 },
|
||||
{ "Second", null },
|
||||
{ "Third", 3 }
|
||||
};
|
||||
|
||||
string json = JsonConvert.SerializeObject(v1, Formatting.Indented);
|
||||
|
||||
Assert.AreEqual(@"{
|
||||
""First"": 1,
|
||||
""Second"": null,
|
||||
""Third"": 3
|
||||
}", json);
|
||||
|
||||
IDictionary<string, int?> v2 = JsonConvert.DeserializeObject<IDictionary<string, int?>>(json);
|
||||
Assert.AreEqual(3, v2.Count);
|
||||
Assert.AreEqual(1, v2["First"]);
|
||||
Assert.AreEqual(null, v2["Second"]);
|
||||
Assert.AreEqual(3, v2["Third"]);
|
||||
}
|
||||
}
|
||||
|
||||
public class UriGuidTimeSpanTestClass
|
||||
|
||||
@@ -142,6 +142,15 @@ namespace Newtonsoft.Json.Linq
|
||||
return (t != null && ContentsEqual(t));
|
||||
}
|
||||
|
||||
internal override void InsertItem(int index, JToken item)
|
||||
{
|
||||
// don't add comments to JObject, no name to reference comment by
|
||||
if (item != null && item.Type == JTokenType.Comment)
|
||||
return;
|
||||
|
||||
base.InsertItem(index, item);
|
||||
}
|
||||
|
||||
internal override void ValidateToken(JToken o, JToken existing)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(o, "o");
|
||||
@@ -480,16 +489,6 @@ namespace Newtonsoft.Json.Linq
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
/// <returns>The number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>.</returns>
|
||||
public int Count
|
||||
{
|
||||
get { return ChildrenTokens.Count; }
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<string,JToken>>.IsReadOnly
|
||||
{
|
||||
get { return false; }
|
||||
|
||||
@@ -110,7 +110,7 @@ using System.Security;
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("4.0.2.0")]
|
||||
#if !PocketPC
|
||||
[assembly: AssemblyFileVersion("4.0.2.14003")]
|
||||
[assembly: AssemblyFileVersion("4.0.2.14201")]
|
||||
#endif
|
||||
|
||||
[assembly: CLSCompliant(true)]
|
||||
|
||||
@@ -78,7 +78,11 @@ namespace Newtonsoft.Json.Serialization
|
||||
/// </summary>
|
||||
public class DefaultContractResolver : IContractResolver
|
||||
{
|
||||
internal static readonly IContractResolver Instance = new DefaultContractResolver(true);
|
||||
private static readonly IContractResolver _instance = new DefaultContractResolver(true);
|
||||
internal static IContractResolver Instance
|
||||
{
|
||||
get { return _instance; }
|
||||
}
|
||||
private static readonly IList<JsonConverter> BuiltInConverters = new List<JsonConverter>
|
||||
{
|
||||
#if !PocketPC && !SILVERLIGHT && !NET20
|
||||
@@ -792,7 +796,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
property.Writable = ReflectionUtils.CanSetMemberValue(member, allowNonPublicAccess, hasExplicitAttribute);
|
||||
property.ShouldSerialize = CreateShouldSerializeTest(member);
|
||||
|
||||
SetIsSpecifiedActions(property, member);
|
||||
SetIsSpecifiedActions(property, member, allowNonPublicAccess);
|
||||
|
||||
return property;
|
||||
}
|
||||
@@ -898,7 +902,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
return o => (bool)shouldSerializeCall(o);
|
||||
}
|
||||
|
||||
private void SetIsSpecifiedActions(JsonProperty property, MemberInfo member)
|
||||
private void SetIsSpecifiedActions(JsonProperty property, MemberInfo member, bool allowNonPublicAccess)
|
||||
{
|
||||
MemberInfo specifiedMember = member.DeclaringType.GetProperty(member.Name + JsonTypeReflector.SpecifiedPostfix);
|
||||
if (specifiedMember == null)
|
||||
@@ -912,7 +916,9 @@ namespace Newtonsoft.Json.Serialization
|
||||
Func<object, object> specifiedPropertyGet = JsonTypeReflector.ReflectionDelegateFactory.CreateGet<object>(specifiedMember);
|
||||
|
||||
property.GetIsSpecified = o => (bool)specifiedPropertyGet(o);
|
||||
property.SetIsSpecified = JsonTypeReflector.ReflectionDelegateFactory.CreateSet<object>(specifiedMember);
|
||||
|
||||
if (ReflectionUtils.CanSetMemberValue(specifiedMember, allowNonPublicAccess, false))
|
||||
property.SetIsSpecified = JsonTypeReflector.ReflectionDelegateFactory.CreateSet<object>(specifiedMember);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -45,6 +45,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
internal Type DictionaryKeyType { get; private set; }
|
||||
internal Type DictionaryValueType { get; private set; }
|
||||
|
||||
private readonly bool _isDictionaryValueTypeNullableType;
|
||||
private readonly Type _genericCollectionDefinitionType;
|
||||
private Type _genericWrapperType;
|
||||
private MethodCall<object, object> _genericWrapperCreator;
|
||||
@@ -71,6 +72,9 @@ namespace Newtonsoft.Json.Serialization
|
||||
DictionaryKeyType = keyType;
|
||||
DictionaryValueType = valueType;
|
||||
|
||||
if (DictionaryValueType != null)
|
||||
_isDictionaryValueTypeNullableType = ReflectionUtils.IsNullableType(DictionaryValueType);
|
||||
|
||||
if (IsTypeGenericDictionaryInterface(UnderlyingType))
|
||||
{
|
||||
CreatedType = ReflectionUtils.MakeGenericType(typeof(Dictionary<,>), keyType, valueType);
|
||||
@@ -83,7 +87,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
internal IWrappedDictionary CreateWrapper(object dictionary)
|
||||
{
|
||||
if (dictionary is IDictionary)
|
||||
if (dictionary is IDictionary && (DictionaryValueType == null || !_isDictionaryValueTypeNullableType))
|
||||
return new DictionaryWrapper<object, object>((IDictionary)dictionary);
|
||||
|
||||
if (_genericWrapperType == null)
|
||||
|
||||
@@ -31,7 +31,12 @@ namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
internal class LateBoundReflectionDelegateFactory : ReflectionDelegateFactory
|
||||
{
|
||||
public static readonly LateBoundReflectionDelegateFactory Instance = new LateBoundReflectionDelegateFactory();
|
||||
private static readonly LateBoundReflectionDelegateFactory _instance = new LateBoundReflectionDelegateFactory();
|
||||
|
||||
internal static ReflectionDelegateFactory Instance
|
||||
{
|
||||
get { return _instance; }
|
||||
}
|
||||
|
||||
public override MethodCall<T, object> CreateMethodCall<T>(MethodBase method)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user