-Improved deserialization performance
-Added ISerializable support -Changed dictionary serialization to fall back to ToString for keys -Changed schema generator to use JsonContracts to determine schema information -Fixed schema validation bugs when schema has no properties -Fixed not marking dictionary and array schemas as nullable -Fixed serializing generic dictionary that doesn't implement IDictionary
This commit is contained in:
@@ -36,6 +36,8 @@ using Newtonsoft.Json.Schema;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Extensions=Newtonsoft.Json.Schema.Extensions;
|
||||||
|
|
||||||
namespace Newtonsoft.Json.Tests.Schema
|
namespace Newtonsoft.Json.Tests.Schema
|
||||||
{
|
{
|
||||||
@@ -52,12 +54,26 @@ namespace Newtonsoft.Json.Tests.Schema
|
|||||||
Assert.AreEqual(@"{
|
Assert.AreEqual(@"{
|
||||||
""type"": ""object"",
|
""type"": ""object"",
|
||||||
""additionalProperties"": {
|
""additionalProperties"": {
|
||||||
""type"": ""array"",
|
""type"": [
|
||||||
|
""array"",
|
||||||
|
""null""
|
||||||
|
],
|
||||||
""items"": {
|
""items"": {
|
||||||
""type"": ""string""
|
""type"": ""string""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}", json);
|
}", json);
|
||||||
|
|
||||||
|
Dictionary<string, List<string>> value = new Dictionary<string, List<string>>
|
||||||
|
{
|
||||||
|
{"HasValue", new List<string>() { "first", "second"}},
|
||||||
|
{"NoValue", null}
|
||||||
|
};
|
||||||
|
|
||||||
|
string valueJson = JsonConvert.SerializeObject(value, Formatting.Indented);
|
||||||
|
JObject o = JObject.Parse(valueJson);
|
||||||
|
|
||||||
|
Assert.IsTrue(o.IsValid(schema));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !PocketPC
|
#if !PocketPC
|
||||||
@@ -279,10 +295,49 @@ namespace Newtonsoft.Json.Tests.Schema
|
|||||||
JsonSchema schema = generator.Generate(typeof(Type));
|
JsonSchema schema = generator.Generate(typeof(Type));
|
||||||
|
|
||||||
Assert.AreEqual(JsonSchemaType.String, schema.Type);
|
Assert.AreEqual(JsonSchemaType.String, schema.Type);
|
||||||
|
|
||||||
|
string json = JsonConvert.SerializeObject(typeof(Version), Formatting.Indented);
|
||||||
|
|
||||||
|
JValue v = new JValue(json);
|
||||||
|
Assert.IsTrue(v.IsValid(schema));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !SILVERLIGHT && !PocketPC
|
||||||
|
[Test]
|
||||||
|
public void GenerateSchemaForISerializable()
|
||||||
|
{
|
||||||
|
JsonSchemaGenerator generator = new JsonSchemaGenerator();
|
||||||
|
generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
|
||||||
|
|
||||||
|
JsonSchema schema = generator.Generate(typeof(Exception));
|
||||||
|
|
||||||
|
Assert.AreEqual(JsonSchemaType.Object, schema.Type);
|
||||||
|
Assert.AreEqual(true, schema.AllowAdditionalProperties);
|
||||||
|
Assert.AreEqual(null, schema.Properties);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GenerateSchemaForDBNull()
|
||||||
|
{
|
||||||
|
JsonSchemaGenerator generator = new JsonSchemaGenerator();
|
||||||
|
generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
|
||||||
|
|
||||||
|
JsonSchema schema = generator.Generate(typeof(DBNull));
|
||||||
|
|
||||||
|
Assert.AreEqual(JsonSchemaType.Null, schema.Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CustomDirectoryInfoMapper : DefaultContractResolver
|
public class CustomDirectoryInfoMapper : DefaultContractResolver
|
||||||
{
|
{
|
||||||
|
protected override JsonContract CreateContract(Type objectType)
|
||||||
|
{
|
||||||
|
if (objectType == typeof(DirectoryInfo))
|
||||||
|
return base.CreateObjectContract(objectType);
|
||||||
|
|
||||||
|
return base.CreateContract(objectType);
|
||||||
|
}
|
||||||
|
|
||||||
protected override IList<JsonProperty> CreateProperties(JsonObjectContract contract)
|
protected override IList<JsonProperty> CreateProperties(JsonObjectContract contract)
|
||||||
{
|
{
|
||||||
IList<JsonProperty> properties = base.CreateProperties(contract);
|
IList<JsonProperty> properties = base.CreateProperties(contract);
|
||||||
@@ -299,6 +354,7 @@ namespace Newtonsoft.Json.Tests.Schema
|
|||||||
{
|
{
|
||||||
JsonSchemaGenerator generator = new JsonSchemaGenerator();
|
JsonSchemaGenerator generator = new JsonSchemaGenerator();
|
||||||
generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
|
generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
|
||||||
|
generator.ContractResolver = new CustomDirectoryInfoMapper();
|
||||||
|
|
||||||
JsonSchema schema = generator.Generate(typeof(DirectoryInfo), true);
|
JsonSchema schema = generator.Generate(typeof(DirectoryInfo), true);
|
||||||
|
|
||||||
@@ -324,9 +380,6 @@ namespace Newtonsoft.Json.Tests.Schema
|
|||||||
""Exists"": {
|
""Exists"": {
|
||||||
""type"": ""boolean""
|
""type"": ""boolean""
|
||||||
},
|
},
|
||||||
""Root"": {
|
|
||||||
""$ref"": ""System.IO.DirectoryInfo""
|
|
||||||
},
|
|
||||||
""FullName"": {
|
""FullName"": {
|
||||||
""type"": [
|
""type"": [
|
||||||
""string"",
|
""string"",
|
||||||
@@ -374,9 +427,7 @@ namespace Newtonsoft.Json.Tests.Schema
|
|||||||
List<string> errors = new List<string>();
|
List<string> errors = new List<string>();
|
||||||
jsonWriter.Token.Validate(schema, (sender, args) => errors.Add(args.Message));
|
jsonWriter.Token.Validate(schema, (sender, args) => errors.Add(args.Message));
|
||||||
|
|
||||||
Assert.AreEqual(2, errors.Count);
|
Assert.AreEqual(0, errors.Count);
|
||||||
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]
|
[Test]
|
||||||
@@ -386,64 +437,34 @@ namespace Newtonsoft.Json.Tests.Schema
|
|||||||
generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
|
generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
|
||||||
generator.ContractResolver = new CamelCasePropertyNamesContractResolver();
|
generator.ContractResolver = new CamelCasePropertyNamesContractResolver();
|
||||||
|
|
||||||
JsonSchema schema = generator.Generate(typeof (DirectoryInfo), true);
|
JsonSchema schema = generator.Generate(typeof (Version), true);
|
||||||
|
|
||||||
string json = schema.ToString();
|
string json = schema.ToString();
|
||||||
|
|
||||||
Assert.AreEqual(@"{
|
Assert.AreEqual(@"{
|
||||||
""id"": ""System.IO.DirectoryInfo"",
|
""id"": ""System.Version"",
|
||||||
""type"": [
|
""type"": [
|
||||||
""object"",
|
""object"",
|
||||||
""null""
|
""null""
|
||||||
],
|
],
|
||||||
""additionalProperties"": false,
|
""additionalProperties"": false,
|
||||||
""properties"": {
|
""properties"": {
|
||||||
""name"": {
|
""major"": {
|
||||||
""type"": [
|
""type"": ""integer""
|
||||||
""string"",
|
|
||||||
""null""
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
""parent"": {
|
""minor"": {
|
||||||
""$ref"": ""System.IO.DirectoryInfo""
|
""type"": ""integer""
|
||||||
},
|
},
|
||||||
""exists"": {
|
""build"": {
|
||||||
""type"": ""boolean""
|
""type"": ""integer""
|
||||||
},
|
},
|
||||||
""root"": {
|
""revision"": {
|
||||||
""$ref"": ""System.IO.DirectoryInfo""
|
""type"": ""integer""
|
||||||
},
|
},
|
||||||
""fullName"": {
|
""majorRevision"": {
|
||||||
""type"": [
|
""type"": ""integer""
|
||||||
""string"",
|
|
||||||
""null""
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
""extension"": {
|
""minorRevision"": {
|
||||||
""type"": [
|
|
||||||
""string"",
|
|
||||||
""null""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
""creationTime"": {
|
|
||||||
""type"": ""string""
|
|
||||||
},
|
|
||||||
""creationTimeUtc"": {
|
|
||||||
""type"": ""string""
|
|
||||||
},
|
|
||||||
""lastAccessTime"": {
|
|
||||||
""type"": ""string""
|
|
||||||
},
|
|
||||||
""lastAccessTimeUtc"": {
|
|
||||||
""type"": ""string""
|
|
||||||
},
|
|
||||||
""lastWriteTime"": {
|
|
||||||
""type"": ""string""
|
|
||||||
},
|
|
||||||
""lastWriteTimeUtc"": {
|
|
||||||
""type"": ""string""
|
|
||||||
},
|
|
||||||
""attributes"": {
|
|
||||||
""type"": ""integer""
|
""type"": ""integer""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1981,14 +1981,31 @@ keyword such as type of business.""
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Could not create string property name from type 'Newtonsoft.Json.Tests.TestObjects.Person'.")]
|
|
||||||
public void SerializePersonKeyedDictionary()
|
public void SerializePersonKeyedDictionary()
|
||||||
{
|
{
|
||||||
Dictionary<Person, int> dictionary = new Dictionary<Person, int>();
|
Dictionary<Person, int> dictionary = new Dictionary<Person, int>();
|
||||||
dictionary.Add(new Person { Name = "p1" }, 1);
|
dictionary.Add(new Person { Name = "p1" }, 1);
|
||||||
dictionary.Add(new Person { Name = "p2" }, 2);
|
dictionary.Add(new Person { Name = "p2" }, 2);
|
||||||
|
|
||||||
JsonConvert.SerializeObject(dictionary, Formatting.Indented);
|
string json = JsonConvert.SerializeObject(dictionary, Formatting.Indented);
|
||||||
|
|
||||||
|
Assert.AreEqual(@"{
|
||||||
|
""Newtonsoft.Json.Tests.TestObjects.Person"": 1,
|
||||||
|
""Newtonsoft.Json.Tests.TestObjects.Person"": 2
|
||||||
|
}", json);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Could not convert string 'Newtonsoft.Json.Tests.TestObjects.Person' to dictionary key type Newtonsoft.Json.Tests.TestObjects.Person. Create a TypeConverter to convert from the string to the key type object.")]
|
||||||
|
public void DeserializePersonKeyedDictionary()
|
||||||
|
{
|
||||||
|
string json =
|
||||||
|
@"{
|
||||||
|
""Newtonsoft.Json.Tests.TestObjects.Person"": 1,
|
||||||
|
""Newtonsoft.Json.Tests.TestObjects.Person"": 2
|
||||||
|
}";
|
||||||
|
|
||||||
|
JsonConvert.DeserializeObject<Dictionary<Person, int>>(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -2314,5 +2331,288 @@ keyword such as type of business.""
|
|||||||
|
|
||||||
Assert.AreEqual(123, item.Value);
|
Assert.AreEqual(123, item.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract class Animal
|
||||||
|
{
|
||||||
|
public abstract string Name { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Human : Animal
|
||||||
|
{
|
||||||
|
public override string Name
|
||||||
|
{
|
||||||
|
get { return typeof(Human).Name; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Ethnicity { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !NET20 && !PocketPC
|
||||||
|
public class DataContractJsonSerializerTestClass
|
||||||
|
{
|
||||||
|
public TimeSpan TimeSpanProperty { get; set; }
|
||||||
|
public Guid GuidProperty { get; set; }
|
||||||
|
public Animal AnimalProperty { get; set; }
|
||||||
|
public Exception ExceptionProperty { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void DataContractJsonSerializerTest()
|
||||||
|
{
|
||||||
|
Exception ex = new Exception("Blah blah blah");
|
||||||
|
|
||||||
|
DataContractJsonSerializerTestClass c = new DataContractJsonSerializerTestClass();
|
||||||
|
c.TimeSpanProperty = new TimeSpan(200, 20, 59, 30, 900);
|
||||||
|
c.GuidProperty = new Guid("66143115-BE2A-4a59-AF0A-348E1EA15B1E");
|
||||||
|
c.AnimalProperty = new Human() {Ethnicity = "European"};
|
||||||
|
c.ExceptionProperty = ex;
|
||||||
|
|
||||||
|
MemoryStream ms = new MemoryStream();
|
||||||
|
DataContractJsonSerializer serializer = new DataContractJsonSerializer(
|
||||||
|
typeof(DataContractJsonSerializerTestClass),
|
||||||
|
new Type[] { typeof(Human) });
|
||||||
|
serializer.WriteObject(ms, c);
|
||||||
|
|
||||||
|
byte[] jsonBytes = ms.ToArray();
|
||||||
|
string json = Encoding.UTF8.GetString(jsonBytes, 0, jsonBytes.Length);
|
||||||
|
|
||||||
|
Console.WriteLine(JObject.Parse(json).ToString());
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
Console.WriteLine(JsonConvert.SerializeObject(c, Formatting.Indented, new JsonSerializerSettings
|
||||||
|
{
|
||||||
|
// TypeNameHandling = TypeNameHandling.Objects
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public class ModelStateDictionary<T> : IDictionary<string, T>
|
||||||
|
{
|
||||||
|
|
||||||
|
private readonly Dictionary<string, T> _innerDictionary = new Dictionary<string, T>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
public ModelStateDictionary()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModelStateDictionary(ModelStateDictionary<T> dictionary)
|
||||||
|
{
|
||||||
|
if (dictionary == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("dictionary");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var entry in dictionary)
|
||||||
|
{
|
||||||
|
_innerDictionary.Add(entry.Key, entry.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _innerDictionary.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsReadOnly
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return ((IDictionary<string, T>)_innerDictionary).IsReadOnly;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICollection<string> Keys
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _innerDictionary.Keys;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public T this[string key]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
T value;
|
||||||
|
_innerDictionary.TryGetValue(key, out value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_innerDictionary[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICollection<T> Values
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _innerDictionary.Values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(KeyValuePair<string, T> item)
|
||||||
|
{
|
||||||
|
((IDictionary<string, T>)_innerDictionary).Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(string key, T value)
|
||||||
|
{
|
||||||
|
_innerDictionary.Add(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
_innerDictionary.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(KeyValuePair<string, T> item)
|
||||||
|
{
|
||||||
|
return ((IDictionary<string, T>)_innerDictionary).Contains(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ContainsKey(string key)
|
||||||
|
{
|
||||||
|
return _innerDictionary.ContainsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo(KeyValuePair<string, T>[] array, int arrayIndex)
|
||||||
|
{
|
||||||
|
((IDictionary<string, T>)_innerDictionary).CopyTo(array, arrayIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<KeyValuePair<string, T>> GetEnumerator()
|
||||||
|
{
|
||||||
|
return _innerDictionary.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Merge(ModelStateDictionary<T> dictionary)
|
||||||
|
{
|
||||||
|
if (dictionary == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var entry in dictionary)
|
||||||
|
{
|
||||||
|
this[entry.Key] = entry.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(KeyValuePair<string, T> item)
|
||||||
|
{
|
||||||
|
return ((IDictionary<string, T>)_innerDictionary).Remove(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(string key)
|
||||||
|
{
|
||||||
|
return _innerDictionary.Remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetValue(string key, out T value)
|
||||||
|
{
|
||||||
|
return _innerDictionary.TryGetValue(key, out value);
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return ((IEnumerable)_innerDictionary).GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SerializeNonIDictionary()
|
||||||
|
{
|
||||||
|
ModelStateDictionary<string> modelStateDictionary = new ModelStateDictionary<string>();
|
||||||
|
modelStateDictionary.Add("key", "value");
|
||||||
|
|
||||||
|
string json = JsonConvert.SerializeObject(modelStateDictionary);
|
||||||
|
|
||||||
|
Assert.AreEqual(@"{""key"":""value""}", json);
|
||||||
|
|
||||||
|
ModelStateDictionary<string> newModelStateDictionary = JsonConvert.DeserializeObject<ModelStateDictionary<string>>(json);
|
||||||
|
Assert.AreEqual(1, newModelStateDictionary.Count);
|
||||||
|
Assert.AreEqual("value", newModelStateDictionary["key"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !SILVERLIGHT && !PocketPC
|
||||||
|
public class ISerializableTestObject : ISerializable
|
||||||
|
{
|
||||||
|
internal string _stringValue;
|
||||||
|
internal int _intValue;
|
||||||
|
internal DateTimeOffset _dateTimeOffsetValue;
|
||||||
|
internal Person _personValue;
|
||||||
|
internal Person _nullPersonValue;
|
||||||
|
|
||||||
|
public ISerializableTestObject(string stringValue, int intValue, DateTimeOffset dateTimeOffset, Person personValue)
|
||||||
|
{
|
||||||
|
_stringValue = stringValue;
|
||||||
|
_intValue = intValue;
|
||||||
|
_dateTimeOffsetValue = dateTimeOffset;
|
||||||
|
_personValue = personValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ISerializableTestObject(SerializationInfo info, StreamingContext context)
|
||||||
|
{
|
||||||
|
_stringValue = info.GetString("stringValue");
|
||||||
|
_intValue = info.GetInt32("intValue");
|
||||||
|
_dateTimeOffsetValue = (DateTimeOffset)info.GetValue("dateTimeOffsetValue", typeof(DateTimeOffset));
|
||||||
|
_personValue = (Person)info.GetValue("personValue", typeof(Person));
|
||||||
|
_nullPersonValue = (Person)info.GetValue("nullPersonValue", typeof(Person));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||||
|
{
|
||||||
|
info.AddValue("stringValue", _stringValue);
|
||||||
|
info.AddValue("intValue", _intValue);
|
||||||
|
info.AddValue("dateTimeOffsetValue", _dateTimeOffsetValue);
|
||||||
|
info.AddValue("personValue", _personValue);
|
||||||
|
info.AddValue("nullPersonValue", _nullPersonValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SerializeISerializableTestObject()
|
||||||
|
{
|
||||||
|
Person person = new Person();
|
||||||
|
person.BirthDate = new DateTime(2000, 1, 1, 1, 1, 1, DateTimeKind.Utc);
|
||||||
|
person.LastModified = person.BirthDate;
|
||||||
|
person.Department = "Department!";
|
||||||
|
person.Name = "Name!";
|
||||||
|
|
||||||
|
DateTimeOffset dateTimeOffset = new DateTimeOffset(2000, 12, 20, 22, 59, 59, TimeSpan.FromHours(2));
|
||||||
|
string dateTimeOffsetText;
|
||||||
|
#if !NET20
|
||||||
|
dateTimeOffsetText = @"\/Date(977345999000+0200)\/";
|
||||||
|
#else
|
||||||
|
dateTimeOffsetText = @"12/20/2000 22:59:59 +02:00";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ISerializableTestObject o = new ISerializableTestObject("String!", int.MinValue, dateTimeOffset, person);
|
||||||
|
|
||||||
|
string json = JsonConvert.SerializeObject(o, Formatting.Indented);
|
||||||
|
Assert.AreEqual(@"{
|
||||||
|
""stringValue"": ""String!"",
|
||||||
|
""intValue"": -2147483648,
|
||||||
|
""dateTimeOffsetValue"": """ + dateTimeOffsetText + @""",
|
||||||
|
""personValue"": {
|
||||||
|
""Name"": ""Name!"",
|
||||||
|
""BirthDate"": ""\/Date(946688461000)\/"",
|
||||||
|
""LastModified"": ""\/Date(946688461000)\/""
|
||||||
|
},
|
||||||
|
""nullPersonValue"": null
|
||||||
|
}", json);
|
||||||
|
|
||||||
|
ISerializableTestObject o2 = JsonConvert.DeserializeObject<ISerializableTestObject>(json);
|
||||||
|
Assert.AreEqual("String!", o2._stringValue);
|
||||||
|
Assert.AreEqual(int.MinValue, o2._intValue);
|
||||||
|
Assert.AreEqual(dateTimeOffset, o2._dateTimeOffsetValue);
|
||||||
|
Assert.AreEqual("Name!", o2._personValue.Name);
|
||||||
|
Assert.AreEqual(null, o2._nullPersonValue);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -472,6 +472,9 @@ namespace Newtonsoft.Json
|
|||||||
|
|
||||||
internal static bool IsJsonPrimitiveType(Type type)
|
internal static bool IsJsonPrimitiveType(Type type)
|
||||||
{
|
{
|
||||||
|
if (ReflectionUtils.IsNullableType(type))
|
||||||
|
type = Nullable.GetUnderlyingType(type);
|
||||||
|
|
||||||
#if !PocketPC && !NET20
|
#if !PocketPC && !NET20
|
||||||
if (type == typeof(DateTimeOffset))
|
if (type == typeof(DateTimeOffset))
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -70,9 +70,9 @@ namespace Newtonsoft.Json
|
|||||||
_schema = schema;
|
_schema = schema;
|
||||||
|
|
||||||
if (_schema != null && _schema.Properties != null)
|
if (_schema != null && _schema.Properties != null)
|
||||||
{
|
|
||||||
_requiredProperties = GetRequiredProperties(_schema).Distinct().ToDictionary(p => p, p => false);
|
_requiredProperties = GetRequiredProperties(_schema).Distinct().ToDictionary(p => p, p => false);
|
||||||
}
|
else
|
||||||
|
_requiredProperties = new Dictionary<string, bool>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<string> GetRequiredProperties(JsonSchemaModel schema)
|
private IEnumerable<string> GetRequiredProperties(JsonSchemaModel schema)
|
||||||
@@ -178,7 +178,7 @@ namespace Newtonsoft.Json
|
|||||||
throw new Exception("CurrentPropertyName has not been set on scope.");
|
throw new Exception("CurrentPropertyName has not been set on scope.");
|
||||||
|
|
||||||
JsonSchemaModel propertySchema;
|
JsonSchemaModel propertySchema;
|
||||||
if (CurrentSchema.Properties.TryGetValue(_currentScope.CurrentPropertyName, out propertySchema))
|
if (CurrentSchema.Properties != null && CurrentSchema.Properties.TryGetValue(_currentScope.CurrentPropertyName, out propertySchema))
|
||||||
return propertySchema;
|
return propertySchema;
|
||||||
|
|
||||||
return (CurrentSchema.AllowAdditionalProperties) ? CurrentSchema.AdditionalProperties : null;
|
return (CurrentSchema.AllowAdditionalProperties) ? CurrentSchema.AdditionalProperties : null;
|
||||||
@@ -552,7 +552,7 @@ namespace Newtonsoft.Json
|
|||||||
if (_currentScope.RequiredProperties.ContainsKey(propertyName))
|
if (_currentScope.RequiredProperties.ContainsKey(propertyName))
|
||||||
_currentScope.RequiredProperties[propertyName] = true;
|
_currentScope.RequiredProperties[propertyName] = true;
|
||||||
|
|
||||||
if (!schema.Properties.ContainsKey(propertyName))
|
if (schema.Properties != null && !schema.Properties.ContainsKey(propertyName))
|
||||||
{
|
{
|
||||||
IList<string> definedProperties = schema.Properties.Select(p => p.Key).ToList();
|
IList<string> definedProperties = schema.Properties.Select(p => p.Key).ToList();
|
||||||
|
|
||||||
|
|||||||
@@ -151,6 +151,8 @@
|
|||||||
<Compile Include="Schema\JsonSchemaGenerator.cs" />
|
<Compile Include="Schema\JsonSchemaGenerator.cs" />
|
||||||
<Compile Include="Schema\JsonSchemaResolver.cs" />
|
<Compile Include="Schema\JsonSchemaResolver.cs" />
|
||||||
<Compile Include="Schema\JsonSchemaType.cs" />
|
<Compile Include="Schema\JsonSchemaType.cs" />
|
||||||
|
<Compile Include="Serialization\JsonFormatterConverter.cs" />
|
||||||
|
<Compile Include="Serialization\JsonISerializableContract.cs" />
|
||||||
<Compile Include="Serialization\JsonLinqContract.cs" />
|
<Compile Include="Serialization\JsonLinqContract.cs" />
|
||||||
<Compile Include="Serialization\JsonObjectContract.cs" />
|
<Compile Include="Serialization\JsonObjectContract.cs" />
|
||||||
<Compile Include="Serialization\JsonPrimitiveContract.cs" />
|
<Compile Include="Serialization\JsonPrimitiveContract.cs" />
|
||||||
@@ -160,7 +162,9 @@
|
|||||||
<Compile Include="Serialization\JsonSerializerInternalReader.cs" />
|
<Compile Include="Serialization\JsonSerializerInternalReader.cs" />
|
||||||
<Compile Include="Serialization\JsonSerializerInternalWriter.cs" />
|
<Compile Include="Serialization\JsonSerializerInternalWriter.cs" />
|
||||||
<Compile Include="Serialization\JsonSerializerProxy.cs" />
|
<Compile Include="Serialization\JsonSerializerProxy.cs" />
|
||||||
|
<Compile Include="Serialization\JsonStringContract.cs" />
|
||||||
<Compile Include="Serialization\JsonTypeReflector.cs" />
|
<Compile Include="Serialization\JsonTypeReflector.cs" />
|
||||||
|
<Compile Include="Serialization\MemberHandler.cs" />
|
||||||
<Compile Include="Serialization\OnErrorAttribute.cs" />
|
<Compile Include="Serialization\OnErrorAttribute.cs" />
|
||||||
<Compile Include="Serialization\ReflectionValueProvider.cs" />
|
<Compile Include="Serialization\ReflectionValueProvider.cs" />
|
||||||
<Compile Include="StreamingContext.cs" />
|
<Compile Include="StreamingContext.cs" />
|
||||||
|
|||||||
@@ -160,6 +160,8 @@
|
|||||||
<Compile Include="Serialization\JsonArrayContract.cs" />
|
<Compile Include="Serialization\JsonArrayContract.cs" />
|
||||||
<Compile Include="Serialization\JsonContract.cs" />
|
<Compile Include="Serialization\JsonContract.cs" />
|
||||||
<Compile Include="Serialization\JsonDictionaryContract.cs" />
|
<Compile Include="Serialization\JsonDictionaryContract.cs" />
|
||||||
|
<Compile Include="Serialization\JsonFormatterConverter.cs" />
|
||||||
|
<Compile Include="Serialization\JsonISerializableContract.cs" />
|
||||||
<Compile Include="Serialization\JsonLinqContract.cs" />
|
<Compile Include="Serialization\JsonLinqContract.cs" />
|
||||||
<Compile Include="Serialization\JsonPrimitiveContract.cs" />
|
<Compile Include="Serialization\JsonPrimitiveContract.cs" />
|
||||||
<Compile Include="Serialization\JsonProperty.cs" />
|
<Compile Include="Serialization\JsonProperty.cs" />
|
||||||
@@ -178,8 +180,10 @@
|
|||||||
<Compile Include="Serialization\JsonSerializerInternalReader.cs" />
|
<Compile Include="Serialization\JsonSerializerInternalReader.cs" />
|
||||||
<Compile Include="Serialization\JsonSerializerInternalWriter.cs" />
|
<Compile Include="Serialization\JsonSerializerInternalWriter.cs" />
|
||||||
<Compile Include="Serialization\JsonSerializerProxy.cs" />
|
<Compile Include="Serialization\JsonSerializerProxy.cs" />
|
||||||
|
<Compile Include="Serialization\JsonStringContract.cs" />
|
||||||
<Compile Include="Serialization\JsonTypeReflector.cs" />
|
<Compile Include="Serialization\JsonTypeReflector.cs" />
|
||||||
<Compile Include="Serialization\CachedAttributeGetter.cs" />
|
<Compile Include="Serialization\CachedAttributeGetter.cs" />
|
||||||
|
<Compile Include="Serialization\MemberHandler.cs" />
|
||||||
<Compile Include="Serialization\OnErrorAttribute.cs" />
|
<Compile Include="Serialization\OnErrorAttribute.cs" />
|
||||||
<Compile Include="Serialization\ReflectionValueProvider.cs" />
|
<Compile Include="Serialization\ReflectionValueProvider.cs" />
|
||||||
<Compile Include="Utilities\Base64Encoder.cs" />
|
<Compile Include="Utilities\Base64Encoder.cs" />
|
||||||
|
|||||||
@@ -135,6 +135,8 @@
|
|||||||
<Compile Include="Serialization\JsonArrayContract.cs" />
|
<Compile Include="Serialization\JsonArrayContract.cs" />
|
||||||
<Compile Include="Serialization\JsonContract.cs" />
|
<Compile Include="Serialization\JsonContract.cs" />
|
||||||
<Compile Include="Serialization\JsonDictionaryContract.cs" />
|
<Compile Include="Serialization\JsonDictionaryContract.cs" />
|
||||||
|
<Compile Include="Serialization\JsonFormatterConverter.cs" />
|
||||||
|
<Compile Include="Serialization\JsonISerializableContract.cs" />
|
||||||
<Compile Include="Serialization\JsonLinqContract.cs" />
|
<Compile Include="Serialization\JsonLinqContract.cs" />
|
||||||
<Compile Include="Serialization\JsonObjectContract.cs" />
|
<Compile Include="Serialization\JsonObjectContract.cs" />
|
||||||
<Compile Include="Serialization\JsonPrimitiveContract.cs" />
|
<Compile Include="Serialization\JsonPrimitiveContract.cs" />
|
||||||
@@ -144,6 +146,8 @@
|
|||||||
<Compile Include="Serialization\JsonSerializerProxy.cs" />
|
<Compile Include="Serialization\JsonSerializerProxy.cs" />
|
||||||
<Compile Include="Serialization\JsonSerializerInternalReader.cs" />
|
<Compile Include="Serialization\JsonSerializerInternalReader.cs" />
|
||||||
<Compile Include="Serialization\JsonSerializerInternalWriter.cs" />
|
<Compile Include="Serialization\JsonSerializerInternalWriter.cs" />
|
||||||
|
<Compile Include="Serialization\JsonStringContract.cs" />
|
||||||
|
<Compile Include="Serialization\MemberHandler.cs" />
|
||||||
<Compile Include="Serialization\OnErrorAttribute.cs" />
|
<Compile Include="Serialization\OnErrorAttribute.cs" />
|
||||||
<Compile Include="Serialization\ReflectionValueProvider.cs" />
|
<Compile Include="Serialization\ReflectionValueProvider.cs" />
|
||||||
<Compile Include="StreamingContext.cs" />
|
<Compile Include="StreamingContext.cs" />
|
||||||
|
|||||||
@@ -92,6 +92,8 @@
|
|||||||
<Compile Include="Linq\JPath.cs" />
|
<Compile Include="Linq\JPath.cs" />
|
||||||
<Compile Include="Linq\JRaw.cs" />
|
<Compile Include="Linq\JRaw.cs" />
|
||||||
<Compile Include="Required.cs" />
|
<Compile Include="Required.cs" />
|
||||||
|
<Compile Include="Serialization\JsonFormatterConverter.cs" />
|
||||||
|
<Compile Include="Serialization\JsonISerializableContract.cs" />
|
||||||
<Compile Include="Serialization\JsonLinqContract.cs" />
|
<Compile Include="Serialization\JsonLinqContract.cs" />
|
||||||
<Compile Include="Serialization\JsonPrimitiveContract.cs" />
|
<Compile Include="Serialization\JsonPrimitiveContract.cs" />
|
||||||
<Compile Include="Serialization\DynamicValueProvider.cs" />
|
<Compile Include="Serialization\DynamicValueProvider.cs" />
|
||||||
@@ -178,6 +180,7 @@
|
|||||||
<Compile Include="Serialization\JsonSerializerInternalReader.cs" />
|
<Compile Include="Serialization\JsonSerializerInternalReader.cs" />
|
||||||
<Compile Include="Serialization\JsonSerializerInternalWriter.cs" />
|
<Compile Include="Serialization\JsonSerializerInternalWriter.cs" />
|
||||||
<Compile Include="Serialization\JsonSerializerProxy.cs" />
|
<Compile Include="Serialization\JsonSerializerProxy.cs" />
|
||||||
|
<Compile Include="Serialization\JsonStringContract.cs" />
|
||||||
<Compile Include="Serialization\JsonTypeReflector.cs" />
|
<Compile Include="Serialization\JsonTypeReflector.cs" />
|
||||||
<Compile Include="Serialization\CachedAttributeGetter.cs" />
|
<Compile Include="Serialization\CachedAttributeGetter.cs" />
|
||||||
<Compile Include="Serialization\ReflectionValueProvider.cs" />
|
<Compile Include="Serialization\ReflectionValueProvider.cs" />
|
||||||
@@ -185,6 +188,7 @@
|
|||||||
<Compile Include="Utilities\Base64Encoder.cs" />
|
<Compile Include="Utilities\Base64Encoder.cs" />
|
||||||
<Compile Include="Utilities\DynamicWrapper.cs" />
|
<Compile Include="Utilities\DynamicWrapper.cs" />
|
||||||
<Compile Include="Utilities\LateBoundDelegateFactory.cs" />
|
<Compile Include="Utilities\LateBoundDelegateFactory.cs" />
|
||||||
|
<Compile Include="Serialization\MemberHandler.cs" />
|
||||||
<Compile Include="Utilities\ThreadSafeStore.cs" />
|
<Compile Include="Utilities\ThreadSafeStore.cs" />
|
||||||
<Compile Include="TypeNameHandling.cs" />
|
<Compile Include="TypeNameHandling.cs" />
|
||||||
<Compile Include="Utilities\BidirectionalDictionary.cs" />
|
<Compile Include="Utilities\BidirectionalDictionary.cs" />
|
||||||
|
|||||||
@@ -233,10 +233,11 @@ namespace Newtonsoft.Json.Schema
|
|||||||
CurrentSchema.Title = GetTitle(type);
|
CurrentSchema.Title = GetTitle(type);
|
||||||
CurrentSchema.Description = GetDescription(type);
|
CurrentSchema.Description = GetDescription(type);
|
||||||
|
|
||||||
if (CollectionUtils.IsDictionaryType(type))
|
JsonContract contract = ContractResolver.ResolveContract(type);
|
||||||
|
|
||||||
|
if (contract is JsonDictionaryContract)
|
||||||
{
|
{
|
||||||
// TODO: include null
|
CurrentSchema.Type = AddNullType(JsonSchemaType.Object, valueRequired);
|
||||||
CurrentSchema.Type = JsonSchemaType.Object;
|
|
||||||
|
|
||||||
Type keyType;
|
Type keyType;
|
||||||
Type valueType;
|
Type valueType;
|
||||||
@@ -251,10 +252,9 @@ namespace Newtonsoft.Json.Schema
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (CollectionUtils.IsCollectionType(type))
|
else if (contract is JsonArrayContract)
|
||||||
{
|
{
|
||||||
// TODO: include null
|
CurrentSchema.Type = AddNullType(JsonSchemaType.Array, valueRequired);
|
||||||
CurrentSchema.Type = JsonSchemaType.Array;
|
|
||||||
|
|
||||||
CurrentSchema.Id = GetTypeId(type, false);
|
CurrentSchema.Id = GetTypeId(type, false);
|
||||||
|
|
||||||
@@ -268,37 +268,11 @@ namespace Newtonsoft.Json.Schema
|
|||||||
CurrentSchema.Items.Add(GenerateInternal(collectionItemType, (!allowNullItem) ? Required.Always : Required.Default));
|
CurrentSchema.Items.Add(GenerateInternal(collectionItemType, (!allowNullItem) ? Required.Always : Required.Default));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (contract is JsonPrimitiveContract)
|
||||||
{
|
{
|
||||||
CurrentSchema.Type = GetJsonSchemaType(type, valueRequired);
|
CurrentSchema.Type = GetJsonSchemaType(type, valueRequired);
|
||||||
|
|
||||||
if (HasFlag(CurrentSchema.Type, JsonSchemaType.Object))
|
if (CurrentSchema.Type == JsonSchemaType.Integer && type.IsEnum && !type.IsDefined(typeof(FlagsAttribute), true))
|
||||||
{
|
|
||||||
CurrentSchema.Id = GetTypeId(type, false);
|
|
||||||
|
|
||||||
JsonObjectContract contract = ContractResolver.ResolveContract(type) as JsonObjectContract;
|
|
||||||
|
|
||||||
if (contract == null)
|
|
||||||
throw new Exception("Could not resolve contract for '{0}'.".FormatWith(CultureInfo.InvariantCulture, type));
|
|
||||||
|
|
||||||
CurrentSchema.Properties = new Dictionary<string, JsonSchema>();
|
|
||||||
foreach (JsonProperty property in contract.Properties)
|
|
||||||
{
|
|
||||||
if (!property.Ignored)
|
|
||||||
{
|
|
||||||
JsonSchema propertySchema = GenerateInternal(property.PropertyType, property.Required);
|
|
||||||
|
|
||||||
if (property.DefaultValue != null)
|
|
||||||
propertySchema.Default = JToken.FromObject(property.DefaultValue);
|
|
||||||
|
|
||||||
CurrentSchema.Properties.Add(property.PropertyName, propertySchema);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type.IsSealed)
|
|
||||||
CurrentSchema.AllowAdditionalProperties = false;
|
|
||||||
}
|
|
||||||
else if (CurrentSchema.Type == JsonSchemaType.Integer && type.IsEnum && !type.IsDefined(typeof(FlagsAttribute), true))
|
|
||||||
{
|
{
|
||||||
CurrentSchema.Enum = new List<JToken>();
|
CurrentSchema.Enum = new List<JToken>();
|
||||||
CurrentSchema.Options = new Dictionary<JToken, string>();
|
CurrentSchema.Options = new Dictionary<JToken, string>();
|
||||||
@@ -313,10 +287,71 @@ namespace Newtonsoft.Json.Schema
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (contract is JsonObjectContract)
|
||||||
|
{
|
||||||
|
CurrentSchema.Type = AddNullType(JsonSchemaType.Object, valueRequired);
|
||||||
|
CurrentSchema.Id = GetTypeId(type, false);
|
||||||
|
GenerateObjectSchema(type, (JsonObjectContract)contract);
|
||||||
|
}
|
||||||
|
#if !SILVERLIGHT && !PocketPC
|
||||||
|
else if (contract is JsonISerializableContract)
|
||||||
|
{
|
||||||
|
CurrentSchema.Type = AddNullType(JsonSchemaType.Object, valueRequired);
|
||||||
|
CurrentSchema.Id = GetTypeId(type, false);
|
||||||
|
GenerateISerializableContract(type, (JsonISerializableContract) contract);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else if (contract is JsonStringContract)
|
||||||
|
{
|
||||||
|
JsonSchemaType schemaType = (!ReflectionUtils.IsNullable(contract.UnderlyingType))
|
||||||
|
? JsonSchemaType.String
|
||||||
|
: AddNullType(JsonSchemaType.String, valueRequired);
|
||||||
|
|
||||||
|
CurrentSchema.Type = schemaType;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("Unexpected contract type: {0}".FormatWith(CultureInfo.InvariantCulture, contract));
|
||||||
|
}
|
||||||
|
|
||||||
return Pop().Schema;
|
return Pop().Schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private JsonSchemaType AddNullType(JsonSchemaType type, Required valueRequired)
|
||||||
|
{
|
||||||
|
if (valueRequired != Required.Always)
|
||||||
|
return type | JsonSchemaType.Null;
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateObjectSchema(Type type, JsonObjectContract contract)
|
||||||
|
{
|
||||||
|
CurrentSchema.Properties = new Dictionary<string, JsonSchema>();
|
||||||
|
foreach (JsonProperty property in contract.Properties)
|
||||||
|
{
|
||||||
|
if (!property.Ignored)
|
||||||
|
{
|
||||||
|
JsonSchema propertySchema = GenerateInternal(property.PropertyType, property.Required);
|
||||||
|
|
||||||
|
if (property.DefaultValue != null)
|
||||||
|
propertySchema.Default = JToken.FromObject(property.DefaultValue);
|
||||||
|
|
||||||
|
CurrentSchema.Properties.Add(property.PropertyName, propertySchema);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type.IsSealed)
|
||||||
|
CurrentSchema.AllowAdditionalProperties = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !SILVERLIGHT && !PocketPC
|
||||||
|
private void GenerateISerializableContract(Type type, JsonISerializableContract contract)
|
||||||
|
{
|
||||||
|
CurrentSchema.AllowAdditionalProperties = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
internal static bool HasFlag(JsonSchemaType? value, JsonSchemaType flag)
|
internal static bool HasFlag(JsonSchemaType? value, JsonSchemaType flag)
|
||||||
{
|
{
|
||||||
// default value is Any
|
// default value is Any
|
||||||
|
|||||||
@@ -315,33 +315,90 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
return contract;
|
return contract;
|
||||||
}
|
}
|
||||||
|
|
||||||
private JsonContract CreateContract(Type objectType)
|
#if !SILVERLIGHT && !PocketPC
|
||||||
|
protected virtual JsonISerializableContract CreateISerializableContract(Type objectType)
|
||||||
|
{
|
||||||
|
JsonISerializableContract contract = new JsonISerializableContract(objectType);
|
||||||
|
InitializeContract(contract);
|
||||||
|
|
||||||
|
ConstructorInfo constructorInfo = objectType.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new [] {typeof (SerializationInfo), typeof (StreamingContext)}, null);
|
||||||
|
if (constructorInfo != null)
|
||||||
|
contract.ISerializableCreator = LateBoundDelegateFactory.CreateMethodHandler(constructorInfo);
|
||||||
|
|
||||||
|
return contract;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected virtual JsonStringContract CreateStringContract(Type objectType)
|
||||||
|
{
|
||||||
|
JsonStringContract contract = new JsonStringContract(objectType);
|
||||||
|
InitializeContract(contract);
|
||||||
|
|
||||||
|
return contract;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual JsonContract CreateContract(Type objectType)
|
||||||
{
|
{
|
||||||
if (JsonConvert.IsJsonPrimitiveType(objectType))
|
if (JsonConvert.IsJsonPrimitiveType(objectType))
|
||||||
{
|
|
||||||
return CreatePrimitiveContract(objectType);
|
return CreatePrimitiveContract(objectType);
|
||||||
}
|
|
||||||
if (JsonTypeReflector.GetJsonObjectAttribute(objectType) != null)
|
if (JsonTypeReflector.GetJsonObjectAttribute(objectType) != null)
|
||||||
{
|
|
||||||
return CreateObjectContract(objectType);
|
return CreateObjectContract(objectType);
|
||||||
}
|
|
||||||
|
if (JsonTypeReflector.GetJsonArrayAttribute(objectType) != null)
|
||||||
|
return CreateArrayContract(objectType);
|
||||||
|
|
||||||
if (objectType.IsSubclassOf(typeof(JToken)))
|
if (objectType.IsSubclassOf(typeof(JToken)))
|
||||||
{
|
|
||||||
return CreateLinqContract(objectType);
|
return CreateLinqContract(objectType);
|
||||||
}
|
|
||||||
|
bool canConvertToString = CanConvertToString(objectType);
|
||||||
|
|
||||||
|
#if !SILVERLIGHT && !PocketPC
|
||||||
|
if (typeof(ISerializable).IsAssignableFrom(objectType) && !canConvertToString)
|
||||||
|
return CreateISerializableContract(objectType);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (CollectionUtils.IsDictionaryType(objectType))
|
if (CollectionUtils.IsDictionaryType(objectType))
|
||||||
{
|
|
||||||
return CreateDictionaryContract(objectType);
|
return CreateDictionaryContract(objectType);
|
||||||
}
|
|
||||||
if (typeof(IEnumerable).IsAssignableFrom(objectType))
|
if (typeof(IEnumerable).IsAssignableFrom(objectType))
|
||||||
{
|
|
||||||
return CreateArrayContract(objectType);
|
return CreateArrayContract(objectType);
|
||||||
}
|
|
||||||
|
if (canConvertToString)
|
||||||
|
return CreateStringContract(objectType);
|
||||||
|
|
||||||
return CreateObjectContract(objectType);
|
return CreateObjectContract(objectType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static bool CanConvertToString(Type type)
|
||||||
|
{
|
||||||
|
#if !PocketPC
|
||||||
|
TypeConverter converter = ConvertUtils.GetConverter(type);
|
||||||
|
|
||||||
|
// use the objectType's TypeConverter if it has one and can convert to a string
|
||||||
|
if (converter != null
|
||||||
|
#if !SILVERLIGHT
|
||||||
|
&& !(converter is ComponentConverter)
|
||||||
|
&& !(converter is ReferenceConverter)
|
||||||
|
#endif
|
||||||
|
&& converter.GetType() != typeof(TypeConverter))
|
||||||
|
{
|
||||||
|
if (converter.CanConvertTo(typeof(string)))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (type == typeof(Type) || type.IsSubclassOf(typeof(Type)))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
#if SILVERLIGHT || PocketPC
|
||||||
|
if (type == typeof(Guid) || type == typeof(Uri) || type == typeof(TimeSpan))
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private static bool IsValidCallback(MethodInfo method, ParameterInfo[] parameters, Type attributeType, MethodInfo currentCallback, ref Type prevAttributeType)
|
private static bool IsValidCallback(MethodInfo method, ParameterInfo[] parameters, Type attributeType, MethodInfo currentCallback, ref Type prevAttributeType)
|
||||||
{
|
{
|
||||||
if (!method.IsDefined(attributeType, false))
|
if (!method.IsDefined(attributeType, false))
|
||||||
|
|||||||
@@ -0,0 +1,154 @@
|
|||||||
|
#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 !SILVERLIGHT && !PocketPC
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.Text;
|
||||||
|
using Newtonsoft.Json.Utilities;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace Newtonsoft.Json.Serialization
|
||||||
|
{
|
||||||
|
internal class JsonFormatterConverter : IFormatterConverter
|
||||||
|
{
|
||||||
|
private readonly JsonSerializer _serializer;
|
||||||
|
|
||||||
|
public JsonFormatterConverter(JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(serializer, "serializer");
|
||||||
|
|
||||||
|
_serializer = serializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private T GetTokenValue<T>(object value)
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(value, "value");
|
||||||
|
|
||||||
|
JValue v = (JValue)value;
|
||||||
|
return (T)System.Convert.ChangeType(v.Value, typeof(T), CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object Convert(object value, Type type)
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(value, "value");
|
||||||
|
|
||||||
|
JToken token = value as JToken;
|
||||||
|
if (token == null)
|
||||||
|
throw new ArgumentException("Value is not a JToken.", "value");
|
||||||
|
|
||||||
|
return _serializer.Deserialize(token.CreateReader(), type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object Convert(object value, TypeCode typeCode)
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(value, "value");
|
||||||
|
|
||||||
|
if (value is JValue)
|
||||||
|
value = ((JValue) value).Value;
|
||||||
|
|
||||||
|
return System.Convert.ChangeType(value, typeCode, CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ToBoolean(object value)
|
||||||
|
{
|
||||||
|
return GetTokenValue<bool>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte ToByte(object value)
|
||||||
|
{
|
||||||
|
return GetTokenValue<byte>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public char ToChar(object value)
|
||||||
|
{
|
||||||
|
return GetTokenValue<char>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime ToDateTime(object value)
|
||||||
|
{
|
||||||
|
return GetTokenValue<DateTime>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public decimal ToDecimal(object value)
|
||||||
|
{
|
||||||
|
return GetTokenValue<decimal>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double ToDouble(object value)
|
||||||
|
{
|
||||||
|
return GetTokenValue<double>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public short ToInt16(object value)
|
||||||
|
{
|
||||||
|
return GetTokenValue<short>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ToInt32(object value)
|
||||||
|
{
|
||||||
|
return GetTokenValue<int>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long ToInt64(object value)
|
||||||
|
{
|
||||||
|
return GetTokenValue<long>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public sbyte ToSByte(object value)
|
||||||
|
{
|
||||||
|
return GetTokenValue<sbyte>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float ToSingle(object value)
|
||||||
|
{
|
||||||
|
return GetTokenValue<float>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToString(object value)
|
||||||
|
{
|
||||||
|
return GetTokenValue<string>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ushort ToUInt16(object value)
|
||||||
|
{
|
||||||
|
return GetTokenValue<ushort>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint ToUInt32(object value)
|
||||||
|
{
|
||||||
|
return GetTokenValue<uint>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ulong ToUInt64(object value)
|
||||||
|
{
|
||||||
|
return GetTokenValue<ulong>(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
#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 !SILVERLIGHT && !PocketPC
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
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 JsonISerializableContract : JsonContract
|
||||||
|
{
|
||||||
|
public MemberHandler<object> ISerializableCreator { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonISerializableContract"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="underlyingType">The underlying type for the contract.</param>
|
||||||
|
public JsonISerializableContract(Type underlyingType)
|
||||||
|
: base(underlyingType)
|
||||||
|
{
|
||||||
|
CreatedType = underlyingType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -39,6 +39,9 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
internal class JsonSerializerInternalReader : JsonSerializerInternalBase
|
internal class JsonSerializerInternalReader : JsonSerializerInternalBase
|
||||||
{
|
{
|
||||||
private JsonSerializerProxy _internalSerializer;
|
private JsonSerializerProxy _internalSerializer;
|
||||||
|
#if !SILVERLIGHT && !PocketPC
|
||||||
|
private JsonFormatterConverter _formatterConverter;
|
||||||
|
#endif
|
||||||
|
|
||||||
public JsonSerializerInternalReader(JsonSerializer serializer) : base(serializer)
|
public JsonSerializerInternalReader(JsonSerializer serializer) : base(serializer)
|
||||||
{
|
{
|
||||||
@@ -122,6 +125,16 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
return _internalSerializer;
|
return _internalSerializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !SILVERLIGHT && !PocketPC
|
||||||
|
private JsonFormatterConverter GetFormatterConverter()
|
||||||
|
{
|
||||||
|
if (_formatterConverter == null)
|
||||||
|
_formatterConverter = new JsonFormatterConverter(GetInternalSerializer());
|
||||||
|
|
||||||
|
return _formatterConverter;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
private JToken CreateJToken(JsonReader reader, JsonContract contract)
|
private JToken CreateJToken(JsonReader reader, JsonContract contract)
|
||||||
{
|
{
|
||||||
ValidationUtils.ArgumentNotNull(reader, "reader");
|
ValidationUtils.ArgumentNotNull(reader, "reader");
|
||||||
@@ -320,21 +333,31 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
if (contract == null)
|
if (contract == null)
|
||||||
throw new JsonSerializationException("Could not resolve type '{0}' to a JsonContract.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
throw new JsonSerializationException("Could not resolve type '{0}' to a JsonContract.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
||||||
|
|
||||||
if (contract is JsonDictionaryContract)
|
JsonDictionaryContract dictionaryContract = contract as JsonDictionaryContract;
|
||||||
|
if (dictionaryContract != null)
|
||||||
{
|
{
|
||||||
if (existingValue == null)
|
if (existingValue == null)
|
||||||
return CreateAndPopulateDictionary(reader, (JsonDictionaryContract) contract, id);
|
return CreateAndPopulateDictionary(reader, dictionaryContract, id);
|
||||||
|
|
||||||
return PopulateDictionary(CollectionUtils.CreateDictionaryWrapper(existingValue), reader, (JsonDictionaryContract) contract, id);
|
return PopulateDictionary(dictionaryContract.CreateWrapper(existingValue), reader, dictionaryContract, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contract is JsonObjectContract)
|
JsonObjectContract objectContract = contract as JsonObjectContract;
|
||||||
|
if (objectContract != null)
|
||||||
{
|
{
|
||||||
if (existingValue == null)
|
if (existingValue == null)
|
||||||
return CreateAndPopulateObject(reader, (JsonObjectContract) contract, id);
|
return CreateAndPopulateObject(reader, objectContract, id);
|
||||||
|
|
||||||
return PopulateObject(existingValue, reader, (JsonObjectContract) contract, id);
|
return PopulateObject(existingValue, reader, objectContract, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !SILVERLIGHT && !PocketPC
|
||||||
|
JsonISerializableContract serializableContract = contract as JsonISerializableContract;
|
||||||
|
if (serializableContract != null)
|
||||||
|
{
|
||||||
|
return CreateISerializable(reader, serializableContract, id);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
throw new JsonSerializationException("Cannot deserialize JSON object into type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
throw new JsonSerializationException("Cannot deserialize JSON object into type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
||||||
}
|
}
|
||||||
@@ -367,7 +390,7 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
if (existingValue == null)
|
if (existingValue == null)
|
||||||
value = CreateAndPopulateList(reader, reference, arrayContract);
|
value = CreateAndPopulateList(reader, reference, arrayContract);
|
||||||
else
|
else
|
||||||
value = PopulateList(CollectionUtils.CreateCollectionWrapper(existingValue), reader, reference, arrayContract);
|
value = PopulateList(arrayContract.CreateWrapper(existingValue), reader, reference, arrayContract);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -501,7 +524,16 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
switch (reader.TokenType)
|
switch (reader.TokenType)
|
||||||
{
|
{
|
||||||
case JsonToken.PropertyName:
|
case JsonToken.PropertyName:
|
||||||
object keyValue = EnsureType(reader.Value, contract.DictionaryKeyType);
|
object keyValue;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
keyValue = EnsureType(reader.Value, contract.DictionaryKeyType);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new JsonSerializationException("Could not convert string '{0}' to dictionary key type {1}. Create a TypeConverter to convert from the string to the key type object.".FormatWith(CultureInfo.InvariantCulture, reader.Value, contract.DictionaryKeyType), ex);
|
||||||
|
}
|
||||||
|
|
||||||
CheckedRead(reader);
|
CheckedRead(reader);
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -588,6 +620,48 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
throw new JsonSerializationException("Unexpected end when deserializing array.");
|
throw new JsonSerializationException("Unexpected end when deserializing array.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !SILVERLIGHT && !PocketPC
|
||||||
|
private object CreateISerializable(JsonReader reader, JsonISerializableContract contract, string id)
|
||||||
|
{
|
||||||
|
Type objectType = contract.UnderlyingType;
|
||||||
|
|
||||||
|
SerializationInfo serializationInfo = new SerializationInfo(contract.UnderlyingType, GetFormatterConverter());
|
||||||
|
|
||||||
|
bool exit = false;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
|
||||||
|
serializationInfo.AddValue(memberName, JToken.ReadFrom(reader));
|
||||||
|
break;
|
||||||
|
case JsonToken.EndObject:
|
||||||
|
exit = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
|
||||||
|
}
|
||||||
|
} while (!exit && reader.Read());
|
||||||
|
|
||||||
|
if (contract.ISerializableCreator == null)
|
||||||
|
throw new JsonSerializationException("ISerializable type '{0}' does not have a valid constructor.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
||||||
|
|
||||||
|
object createdObject = contract.ISerializableCreator(null, new object[] { serializationInfo, Serializer.Context });
|
||||||
|
|
||||||
|
if (id != null)
|
||||||
|
Serializer.ReferenceResolver.AddReference(id, createdObject);
|
||||||
|
|
||||||
|
contract.InvokeOnDeserializing(createdObject, Serializer.Context);
|
||||||
|
contract.InvokeOnDeserialized(createdObject, Serializer.Context);
|
||||||
|
|
||||||
|
return createdObject;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
private object CreateAndPopulateObject(JsonReader reader, JsonObjectContract contract, string id)
|
private object CreateAndPopulateObject(JsonReader reader, JsonObjectContract contract, string id)
|
||||||
{
|
{
|
||||||
object newObject = null;
|
object newObject = null;
|
||||||
|
|||||||
@@ -101,9 +101,9 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
{
|
{
|
||||||
writer.WriteValue(value);
|
writer.WriteValue(value);
|
||||||
}
|
}
|
||||||
else if (value is JToken)
|
else if (contract is JsonStringContract)
|
||||||
{
|
{
|
||||||
((JToken) value).WriteTo(writer, (Serializer.Converters != null) ? Serializer.Converters.ToArray() : null);
|
SerializeString(writer, value, (JsonStringContract) contract);
|
||||||
}
|
}
|
||||||
else if (contract is JsonObjectContract)
|
else if (contract is JsonObjectContract)
|
||||||
{
|
{
|
||||||
@@ -111,7 +111,8 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
}
|
}
|
||||||
else if (contract is JsonDictionaryContract)
|
else if (contract is JsonDictionaryContract)
|
||||||
{
|
{
|
||||||
SerializeDictionary(writer, (IDictionary) value, (JsonDictionaryContract) contract);
|
JsonDictionaryContract dictionaryContract = (JsonDictionaryContract) contract;
|
||||||
|
SerializeDictionary(writer, dictionaryContract.CreateWrapper(value), dictionaryContract);
|
||||||
}
|
}
|
||||||
else if (contract is JsonArrayContract)
|
else if (contract is JsonArrayContract)
|
||||||
{
|
{
|
||||||
@@ -130,6 +131,16 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
CultureInfo.InvariantCulture, value.GetType()));
|
CultureInfo.InvariantCulture, value.GetType()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (contract is JsonLinqContract)
|
||||||
|
{
|
||||||
|
((JToken)value).WriteTo(writer, (Serializer.Converters != null) ? Serializer.Converters.ToArray() : null);
|
||||||
|
}
|
||||||
|
#if !SILVERLIGHT && !PocketPC
|
||||||
|
else if (contract is JsonISerializableContract)
|
||||||
|
{
|
||||||
|
SerializeISerializable(writer, (ISerializable) value, (JsonISerializableContract) contract);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ShouldWriteReference(object value, JsonProperty property, JsonContract contract)
|
private bool ShouldWriteReference(object value, JsonProperty property, JsonContract contract)
|
||||||
@@ -264,18 +275,20 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SerializeObject(JsonWriter writer, object value, JsonObjectContract contract)
|
private void SerializeString(JsonWriter writer, object value, JsonStringContract contract)
|
||||||
{
|
{
|
||||||
contract.InvokeOnSerializing(value, Serializer.Context);
|
contract.InvokeOnSerializing(value, Serializer.Context);
|
||||||
|
|
||||||
string s;
|
string s;
|
||||||
if (TryConvertToString(value, contract.UnderlyingType, out s))
|
TryConvertToString(value, contract.UnderlyingType, out s);
|
||||||
{
|
writer.WriteValue(s);
|
||||||
writer.WriteValue(s);
|
|
||||||
contract.InvokeOnSerialized(value, Serializer.Context);
|
|
||||||
|
|
||||||
return;
|
contract.InvokeOnSerialized(value, Serializer.Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SerializeObject(JsonWriter writer, object value, JsonObjectContract contract)
|
||||||
|
{
|
||||||
|
contract.InvokeOnSerializing(value, Serializer.Context);
|
||||||
|
|
||||||
SerializeStack.Add(value);
|
SerializeStack.Add(value);
|
||||||
writer.WriteStartObject();
|
writer.WriteStartObject();
|
||||||
@@ -429,22 +442,46 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
contract.InvokeOnSerialized(values, Serializer.Context);
|
contract.InvokeOnSerialized(values, Serializer.Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SerializeDictionary(JsonWriter writer, IDictionary values, JsonDictionaryContract contract)
|
#if !SILVERLIGHT && !PocketPC
|
||||||
|
private void SerializeISerializable(JsonWriter writer, ISerializable value, JsonISerializableContract contract)
|
||||||
{
|
{
|
||||||
contract.InvokeOnSerializing(values, Serializer.Context);
|
contract.InvokeOnSerializing(value, Serializer.Context);
|
||||||
|
SerializeStack.Add(value);
|
||||||
|
|
||||||
SerializeStack.Add(values);
|
writer.WriteStartObject();
|
||||||
|
|
||||||
|
SerializationInfo serializationInfo = new SerializationInfo(contract.UnderlyingType, new FormatterConverter());
|
||||||
|
value.GetObjectData(serializationInfo, Serializer.Context);
|
||||||
|
|
||||||
|
foreach (SerializationEntry serializationEntry in serializationInfo)
|
||||||
|
{
|
||||||
|
writer.WritePropertyName(serializationEntry.Name);
|
||||||
|
SerializeValue(writer, serializationEntry.Value, null, GetContractSafe(serializationEntry.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WriteEndObject();
|
||||||
|
|
||||||
|
SerializeStack.RemoveAt(SerializeStack.Count - 1);
|
||||||
|
contract.InvokeOnSerialized(value, Serializer.Context);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private void SerializeDictionary(JsonWriter writer, IWrappedDictionary values, JsonDictionaryContract contract)
|
||||||
|
{
|
||||||
|
contract.InvokeOnSerializing(values.UnderlyingDictionary, Serializer.Context);
|
||||||
|
|
||||||
|
SerializeStack.Add(values.UnderlyingDictionary);
|
||||||
writer.WriteStartObject();
|
writer.WriteStartObject();
|
||||||
|
|
||||||
bool isReference = contract.IsReference ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects);
|
bool isReference = contract.IsReference ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects);
|
||||||
if (isReference)
|
if (isReference)
|
||||||
{
|
{
|
||||||
writer.WritePropertyName(JsonTypeReflector.IdPropertyName);
|
writer.WritePropertyName(JsonTypeReflector.IdPropertyName);
|
||||||
writer.WriteValue(Serializer.ReferenceResolver.GetReference(values));
|
writer.WriteValue(Serializer.ReferenceResolver.GetReference(values.UnderlyingDictionary));
|
||||||
}
|
}
|
||||||
if (HasFlag(Serializer.TypeNameHandling, TypeNameHandling.Objects))
|
if (HasFlag(Serializer.TypeNameHandling, TypeNameHandling.Objects))
|
||||||
{
|
{
|
||||||
WriteTypeProperty(writer, values.GetType());
|
WriteTypeProperty(writer, values.UnderlyingDictionary.GetType());
|
||||||
}
|
}
|
||||||
|
|
||||||
int initialDepth = writer.Top;
|
int initialDepth = writer.Top;
|
||||||
@@ -475,7 +512,7 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
if (IsErrorHandled(values, contract, propertyName, ex))
|
if (IsErrorHandled(values.UnderlyingDictionary, contract, propertyName, ex))
|
||||||
HandleError(writer, initialDepth);
|
HandleError(writer, initialDepth);
|
||||||
else
|
else
|
||||||
throw;
|
throw;
|
||||||
@@ -485,7 +522,7 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
writer.WriteEndObject();
|
writer.WriteEndObject();
|
||||||
SerializeStack.RemoveAt(SerializeStack.Count - 1);
|
SerializeStack.RemoveAt(SerializeStack.Count - 1);
|
||||||
|
|
||||||
contract.InvokeOnSerialized(values, Serializer.Context);
|
contract.InvokeOnSerialized(values.UnderlyingDictionary, Serializer.Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetPropertyName(DictionaryEntry entry)
|
private string GetPropertyName(DictionaryEntry entry)
|
||||||
@@ -496,8 +533,8 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
return Convert.ToString(entry.Key, CultureInfo.InvariantCulture);
|
return Convert.ToString(entry.Key, CultureInfo.InvariantCulture);
|
||||||
else if (TryConvertToString(entry.Key, entry.Key.GetType(), out propertyName))
|
else if (TryConvertToString(entry.Key, entry.Key.GetType(), out propertyName))
|
||||||
return propertyName;
|
return propertyName;
|
||||||
|
else
|
||||||
throw new JsonSerializationException("Could not create string property name from type '{0}'.".FormatWith(CultureInfo.InvariantCulture, entry.Key.GetType()));
|
return entry.Key.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleError(JsonWriter writer, int initialDepth)
|
private void HandleError(JsonWriter writer, int initialDepth)
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#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>
|
||||||
|
/// Contract details for a <see cref="Type"/> used by the <see cref="JsonSerializer"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class JsonStringContract : JsonContract
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonStringContract"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="underlyingType">The underlying type for the contract.</param>
|
||||||
|
public JsonStringContract(Type underlyingType)
|
||||||
|
: base(underlyingType)
|
||||||
|
{
|
||||||
|
CreatedType = underlyingType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -83,6 +83,11 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
return GetJsonContainerAttribute(type) as JsonObjectAttribute;
|
return GetJsonContainerAttribute(type) as JsonObjectAttribute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static JsonArrayAttribute GetJsonArrayAttribute(Type type)
|
||||||
|
{
|
||||||
|
return GetJsonContainerAttribute(type) as JsonArrayAttribute;
|
||||||
|
}
|
||||||
|
|
||||||
#if !PocketPC && !NET20
|
#if !PocketPC && !NET20
|
||||||
public static DataContractAttribute GetDataContractAttribute(Type type)
|
public static DataContractAttribute GetDataContractAttribute(Type type)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
namespace Newtonsoft.Json.Serialization
|
||||||
|
{
|
||||||
|
public delegate object MemberHandler<T>(T target, params object[] args);
|
||||||
|
}
|
||||||
@@ -248,11 +248,11 @@ namespace Newtonsoft.Json.Utilities
|
|||||||
return _dictionary.Contains(key);
|
return _dictionary.Contains(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct DictionaryEnumerator : IDictionaryEnumerator
|
private struct DictionaryEnumerator<TEnumeratorKey, TEnumeratorValue> : IDictionaryEnumerator
|
||||||
{
|
{
|
||||||
private IEnumerator _e;
|
private readonly IEnumerator<KeyValuePair<TEnumeratorKey, TEnumeratorValue>> _e;
|
||||||
|
|
||||||
public DictionaryEnumerator(IEnumerator e)
|
public DictionaryEnumerator(IEnumerator<KeyValuePair<TEnumeratorKey, TEnumeratorValue>> e)
|
||||||
{
|
{
|
||||||
ValidationUtils.ArgumentNotNull(e, "e");
|
ValidationUtils.ArgumentNotNull(e, "e");
|
||||||
_e = e;
|
_e = e;
|
||||||
@@ -275,7 +275,7 @@ namespace Newtonsoft.Json.Utilities
|
|||||||
|
|
||||||
public object Current
|
public object Current
|
||||||
{
|
{
|
||||||
get { return _e.Current; }
|
get { return new DictionaryEntry(_e.Current.Key, _e.Current.Value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool MoveNext()
|
public bool MoveNext()
|
||||||
@@ -292,7 +292,7 @@ namespace Newtonsoft.Json.Utilities
|
|||||||
IDictionaryEnumerator IDictionary.GetEnumerator()
|
IDictionaryEnumerator IDictionary.GetEnumerator()
|
||||||
{
|
{
|
||||||
if (_genericDictionary != null)
|
if (_genericDictionary != null)
|
||||||
return new DictionaryEnumerator(_genericDictionary.GetEnumerator());
|
return new DictionaryEnumerator<TKey, TValue>(_genericDictionary.GetEnumerator());
|
||||||
else
|
else
|
||||||
return _dictionary.GetEnumerator();
|
return _dictionary.GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ using System.Reflection;
|
|||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using Newtonsoft.Json.Serialization;
|
||||||
|
|
||||||
namespace Newtonsoft.Json.Utilities
|
namespace Newtonsoft.Json.Utilities
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -32,8 +32,6 @@ using System.Globalization;
|
|||||||
|
|
||||||
namespace Newtonsoft.Json.Utilities
|
namespace Newtonsoft.Json.Utilities
|
||||||
{
|
{
|
||||||
internal delegate object MemberHandler<T>(T target, params object[] args);
|
|
||||||
|
|
||||||
internal static class ReflectionUtils
|
internal static class ReflectionUtils
|
||||||
{
|
{
|
||||||
public static Type GetObjectType(object v)
|
public static Type GetObjectType(object v)
|
||||||
|
|||||||
Reference in New Issue
Block a user