-Added support to deserializing to IEnumerable<T>, IList<T>, IDictionary<K, V>
-Added populating members when creating object from non default constructor -Added case best match when deserializing properties -Added ToString(Formatting, JsonConverters[]) overload to JToken -Added SerializeObject(object, Formatting, JsonConverter[]) overload to JsonConvert -Added IMappingResolver. Property added to JsonSerializer, JsonSerializerSettings, JsonSchemaGenerator -Added CamelCaseMappingResolver
This commit is contained in:
@@ -777,14 +777,28 @@ keyword such as type of business.""
|
||||
name.pNumbers.Add(p1);
|
||||
name.pNumbers.Add(p2);
|
||||
|
||||
string json = JsonConvert.SerializeObject(name);
|
||||
string json = JsonConvert.SerializeObject(name, Formatting.Indented);
|
||||
|
||||
Assert.AreEqual(@"{
|
||||
""personsName"": ""The Idiot in Next To Me"",
|
||||
""pNumbers"": [
|
||||
{
|
||||
""phoneNumber"": ""555-1212""
|
||||
},
|
||||
{
|
||||
""phoneNumber"": ""444-1212""
|
||||
}
|
||||
]
|
||||
}", json);
|
||||
|
||||
Name newName = JsonConvert.DeserializeObject<Name>(json);
|
||||
|
||||
Assert.AreEqual("The Idiot in Next To Me", newName.personsName);
|
||||
|
||||
// not passed in as part of the constructor, values not deserialized
|
||||
Assert.AreEqual(0, newName.pNumbers.Count);
|
||||
// not passed in as part of the constructor but assigned to pNumbers property
|
||||
Assert.AreEqual(2, newName.pNumbers.Count);
|
||||
Assert.AreEqual("555-1212", newName.pNumbers[0].phoneNumber);
|
||||
Assert.AreEqual("444-1212", newName.pNumbers[1].phoneNumber);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -1323,15 +1337,103 @@ keyword such as type of business.""
|
||||
Console.WriteLine(javascriptJson);
|
||||
}
|
||||
|
||||
public class SomeClass
|
||||
public void GenericListAndDictionaryInterfaceProperties()
|
||||
{
|
||||
public int? SomeProp { get; set; }
|
||||
GenericListAndDictionaryInterfaceProperties o = new GenericListAndDictionaryInterfaceProperties();
|
||||
o.IDictionaryProperty = new Dictionary<string, int>
|
||||
{
|
||||
{"one", 1},
|
||||
{"two", 2},
|
||||
{"three", 3}
|
||||
};
|
||||
o.IListProperty = new List<int>
|
||||
{
|
||||
1, 2, 3
|
||||
};
|
||||
o.IEnumerableProperty = new List<int>
|
||||
{
|
||||
4, 5, 6
|
||||
};
|
||||
|
||||
string json = JsonConvert.SerializeObject(o, Formatting.Indented);
|
||||
|
||||
Assert.AreEqual(@"{
|
||||
""IEnumerableProperty"": [
|
||||
4,
|
||||
5,
|
||||
6
|
||||
],
|
||||
""IListProperty"": [
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
""IDictionaryProperty"": {
|
||||
""one"": 1,
|
||||
""two"": 2,
|
||||
""three"": 3
|
||||
}
|
||||
}", json);
|
||||
|
||||
GenericListAndDictionaryInterfaceProperties deserializedObject = JsonConvert.DeserializeObject<GenericListAndDictionaryInterfaceProperties>(json);
|
||||
Assert.IsNotNull(deserializedObject);
|
||||
|
||||
CollectionAssert.AreEqual(o.IListProperty.ToArray(), deserializedObject.IListProperty.ToArray());
|
||||
CollectionAssert.AreEqual(o.IEnumerableProperty.ToArray(), deserializedObject.IEnumerableProperty.ToArray());
|
||||
CollectionAssert.AreEqual(o.IDictionaryProperty.ToArray(), deserializedObject.IDictionaryProperty.ToArray());
|
||||
}
|
||||
|
||||
public class PropertyCase
|
||||
{
|
||||
public string firstName { get; set; }
|
||||
public string FirstName { get; set; }
|
||||
public string LastName { get; set; }
|
||||
public string lastName { get; set; }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Main()
|
||||
public void DeserializeBestMatchPropertyCase()
|
||||
{
|
||||
var pokes = JsonConvert.DeserializeObject<SomeClass>(@"{""SomeProp"":1}");
|
||||
string json = @"{
|
||||
""firstName"": ""firstName"",
|
||||
""FirstName"": ""FirstName"",
|
||||
""LastName"": ""LastName"",
|
||||
""lastName"": ""lastName"",
|
||||
}";
|
||||
|
||||
PropertyCase o = JsonConvert.DeserializeObject<PropertyCase>(json);
|
||||
Assert.IsNotNull(o);
|
||||
|
||||
Assert.AreEqual("firstName", o.firstName);
|
||||
Assert.AreEqual("FirstName", o.FirstName);
|
||||
Assert.AreEqual("LastName", o.LastName);
|
||||
Assert.AreEqual("lastName", o.lastName);
|
||||
}
|
||||
|
||||
public class SuperKlass
|
||||
{
|
||||
public string SuperProp { get; set; }
|
||||
public SuperKlass() { SuperProp = "default superprop"; }
|
||||
}
|
||||
|
||||
public class SubKlass : SuperKlass
|
||||
{
|
||||
public string SubProp { get; set; }
|
||||
public SubKlass(string subprop) { SubProp = subprop; }
|
||||
}
|
||||
|
||||
public void DeserializePropertiesOnToNonDefaultConstructor()
|
||||
{
|
||||
SubKlass i = new SubKlass("my subprop");
|
||||
i.SuperProp = "overrided superprop";
|
||||
|
||||
string json = JsonConvert.SerializeObject(i);
|
||||
Assert.AreEqual(@"{""SubProp"":""my subprop"",""SuperProp"":""overrided superprop""}", json);
|
||||
|
||||
SubKlass ii = JsonConvert.DeserializeObject<SubKlass>(json);
|
||||
|
||||
string newJson = JsonConvert.SerializeObject(ii);
|
||||
Assert.AreEqual(@"{""SubProp"":""my subprop"",""SuperProp"":""overrided superprop""}", newJson);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -506,7 +506,7 @@ namespace Newtonsoft.Json.Tests.Linq
|
||||
new JValue(new DateTime(2009, 2, 15, 0, 0, 0, DateTimeKind.Utc))
|
||||
);
|
||||
|
||||
string json = a.ToString(new IsoDateTimeConverter());
|
||||
string json = a.ToString(Formatting.Indented, new IsoDateTimeConverter());
|
||||
|
||||
Assert.AreEqual(@"[
|
||||
""2009-02-15T00:00:00.0000000Z""
|
||||
@@ -517,6 +517,19 @@ namespace Newtonsoft.Json.Tests.Linq
|
||||
Assert.AreEqual(@"[""2009-02-15T00:00:00.0000000Z""]", json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ToStringWithNoIndenting()
|
||||
{
|
||||
JArray a =
|
||||
new JArray(
|
||||
new JValue(new DateTime(2009, 2, 15, 0, 0, 0, DateTimeKind.Utc))
|
||||
);
|
||||
|
||||
string json = a.ToString(Formatting.None, new IsoDateTimeConverter());
|
||||
|
||||
Assert.AreEqual(@"[""2009-02-15T00:00:00.0000000Z""]", json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddAfterSelf()
|
||||
{
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Serialization\CamelCaseMappingResolverTests.cs" />
|
||||
<Compile Include="JsonValidatingReaderTests.cs" />
|
||||
<Compile Include="Schema\ExtensionsTests.cs" />
|
||||
<Compile Include="Schema\JsonSchemaModelBuilderTests.cs" />
|
||||
@@ -75,6 +76,7 @@
|
||||
<Compile Include="TestObjects\DefaultValueAttributeTestClass.cs" />
|
||||
<Compile Include="TestObjects\DoubleClass.cs" />
|
||||
<Compile Include="TestObjects\GenericImpl.cs" />
|
||||
<Compile Include="TestObjects\GenericListAndDictionaryInterfaceProperties.cs" />
|
||||
<Compile Include="TestObjects\GetOnlyPropertyClass.cs" />
|
||||
<Compile Include="TestObjects\IncompatibleJsonAttributeClass.cs" />
|
||||
<Compile Include="TestObjects\Invoice.cs" />
|
||||
@@ -86,6 +88,7 @@
|
||||
<Compile Include="TestObjects\Name.cs" />
|
||||
<Compile Include="TestObjects\PersonRaw.cs" />
|
||||
<Compile Include="TestObjects\PhoneNumber.cs" />
|
||||
<Compile Include="TestObjects\PrivateMembersClass.cs" />
|
||||
<Compile Include="TestObjects\RequiredMembersClass.cs" />
|
||||
<Compile Include="TestObjects\SetOnlyPropertyClass.cs" />
|
||||
<Compile Include="TestObjects\Article.cs" />
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Serialization\CamelCaseMappingResolverTests.cs" />
|
||||
<Compile Include="JsonValidatingReaderTests.cs" />
|
||||
<Compile Include="Schema\ExtensionsTests.cs" />
|
||||
<Compile Include="Schema\JsonSchemaModelBuilderTests.cs" />
|
||||
@@ -80,6 +81,7 @@
|
||||
<Compile Include="TestObjects\DefaultValueAttributeTestClass.cs" />
|
||||
<Compile Include="TestObjects\DoubleClass.cs" />
|
||||
<Compile Include="TestObjects\GenericImpl.cs" />
|
||||
<Compile Include="TestObjects\GenericListAndDictionaryInterfaceProperties.cs" />
|
||||
<Compile Include="TestObjects\GetOnlyPropertyClass.cs" />
|
||||
<Compile Include="TestObjects\IncompatibleJsonAttributeClass.cs" />
|
||||
<Compile Include="TestObjects\Invoice.cs" />
|
||||
@@ -91,6 +93,7 @@
|
||||
<Compile Include="TestObjects\Name.cs" />
|
||||
<Compile Include="TestObjects\PersonRaw.cs" />
|
||||
<Compile Include="TestObjects\PhoneNumber.cs" />
|
||||
<Compile Include="TestObjects\PrivateMembersClass.cs" />
|
||||
<Compile Include="TestObjects\RequiredMembersClass.cs" />
|
||||
<Compile Include="TestObjects\SetOnlyPropertyClass.cs" />
|
||||
<Compile Include="TestObjects\Article.cs" />
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
<Compile Include="Schema\ExtensionsTests.cs" />
|
||||
<Compile Include="Schema\JsonSchemaModelBuilderTests.cs" />
|
||||
<Compile Include="Schema\JsonSchemaNodeTests.cs" />
|
||||
<Compile Include="Serialization\CamelCaseMappingResolverTests.cs" />
|
||||
<Compile Include="TestObjects\AbstractGenericBase.cs" />
|
||||
<Compile Include="TestObjects\ArgumentConverterPrecedenceClassConverter.cs" />
|
||||
<Compile Include="TestObjects\BadJsonPropertyClass.cs" />
|
||||
@@ -94,6 +95,7 @@
|
||||
<Compile Include="TestObjects\DefaultValueAttributeTestClass.cs" />
|
||||
<Compile Include="TestObjects\DoubleClass.cs" />
|
||||
<Compile Include="TestObjects\GenericImpl.cs" />
|
||||
<Compile Include="TestObjects\GenericListAndDictionaryInterfaceProperties.cs" />
|
||||
<Compile Include="TestObjects\GetOnlyPropertyClass.cs" />
|
||||
<Compile Include="TestObjects\IncompatibleJsonAttributeClass.cs" />
|
||||
<Compile Include="TestObjects\Invoice.cs" />
|
||||
@@ -105,6 +107,7 @@
|
||||
<Compile Include="TestObjects\Name.cs" />
|
||||
<Compile Include="TestObjects\PersonRaw.cs" />
|
||||
<Compile Include="TestObjects\PhoneNumber.cs" />
|
||||
<Compile Include="TestObjects\PrivateMembersClass.cs" />
|
||||
<Compile Include="TestObjects\RequiredMembersClass.cs" />
|
||||
<Compile Include="TestObjects\SetOnlyPropertyClass.cs" />
|
||||
<Compile Include="TestObjects\Article.cs" />
|
||||
|
||||
@@ -281,14 +281,27 @@ namespace Newtonsoft.Json.Tests.Schema
|
||||
Assert.AreEqual(JsonSchemaType.String, schema.Type);
|
||||
}
|
||||
|
||||
public class CustomDirectoryInfoSerializer : JsonSerializer
|
||||
//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
|
||||
{
|
||||
protected override Newtonsoft.Json.Serialization.JsonMemberMappingCollection GetMemberMappings(Type objectType)
|
||||
public override JsonMemberMappingCollection ResolveMappings(Type type)
|
||||
{
|
||||
JsonMemberMappingCollection mappings = base.GetMemberMappings(objectType);
|
||||
JsonMemberMappingCollection mappings = base.ResolveMappings(type);
|
||||
|
||||
JsonMemberMappingCollection c = new JsonMemberMappingCollection();
|
||||
CollectionUtils.AddRange(c, (IEnumerable) mappings.Where(m => m.MappingName != "Root"));
|
||||
CollectionUtils.AddRange(c, (IEnumerable)mappings.Where(m => m.MappingName != "Root"));
|
||||
|
||||
return c;
|
||||
}
|
||||
@@ -366,9 +379,10 @@ namespace Newtonsoft.Json.Tests.Schema
|
||||
DirectoryInfo temp = new DirectoryInfo(@"c:\temp");
|
||||
|
||||
JsonTokenWriter jsonWriter = new JsonTokenWriter();
|
||||
CustomDirectoryInfoSerializer customSerializer = new CustomDirectoryInfoSerializer();
|
||||
customSerializer.Converters.Add(new IsoDateTimeConverter());
|
||||
customSerializer.Serialize(jsonWriter, temp);
|
||||
JsonSerializer serializer = new JsonSerializer();
|
||||
serializer.Converters.Add(new IsoDateTimeConverter());
|
||||
serializer.MappingResolver = new CustomDirectoryInfoMapper();
|
||||
serializer.Serialize(jsonWriter, temp);
|
||||
|
||||
List<string> errors = new List<string>();
|
||||
jsonWriter.Token.Validate(schema, (sender, args) => errors.Add(args.Message));
|
||||
@@ -377,5 +391,76 @@ namespace Newtonsoft.Json.Tests.Schema
|
||||
Assert.AreEqual("Non-optional properties are missing from object: Root.", errors[0]);
|
||||
Assert.AreEqual("Non-optional properties are missing from object: Root.", errors[1]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateSchemaCamelCase()
|
||||
{
|
||||
JsonSchemaGenerator generator = new JsonSchemaGenerator();
|
||||
generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
|
||||
generator.MappingResolver = new CamelCaseMappingResolver();
|
||||
|
||||
JsonSchema schema = generator.Generate(typeof (DirectoryInfo), true);
|
||||
|
||||
string json = schema.ToString();
|
||||
|
||||
Assert.AreEqual(@"{
|
||||
""id"": ""System.IO.DirectoryInfo"",
|
||||
""type"": [
|
||||
""object"",
|
||||
""null""
|
||||
],
|
||||
""additionalProperties"": false,
|
||||
""properties"": {
|
||||
""name"": {
|
||||
""type"": [
|
||||
""string"",
|
||||
""null""
|
||||
]
|
||||
},
|
||||
""parent"": {
|
||||
""$ref"": ""System.IO.DirectoryInfo""
|
||||
},
|
||||
""exists"": {
|
||||
""type"": ""boolean""
|
||||
},
|
||||
""root"": {
|
||||
""$ref"": ""System.IO.DirectoryInfo""
|
||||
},
|
||||
""fullName"": {
|
||||
""type"": [
|
||||
""string"",
|
||||
""null""
|
||||
]
|
||||
},
|
||||
""extension"": {
|
||||
""type"": [
|
||||
""string"",
|
||||
""null""
|
||||
]
|
||||
},
|
||||
""creationTime"": {
|
||||
""type"": ""string""
|
||||
},
|
||||
""creationTimeUtc"": {
|
||||
""type"": ""string""
|
||||
},
|
||||
""lastAccessTime"": {
|
||||
""type"": ""string""
|
||||
},
|
||||
""lastAccessTimeUtc"": {
|
||||
""type"": ""string""
|
||||
},
|
||||
""lastWriteTime"": {
|
||||
""type"": ""string""
|
||||
},
|
||||
""lastWriteTimeUtc"": {
|
||||
""type"": ""string""
|
||||
},
|
||||
""attributes"": {
|
||||
""type"": ""integer""
|
||||
}
|
||||
}
|
||||
}", json);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
#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.Serialization;
|
||||
using NUnit.Framework;
|
||||
using Newtonsoft.Json.Tests.TestObjects;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json.Utilities;
|
||||
|
||||
namespace Newtonsoft.Json.Tests.Serialization
|
||||
{
|
||||
public class CamelCaseMappingResolverTests : TestFixtureBase
|
||||
{
|
||||
[Test]
|
||||
public void JsonConvertSerializerSettings()
|
||||
{
|
||||
Person person = new Person();
|
||||
person.BirthDate = new DateTime(2000, 11, 20, 23, 55, 44, DateTimeKind.Utc);
|
||||
person.LastModified = new DateTime(2000, 11, 20, 23, 55, 44, DateTimeKind.Utc);
|
||||
person.Name = "Name!";
|
||||
|
||||
string json = JsonConvert.SerializeObject(person, Formatting.Indented, new JsonSerializerSettings
|
||||
{
|
||||
MappingResolver = new CamelCaseMappingResolver()
|
||||
});
|
||||
|
||||
Assert.AreEqual(@"{
|
||||
""name"": ""Name!"",
|
||||
""birthDate"": ""\/Date(974764544000)\/"",
|
||||
""lastModified"": ""\/Date(974764544000)\/""
|
||||
}", json);
|
||||
|
||||
Person deserializedPerson = JsonConvert.DeserializeObject<Person>(json, new JsonSerializerSettings
|
||||
{
|
||||
MappingResolver = new CamelCaseMappingResolver()
|
||||
});
|
||||
|
||||
Assert.AreEqual(person.BirthDate, deserializedPerson.BirthDate);
|
||||
Assert.AreEqual(person.LastModified, deserializedPerson.LastModified);
|
||||
Assert.AreEqual(person.Name, deserializedPerson.Name);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void JsonTokenWriter()
|
||||
{
|
||||
JsonIgnoreAttributeOnClassTestClass ignoreAttributeOnClassTestClass = new JsonIgnoreAttributeOnClassTestClass();
|
||||
ignoreAttributeOnClassTestClass.Field = int.MinValue;
|
||||
|
||||
JsonSerializer serializer = new JsonSerializer();
|
||||
serializer.MappingResolver = new CamelCaseMappingResolver();
|
||||
|
||||
JsonTokenWriter writer = new JsonTokenWriter();
|
||||
|
||||
serializer.Serialize(writer, ignoreAttributeOnClassTestClass);
|
||||
|
||||
JObject o = (JObject) writer.Token;
|
||||
JProperty p = o.Property("theField");
|
||||
|
||||
Assert.IsNotNull(p);
|
||||
Assert.AreEqual(int.MinValue, (int)p.Value);
|
||||
|
||||
string json = o.ToString();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MemberSearchFlags()
|
||||
{
|
||||
PrivateMembersClass privateMembersClass = new PrivateMembersClass("PrivateString!", "InternalString!");
|
||||
|
||||
string json = JsonConvert.SerializeObject(privateMembersClass, Formatting.Indented, new JsonSerializerSettings
|
||||
{
|
||||
MappingResolver = new CamelCaseMappingResolver { MemberSearchFlags = BindingFlags.NonPublic | BindingFlags.Instance }
|
||||
});
|
||||
|
||||
Assert.AreEqual(@"{
|
||||
""_privateString"": ""PrivateString!"",
|
||||
""i"": 0,
|
||||
""_internalString"": ""InternalString!""
|
||||
}", json);
|
||||
|
||||
PrivateMembersClass deserializedPrivateMembersClass = JsonConvert.DeserializeObject<PrivateMembersClass>(@"{
|
||||
""_privateString"": ""Private!"",
|
||||
""i"": -2,
|
||||
""_internalString"": ""Internal!""
|
||||
}", new JsonSerializerSettings
|
||||
{
|
||||
MappingResolver = new CamelCaseMappingResolver { MemberSearchFlags = BindingFlags.NonPublic | BindingFlags.Instance }
|
||||
});
|
||||
|
||||
Assert.AreEqual("Private!", ReflectionUtils.GetMemberValue(typeof(PrivateMembersClass).GetField("_privateString", BindingFlags.Instance | BindingFlags.NonPublic), deserializedPrivateMembersClass));
|
||||
Assert.AreEqual("Internal!", ReflectionUtils.GetMemberValue(typeof(PrivateMembersClass).GetField("_internalString", BindingFlags.Instance | BindingFlags.NonPublic), deserializedPrivateMembersClass));
|
||||
Assert.AreEqual(-2, ReflectionUtils.GetMemberValue(typeof(PrivateMembersClass).GetField("i", BindingFlags.Instance | BindingFlags.NonPublic), deserializedPrivateMembersClass));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Newtonsoft.Json.Tests.TestObjects
|
||||
{
|
||||
public class GenericListAndDictionaryInterfaceProperties
|
||||
{
|
||||
public IEnumerable<int> IEnumerableProperty { get; set; }
|
||||
public IList<int> IListProperty { get; set; }
|
||||
public IDictionary<string, int> IDictionaryProperty { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Newtonsoft.Json.Tests.TestObjects
|
||||
{
|
||||
public class PrivateMembersClass
|
||||
{
|
||||
public PrivateMembersClass(string privateString, string internalString)
|
||||
{
|
||||
_privateString = privateString;
|
||||
_internalString = internalString;
|
||||
}
|
||||
|
||||
public PrivateMembersClass()
|
||||
{
|
||||
}
|
||||
|
||||
private string _privateString;
|
||||
private int i;
|
||||
internal string _internalString;
|
||||
}
|
||||
}
|
||||
@@ -467,12 +467,24 @@ namespace Newtonsoft.Json
|
||||
/// <param name="converters">A collection converters used while serializing.</param>
|
||||
/// <returns>A JSON string representation of the object.</returns>
|
||||
public static string SerializeObject(object value, params JsonConverter[] converters)
|
||||
{
|
||||
return SerializeObject(value, Formatting.None, converters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the specified object to a JSON string using a collection of <see cref="JsonConverter"/>.
|
||||
/// </summary>
|
||||
/// <param name="value">The object to serialize.</param>
|
||||
/// <param name="formatting">Indicates how the output is formatted.</param>
|
||||
/// <param name="converters">A collection converters used while serializing.</param>
|
||||
/// <returns>A JSON string representation of the object.</returns>
|
||||
public static string SerializeObject(object value, Formatting formatting, params JsonConverter[] converters)
|
||||
{
|
||||
JsonSerializerSettings settings = (converters != null && converters.Length > 0)
|
||||
? new JsonSerializerSettings { Converters = converters }
|
||||
: null;
|
||||
|
||||
return SerializeObject(value, Formatting.None, settings);
|
||||
return SerializeObject(value, formatting, settings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -53,6 +53,7 @@ namespace Newtonsoft.Json
|
||||
private DefaultValueHandling _defaultValueHandling;
|
||||
private int _level;
|
||||
private JsonConverterCollection _converters;
|
||||
private IMappingResolver _mappingResolver;
|
||||
|
||||
/// <summary>
|
||||
/// Get or set how reference loops (e.g. a class referencing itself) is handled.
|
||||
@@ -144,6 +145,12 @@ namespace Newtonsoft.Json
|
||||
return _converters;
|
||||
}
|
||||
}
|
||||
|
||||
public IMappingResolver MappingResolver
|
||||
{
|
||||
get { return _mappingResolver; }
|
||||
set { _mappingResolver = value; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
@@ -170,7 +177,7 @@ namespace Newtonsoft.Json
|
||||
|
||||
if (settings != null)
|
||||
{
|
||||
if (!CollectionUtils.IsNullOrEmpty<JsonConverter>(settings.Converters))
|
||||
if (!CollectionUtils.IsNullOrEmpty(settings.Converters))
|
||||
jsonSerializer.Converters.AddRange(settings.Converters);
|
||||
|
||||
jsonSerializer.ReferenceLoopHandling = settings.ReferenceLoopHandling;
|
||||
@@ -178,6 +185,7 @@ namespace Newtonsoft.Json
|
||||
jsonSerializer.ObjectCreationHandling = settings.ObjectCreationHandling;
|
||||
jsonSerializer.NullValueHandling = settings.NullValueHandling;
|
||||
jsonSerializer.DefaultValueHandling = settings.DefaultValueHandling;
|
||||
jsonSerializer.MappingResolver = settings.MappingResolver;
|
||||
}
|
||||
|
||||
return jsonSerializer;
|
||||
@@ -363,62 +371,26 @@ namespace Newtonsoft.Json
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual JsonMemberMappingCollection GetMemberMappings(Type objectType)
|
||||
private JsonMemberMappingCollection GetMemberMappings(Type objectType)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(objectType, "objectType");
|
||||
|
||||
return JsonTypeReflector.GetMemberMappings(objectType);
|
||||
if (_mappingResolver != null)
|
||||
return _mappingResolver.ResolveMappings(objectType);
|
||||
|
||||
return DefaultMappingResolver.Instance.ResolveMappings(objectType);
|
||||
}
|
||||
|
||||
private void SetObjectMember(JsonReader reader, object target, Type targetType, string memberName)
|
||||
{
|
||||
JsonMemberMappingCollection memberMappings = GetMemberMappings(targetType);
|
||||
Type memberType;
|
||||
object value;
|
||||
|
||||
// test if a member with memberName exists on the type
|
||||
// otherwise test if target is a dictionary and assign value with the key if it is
|
||||
if (memberMappings.Contains(memberName))
|
||||
JsonMemberMapping memberMapping;
|
||||
// attempt exact case match first
|
||||
// then try match ignoring case
|
||||
if (memberMappings.TryGetClosestMatchMapping(memberName, out memberMapping))
|
||||
{
|
||||
JsonMemberMapping memberMapping = memberMappings[memberName];
|
||||
|
||||
if (memberMapping.Ignored)
|
||||
{
|
||||
reader.Skip();
|
||||
return;
|
||||
}
|
||||
|
||||
// get the member's underlying type
|
||||
memberType = ReflectionUtils.GetMemberUnderlyingType(memberMapping.Member);
|
||||
|
||||
object currentValue = null;
|
||||
bool useExistingValue = false;
|
||||
|
||||
if ((_objectCreationHandling == ObjectCreationHandling.Auto || _objectCreationHandling == ObjectCreationHandling.Reuse)
|
||||
&& (reader.TokenType == JsonToken.StartArray || reader.TokenType == JsonToken.StartObject))
|
||||
{
|
||||
currentValue = ReflectionUtils.GetMemberValue(memberMapping.Member, target);
|
||||
|
||||
useExistingValue = (currentValue != null && !memberType.IsArray && !ReflectionUtils.InheritsGenericDefinition(memberType, typeof(ReadOnlyCollection<>)));
|
||||
}
|
||||
|
||||
|
||||
if (!memberMapping.Writable && !useExistingValue)
|
||||
{
|
||||
reader.Skip();
|
||||
return;
|
||||
}
|
||||
|
||||
value = CreateObject(reader, memberType, (useExistingValue) ? currentValue : null, JsonTypeReflector.GetConverter(memberMapping.Member, memberType));
|
||||
|
||||
if (_nullValueHandling == NullValueHandling.Ignore && value == null)
|
||||
return;
|
||||
|
||||
if (_defaultValueHandling == DefaultValueHandling.Ignore && object.Equals(value, memberMapping.DefaultValue))
|
||||
return;
|
||||
|
||||
if (!useExistingValue)
|
||||
ReflectionUtils.SetMemberValue(memberMapping.Member, target, value);
|
||||
SetMappingValue(memberMapping, reader, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -429,8 +401,64 @@ namespace Newtonsoft.Json
|
||||
}
|
||||
}
|
||||
|
||||
private void SetMappingValue(JsonMemberMapping memberMapping, JsonReader reader, object target)
|
||||
{
|
||||
if (memberMapping.Ignored)
|
||||
{
|
||||
reader.Skip();
|
||||
return;
|
||||
}
|
||||
|
||||
// get the member's underlying type
|
||||
Type memberType = ReflectionUtils.GetMemberUnderlyingType(memberMapping.Member);
|
||||
|
||||
object currentValue = null;
|
||||
bool useExistingValue = false;
|
||||
|
||||
if ((_objectCreationHandling == ObjectCreationHandling.Auto || _objectCreationHandling == ObjectCreationHandling.Reuse)
|
||||
&& (reader.TokenType == JsonToken.StartArray || reader.TokenType == JsonToken.StartObject))
|
||||
{
|
||||
currentValue = ReflectionUtils.GetMemberValue(memberMapping.Member, target);
|
||||
|
||||
useExistingValue = (currentValue != null && !memberType.IsArray && !ReflectionUtils.InheritsGenericDefinition(memberType, typeof(ReadOnlyCollection<>)));
|
||||
}
|
||||
|
||||
if (!memberMapping.Writable && !useExistingValue)
|
||||
{
|
||||
reader.Skip();
|
||||
return;
|
||||
}
|
||||
|
||||
object value = CreateObject(reader, memberType, (useExistingValue) ? currentValue : null, JsonTypeReflector.GetConverter(memberMapping.Member, memberType));
|
||||
|
||||
if (!useExistingValue && ShouldSetMappingValue(memberMapping, value))
|
||||
ReflectionUtils.SetMemberValue(memberMapping.Member, target, value);
|
||||
}
|
||||
|
||||
private bool ShouldSetMappingValue(JsonMemberMapping memberMapping, object value)
|
||||
{
|
||||
if (_nullValueHandling == NullValueHandling.Ignore && value == null)
|
||||
return false;
|
||||
|
||||
if (_defaultValueHandling == DefaultValueHandling.Ignore && Equals(value, memberMapping.DefaultValue))
|
||||
return false;
|
||||
|
||||
if (!memberMapping.Writable)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private object CreateAndPopulateDictionary(JsonReader reader, Type objectType)
|
||||
{
|
||||
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(objectType));
|
||||
PopulateDictionary(dictionary, reader);
|
||||
|
||||
@@ -465,6 +493,12 @@ namespace Newtonsoft.Json
|
||||
|
||||
private object CreateAndPopulateList(JsonReader reader, Type objectType)
|
||||
{
|
||||
if (IsTypeGenericCollectionInterface(objectType))
|
||||
{
|
||||
Type itemType = ReflectionUtils.GetCollectionItemType(objectType);
|
||||
objectType = ReflectionUtils.MakeGenericType(typeof(List<>), itemType);
|
||||
}
|
||||
|
||||
return CollectionUtils.CreateAndPopulateList(objectType, l => PopulateList(l, ReflectionUtils.GetCollectionItemType(objectType), reader));
|
||||
}
|
||||
|
||||
@@ -489,67 +523,117 @@ namespace Newtonsoft.Json
|
||||
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)
|
||||
{
|
||||
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));
|
||||
}
|
||||
else if (ReflectionUtils.HasDefaultConstructor(objectType))
|
||||
|
||||
if (ReflectionUtils.HasDefaultConstructor(objectType))
|
||||
{
|
||||
newObject = Activator.CreateInstance(objectType);
|
||||
|
||||
PopulateObject(newObject, reader, objectType);
|
||||
return newObject;
|
||||
}
|
||||
else
|
||||
|
||||
return CreateObjectFromNonDefaultConstructor(objectType, reader);
|
||||
}
|
||||
|
||||
private object CreateObjectFromNonDefaultConstructor(Type objectType, JsonReader reader)
|
||||
{
|
||||
// object should have a single constructor
|
||||
ConstructorInfo c = objectType.GetConstructors(BindingFlags.Public | BindingFlags.Instance).SingleOrDefault();
|
||||
|
||||
if (c == null)
|
||||
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 = GetMemberMappings(objectType);
|
||||
IDictionary<JsonMemberMapping, object> mappingValues = memberMappings.ToDictionary(kv => kv, kv => (object)null);
|
||||
|
||||
bool exit = false;
|
||||
while (!exit && reader.Read())
|
||||
{
|
||||
ConstructorInfo c = objectType.GetConstructors(BindingFlags.Public | BindingFlags.Instance).SingleOrDefault();
|
||||
|
||||
if (c == null)
|
||||
throw new JsonSerializationException("Could not find a public constructor for type {0}.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
||||
|
||||
// create a dictionary to put retrieved values into
|
||||
IDictionary<ParameterInfo, object> constructorParameters = c.GetParameters().ToDictionary(p => p, p => (object)null);
|
||||
JsonMemberMappingCollection mappings = GetMemberMappings(objectType);
|
||||
|
||||
bool exit = false;
|
||||
while (!exit && reader.Read())
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.PropertyName:
|
||||
string memberName = reader.Value.ToString();
|
||||
if (!reader.Read())
|
||||
throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
|
||||
case JsonToken.PropertyName:
|
||||
string memberName = reader.Value.ToString();
|
||||
if (!reader.Read())
|
||||
throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
|
||||
|
||||
ParameterInfo matchingConstructorParameter = constructorParameters.ForgivingCaseSensitiveFind(kv => kv.Key.Name, memberName).Key;
|
||||
JsonMemberMapping mapping;
|
||||
JsonMemberMapping memberMapping;
|
||||
// attempt exact case match first
|
||||
// then try match ignoring case
|
||||
if (memberMappings.TryGetClosestMatchMapping(memberName, out memberMapping))
|
||||
{
|
||||
if (!memberMapping.Ignored)
|
||||
{
|
||||
Type memberType = ReflectionUtils.GetMemberUnderlyingType(memberMapping.Member);
|
||||
mappingValues[memberMapping] = CreateObject(reader, memberType, null, memberMapping.MemberConverter);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_missingMemberHandling == MissingMemberHandling.Error)
|
||||
throw new JsonSerializationException("Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, objectType.Name));
|
||||
|
||||
if (matchingConstructorParameter != null && mappings.TryGetMapping(memberName, out mapping) && !mapping.Ignored)
|
||||
{
|
||||
constructorParameters[matchingConstructorParameter] = CreateObject(reader, matchingConstructorParameter.ParameterType, null, mapping.MemberConverter);
|
||||
}
|
||||
else
|
||||
{
|
||||
// skip token and all child tokens
|
||||
reader.Skip();
|
||||
}
|
||||
break;
|
||||
case JsonToken.EndObject:
|
||||
exit = true;
|
||||
break;
|
||||
default:
|
||||
throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
|
||||
}
|
||||
reader.Skip();
|
||||
}
|
||||
break;
|
||||
case JsonToken.EndObject:
|
||||
exit = true;
|
||||
break;
|
||||
default:
|
||||
throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
|
||||
}
|
||||
|
||||
newObject = ReflectionUtils.CreateInstance(objectType, constructorParameters.Values.ToArray());
|
||||
|
||||
return newObject;
|
||||
}
|
||||
|
||||
IDictionary<ParameterInfo, object> constructorParameters = c.GetParameters().ToDictionary(p => p, p => (object)null);
|
||||
IDictionary<JsonMemberMapping, object> remainingMappingValues = new Dictionary<JsonMemberMapping, object>();
|
||||
|
||||
foreach (KeyValuePair<JsonMemberMapping, object> mappingValue in mappingValues)
|
||||
{
|
||||
ParameterInfo matchingConstructorParameter = constructorParameters.ForgivingCaseSensitiveFind(kv => kv.Key.Name, mappingValue.Key.MappingName).Key;
|
||||
if (matchingConstructorParameter != null)
|
||||
constructorParameters[matchingConstructorParameter] = mappingValue.Value;
|
||||
else
|
||||
remainingMappingValues.Add(mappingValue);
|
||||
}
|
||||
|
||||
object createdObject = ReflectionUtils.CreateInstance(objectType, constructorParameters.Values.ToArray());
|
||||
|
||||
// go through unused values and set the newly created object's properties
|
||||
foreach (KeyValuePair<JsonMemberMapping, object> remainingMappingValue in remainingMappingValues)
|
||||
{
|
||||
if (ShouldSetMappingValue(remainingMappingValue.Key, remainingMappingValue.Value))
|
||||
ReflectionUtils.SetMemberValue(remainingMappingValue.Key.Member, createdObject, remainingMappingValue.Value);
|
||||
}
|
||||
|
||||
return createdObject;
|
||||
}
|
||||
|
||||
private object PopulateObject(object newObject, JsonReader reader, Type objectType)
|
||||
@@ -557,11 +641,6 @@ namespace Newtonsoft.Json
|
||||
JsonMemberMappingCollection memberMappings = GetMemberMappings(objectType);
|
||||
Dictionary<string, bool> requiredMappings =
|
||||
memberMappings.Where(m => m.Required).ToDictionary(m => m.MappingName, m => false);
|
||||
//List<RequiredMemberContext> requiredMappingContexts =
|
||||
// memberMappings.Where(m => m.Required).Select(m => new RequiredMemberContext(m.MappingName, false)).ToList();
|
||||
|
||||
//ObjectContext context = new ObjectContext(newObject, requiredMappingContexts);
|
||||
//DeserializeStack.Add(context);
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
@@ -574,10 +653,7 @@ namespace Newtonsoft.Json
|
||||
throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
|
||||
|
||||
if (reader.TokenType != JsonToken.Null)
|
||||
{
|
||||
if (requiredMappings.ContainsKey(memberName))
|
||||
requiredMappings[memberName] = true;
|
||||
}
|
||||
SetRequiredMapping(memberName, requiredMappings);
|
||||
|
||||
SetObjectMember(reader, newObject, objectType, memberName);
|
||||
break;
|
||||
@@ -587,8 +663,6 @@ namespace Newtonsoft.Json
|
||||
if (!requiredMapping.Value)
|
||||
throw new JsonSerializationException("Required property '{0}' not found in JSON.".FormatWith(CultureInfo.InvariantCulture, requiredMapping.Key));
|
||||
}
|
||||
// TODO: move below, change to RemoveAt
|
||||
//DeserializeStack.Remove(context);
|
||||
return newObject;
|
||||
default:
|
||||
throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
|
||||
@@ -597,6 +671,28 @@ namespace Newtonsoft.Json
|
||||
|
||||
throw new JsonSerializationException("Unexpected end when deserializing object.");
|
||||
}
|
||||
|
||||
private void SetRequiredMapping(string memberName, Dictionary<string, bool> requiredMappings)
|
||||
{
|
||||
// first attempt to find exact case match
|
||||
// then attempt case insensitive match
|
||||
if (requiredMappings.ContainsKey(memberName))
|
||||
{
|
||||
requiredMappings[memberName] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (KeyValuePair<string, bool> requiredMapping in requiredMappings)
|
||||
{
|
||||
if (string.Compare(requiredMapping.Key, requiredMapping.Key, StringComparison.OrdinalIgnoreCase) == 0)
|
||||
{
|
||||
requiredMappings[requiredMapping.Key] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Serialize
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Newtonsoft.Json.Utilities;
|
||||
|
||||
namespace Newtonsoft.Json
|
||||
@@ -47,6 +48,7 @@ namespace Newtonsoft.Json
|
||||
/// </summary>
|
||||
/// <value>The converters.</value>
|
||||
public IList<JsonConverter> Converters { get; set; }
|
||||
public IMappingResolver MappingResolver { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JsonSerializerSettings"/> class.
|
||||
|
||||
@@ -339,20 +339,21 @@ namespace Newtonsoft.Json.Linq
|
||||
/// </returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return ToString(null);
|
||||
return ToString(Formatting.Indented);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the indented JSON for this token using any given converters.
|
||||
/// Returns the JSON for this token using the given formatting and converters.
|
||||
/// </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>
|
||||
public string ToString(params JsonConverter[] converters)
|
||||
public string ToString(Formatting formatting, params JsonConverter[] converters)
|
||||
{
|
||||
using (StringWriter sw = new StringWriter(CultureInfo.InvariantCulture))
|
||||
{
|
||||
JsonTextWriter jw = new JsonTextWriter(sw);
|
||||
jw.Formatting = Formatting.Indented;
|
||||
jw.Formatting = formatting;
|
||||
|
||||
WriteTo(jw, converters);
|
||||
|
||||
|
||||
@@ -108,6 +108,9 @@
|
||||
<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\IMappingResolver.cs" />
|
||||
<Compile Include="Serialization\JsonMemberMapping.cs" />
|
||||
<Compile Include="Serialization\JsonMemberMappingCollection.cs" />
|
||||
<Compile Include="MissingMemberHandling.cs" />
|
||||
|
||||
@@ -97,6 +97,9 @@
|
||||
<Compile Include="ObjectCreationHandling.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ReferenceLoopHandling.cs" />
|
||||
<Compile Include="Serialization\CamelCaseMappingResolver.cs" />
|
||||
<Compile Include="Serialization\DefaultMappingResolver.cs" />
|
||||
<Compile Include="Serialization\IMappingResolver.cs" />
|
||||
<Compile Include="StringBuffer.cs" />
|
||||
<Compile Include="Utilities\CollectionUtils.cs" />
|
||||
<Compile Include="Utilities\CollectionWrapper.cs" />
|
||||
|
||||
@@ -126,6 +126,9 @@
|
||||
<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\IMappingResolver.cs" />
|
||||
<Compile Include="Serialization\JsonMemberMapping.cs" />
|
||||
<Compile Include="Serialization\JsonMemberMappingCollection.cs" />
|
||||
<Compile Include="MissingMemberHandling.cs" />
|
||||
|
||||
@@ -24,20 +24,20 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json.Utilities;
|
||||
using System.Globalization;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.ComponentModel;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Utilities;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace Newtonsoft.Json.Schema
|
||||
{
|
||||
public class JsonSchemaGenerator
|
||||
{
|
||||
public UndefinedSchemaIdHandling UndefinedSchemaIdHandling { get; set; }
|
||||
public IMappingResolver MappingResolver { get; set; }
|
||||
|
||||
private class TypeSchema
|
||||
{
|
||||
@@ -237,7 +237,12 @@ namespace Newtonsoft.Json.Schema
|
||||
{
|
||||
CurrentSchema.Id = GetTypeId(type, false);
|
||||
|
||||
JsonMemberMappingCollection mappings = JsonTypeReflector.GetMemberMappings(type);
|
||||
JsonMemberMappingCollection mappings;
|
||||
|
||||
if (MappingResolver != null)
|
||||
mappings = MappingResolver.ResolveMappings(type);
|
||||
else
|
||||
mappings = DefaultMappingResolver.Instance.ResolveMappings(type);
|
||||
|
||||
CurrentSchema.Properties = new Dictionary<string, JsonSchema>();
|
||||
foreach (JsonMemberMapping mapping in mappings)
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
#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;
|
||||
|
||||
namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
public class CamelCaseMappingResolver : DefaultMappingResolver
|
||||
{
|
||||
protected override string ResolveMappingName(string mappedName)
|
||||
{
|
||||
// lower case the first letter of the passed in name
|
||||
if (string.IsNullOrEmpty(mappedName))
|
||||
return mappedName;
|
||||
|
||||
if (!char.IsUpper(mappedName[0]))
|
||||
return mappedName;
|
||||
|
||||
string camelCaseName = char.ToLower(mappedName[0]).ToString();
|
||||
if (mappedName.Length > 1)
|
||||
camelCaseName += mappedName.Substring(1);
|
||||
|
||||
return camelCaseName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
#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.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json.Utilities;
|
||||
|
||||
namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
public class DefaultMappingResolver : IMappingResolver
|
||||
{
|
||||
internal static readonly IMappingResolver Instance = new DefaultMappingResolver();
|
||||
|
||||
private readonly Dictionary<Type, JsonMemberMappingCollection> TypeMemberMappingsCache = new Dictionary<Type, JsonMemberMappingCollection>();
|
||||
|
||||
public BindingFlags MemberSearchFlags { get; set; }
|
||||
|
||||
public DefaultMappingResolver()
|
||||
{
|
||||
MemberSearchFlags = BindingFlags.Public | BindingFlags.Instance;
|
||||
}
|
||||
|
||||
public virtual JsonMemberMappingCollection ResolveMappings(Type type)
|
||||
{
|
||||
JsonMemberMappingCollection memberMappings;
|
||||
|
||||
if (TypeMemberMappingsCache.TryGetValue(type, out memberMappings))
|
||||
return memberMappings;
|
||||
|
||||
// double check locking to avoid threading issues
|
||||
lock (TypeMemberMappingsCache)
|
||||
{
|
||||
if (TypeMemberMappingsCache.TryGetValue(type, out memberMappings))
|
||||
return memberMappings;
|
||||
|
||||
memberMappings = CreateMemberMappings(type);
|
||||
TypeMemberMappingsCache[type] = memberMappings;
|
||||
|
||||
return memberMappings;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual List<MemberInfo> GetSerializableMembers(Type objectType)
|
||||
{
|
||||
return ReflectionUtils.GetFieldsAndProperties(objectType, MemberSearchFlags);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
memberMappings.AddMapping(memberMapping);
|
||||
}
|
||||
|
||||
return memberMappings;
|
||||
}
|
||||
|
||||
protected virtual JsonMemberMapping CreateMemberMapping(MemberSerialization memberSerialization, MemberInfo member)
|
||||
{
|
||||
JsonPropertyAttribute propertyAttribute = ReflectionUtils.GetAttribute<JsonPropertyAttribute>(member, true);
|
||||
bool hasIgnoreAttribute = member.IsDefined(typeof(JsonIgnoreAttribute), true);
|
||||
|
||||
string mappedName = (propertyAttribute != null && propertyAttribute.PropertyName != null)
|
||||
? propertyAttribute.PropertyName
|
||||
: member.Name;
|
||||
|
||||
string resolvedMappedName = ResolveMappingName(mappedName);
|
||||
|
||||
bool required = (propertyAttribute != null) ? propertyAttribute.IsRequired : false;
|
||||
|
||||
bool ignored = (hasIgnoreAttribute
|
||||
|| (memberSerialization == MemberSerialization.OptIn && propertyAttribute == null));
|
||||
|
||||
bool readable = ReflectionUtils.CanReadMemberValue(member);
|
||||
bool writable = ReflectionUtils.CanSetMemberValue(member);
|
||||
|
||||
JsonConverter memberConverter = JsonTypeReflector.GetConverter(member, ReflectionUtils.GetMemberUnderlyingType(member));
|
||||
|
||||
DefaultValueAttribute defaultValueAttribute = ReflectionUtils.GetAttribute<DefaultValueAttribute>(member, true);
|
||||
object defaultValue = (defaultValueAttribute != null) ? defaultValueAttribute.Value : null;
|
||||
|
||||
return new JsonMemberMapping(resolvedMappedName, member, ignored, readable, writable, memberConverter, defaultValue, required);
|
||||
}
|
||||
|
||||
protected virtual string ResolveMappingName(string mappedName)
|
||||
{
|
||||
return mappedName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#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;
|
||||
|
||||
namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
/// <summary>
|
||||
/// Resolves member mappings for a type.
|
||||
/// </summary>
|
||||
public interface IMappingResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a collection of <see cref="JsonMemberMapping"/> for the specified <see cref="Type"/>
|
||||
/// to be used during serialization.</see>
|
||||
/// </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);
|
||||
}
|
||||
}
|
||||
@@ -64,18 +64,29 @@ namespace Newtonsoft.Json.Serialization
|
||||
Add(memberMapping);
|
||||
}
|
||||
|
||||
public bool TryGetMapping(string mappingName, out JsonMemberMapping memberMapping)
|
||||
public bool TryGetClosestMatchMapping(string mappingName, out JsonMemberMapping memberMapping)
|
||||
{
|
||||
if (Contains(mappingName))
|
||||
{
|
||||
memberMapping = this[mappingName];
|
||||
if (TryGetMapping(mappingName, StringComparison.Ordinal, out memberMapping))
|
||||
return true;
|
||||
}
|
||||
else
|
||||
if (TryGetMapping(mappingName, StringComparison.OrdinalIgnoreCase, out memberMapping))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetMapping(string mappingName, StringComparison comparisonType, out JsonMemberMapping memberMapping)
|
||||
{
|
||||
foreach (JsonMemberMapping mapping in this)
|
||||
{
|
||||
memberMapping = default(JsonMemberMapping);
|
||||
return false;
|
||||
if (string.Compare(mappingName, mapping.MappingName, comparisonType) == 0)
|
||||
{
|
||||
memberMapping = mapping;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
memberMapping = default(JsonMemberMapping);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,11 +25,8 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json.Utilities;
|
||||
|
||||
namespace Newtonsoft.Json.Serialization
|
||||
@@ -37,7 +34,6 @@ namespace Newtonsoft.Json.Serialization
|
||||
internal static class JsonTypeReflector
|
||||
{
|
||||
private static readonly Dictionary<ICustomAttributeProvider, Type> ConverterTypeCache = new Dictionary<ICustomAttributeProvider, Type>();
|
||||
private static readonly Dictionary<Type, JsonMemberMappingCollection> TypeMemberMappingsCache = new Dictionary<Type, JsonMemberMappingCollection>();
|
||||
private static readonly Dictionary<Type, JsonContainerAttribute> TypeContainerAttributeCache = new Dictionary<Type, JsonContainerAttribute>();
|
||||
|
||||
public static JsonContainerAttribute GetJsonContainerAttribute(Type type)
|
||||
@@ -70,66 +66,6 @@ namespace Newtonsoft.Json.Serialization
|
||||
return objectAttribute.MemberSerialization;
|
||||
}
|
||||
|
||||
public static JsonMemberMappingCollection GetMemberMappings(Type objectType)
|
||||
{
|
||||
JsonMemberMappingCollection memberMappings;
|
||||
|
||||
if (TypeMemberMappingsCache.TryGetValue(objectType, out memberMappings))
|
||||
return memberMappings;
|
||||
|
||||
// double check locking to avoid threading issues
|
||||
lock (TypeMemberMappingsCache)
|
||||
{
|
||||
if (TypeMemberMappingsCache.TryGetValue(objectType, out memberMappings))
|
||||
return memberMappings;
|
||||
|
||||
memberMappings = CreateMemberMappings(objectType);
|
||||
TypeMemberMappingsCache[objectType] = memberMappings;
|
||||
|
||||
return memberMappings;
|
||||
}
|
||||
}
|
||||
|
||||
public static JsonMemberMappingCollection CreateMemberMappings(Type objectType)
|
||||
{
|
||||
MemberSerialization memberSerialization = 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)
|
||||
{
|
||||
JsonPropertyAttribute propertyAttribute = ReflectionUtils.GetAttribute<JsonPropertyAttribute>(member, true);
|
||||
bool hasIgnoreAttribute = member.IsDefined(typeof(JsonIgnoreAttribute), true);
|
||||
|
||||
string mappedName = (propertyAttribute != null && propertyAttribute.PropertyName != null)
|
||||
? propertyAttribute.PropertyName
|
||||
: member.Name;
|
||||
|
||||
bool required = (propertyAttribute != null) ? propertyAttribute.IsRequired : false;
|
||||
|
||||
bool ignored = (hasIgnoreAttribute
|
||||
|| (memberSerialization == MemberSerialization.OptIn && propertyAttribute == null));
|
||||
|
||||
bool readable = ReflectionUtils.CanReadMemberValue(member);
|
||||
bool writable = ReflectionUtils.CanSetMemberValue(member);
|
||||
|
||||
JsonConverter memberConverter = GetConverter(member, ReflectionUtils.GetMemberUnderlyingType(member));
|
||||
|
||||
DefaultValueAttribute defaultValueAttribute = ReflectionUtils.GetAttribute<DefaultValueAttribute>(member, true);
|
||||
object defaultValue = (defaultValueAttribute != null) ? defaultValueAttribute.Value : null;
|
||||
|
||||
JsonMemberMapping memberMapping = new JsonMemberMapping(mappedName, member, ignored, readable, writable, memberConverter, defaultValue, required);
|
||||
|
||||
memberMappings.AddMapping(memberMapping);
|
||||
}
|
||||
|
||||
return memberMappings;
|
||||
}
|
||||
|
||||
private static Type GetConverterType(ICustomAttributeProvider attributeProvider)
|
||||
{
|
||||
Type converterType;
|
||||
@@ -170,10 +106,5 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<MemberInfo> GetSerializableMembers(Type objectType)
|
||||
{
|
||||
return ReflectionUtils.GetFieldsAndProperties(objectType, BindingFlags.Public | BindingFlags.Instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -352,6 +352,14 @@ namespace Newtonsoft.Json.Utilities
|
||||
return (IList)ReflectionUtils.CreateGeneric(typeof(List<>), listType);
|
||||
}
|
||||
|
||||
public static IDictionary CreateGenericDictionary(Type keyType, Type valueType)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(keyType, "keyType");
|
||||
ValidationUtils.ArgumentNotNull(valueType, "valueType");
|
||||
|
||||
return (IDictionary)ReflectionUtils.CreateGeneric(typeof(Dictionary<,>), keyType, valueType);
|
||||
}
|
||||
|
||||
public static bool IsListType(Type type)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(type, "type");
|
||||
|
||||
@@ -224,7 +224,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
return type.GetElementType();
|
||||
}
|
||||
else if (ImplementsGenericDefinition(type, typeof(ICollection<>), out genericListType))
|
||||
else if (ImplementsGenericDefinition(type, typeof(IEnumerable<>), out genericListType))
|
||||
{
|
||||
if (genericListType.IsGenericTypeDefinition)
|
||||
throw new Exception("Type {0} is not a collection.".FormatWith(CultureInfo.InvariantCulture, type));
|
||||
|
||||
Reference in New Issue
Block a user