-Properties on dynamic objects with JsonProperty/DataMember will now be included in serialized JSON
-Serialize and deserialize multidimensional arrays
This commit is contained in:
@@ -72,5 +72,5 @@ using System.Security;
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("4.5.0.0")]
|
||||
#if !PocketPC
|
||||
[assembly: AssemblyFileVersion("4.5.7.15127")]
|
||||
[assembly: AssemblyFileVersion("4.5.8.15131")]
|
||||
#endif
|
||||
|
||||
@@ -192,6 +192,7 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
});
|
||||
|
||||
Assert.AreEqual(@"{
|
||||
""explicit"": false,
|
||||
""text"": ""Text!"",
|
||||
""integer"": 2147483647,
|
||||
""int"": 0,
|
||||
|
||||
@@ -30,6 +30,7 @@ using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Serialization.Formatters;
|
||||
using System.Text;
|
||||
@@ -60,6 +61,8 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
private readonly Dictionary<string, object> _members;
|
||||
|
||||
public int Int;
|
||||
[JsonProperty]
|
||||
public bool Explicit;
|
||||
public DynamicChildObject ChildObject { get; set; }
|
||||
|
||||
internal Dictionary<string, object> Members
|
||||
@@ -122,6 +125,7 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
public void SerializeDynamicObject()
|
||||
{
|
||||
TestDynamicObject dynamicObject = new TestDynamicObject();
|
||||
dynamicObject.Explicit = true;
|
||||
|
||||
dynamic d = dynamicObject;
|
||||
d.Int = 1;
|
||||
@@ -144,6 +148,7 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
|
||||
string json = JsonConvert.SerializeObject(dynamicObject, Formatting.Indented);
|
||||
Assert.AreEqual(@"{
|
||||
""Explicit"": true,
|
||||
""Decimal"": 99.9,
|
||||
""Int"": 1,
|
||||
""ChildObject"": {
|
||||
@@ -153,6 +158,8 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
}", json);
|
||||
|
||||
TestDynamicObject newDynamicObject = JsonConvert.DeserializeObject<TestDynamicObject>(json);
|
||||
Assert.AreEqual(true, newDynamicObject.Explicit);
|
||||
|
||||
d = newDynamicObject;
|
||||
|
||||
Assert.AreEqual(99.9, d.Decimal);
|
||||
|
||||
@@ -6629,6 +6629,186 @@ Parameter name: value",
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[Test]
|
||||
public void SerializeArray2D()
|
||||
{
|
||||
Array2D aa = new Array2D();
|
||||
aa.Before = "Before!";
|
||||
aa.After = "After!";
|
||||
aa.Coordinates = new[,] { { 1, 1 }, { 1, 2 }, { 2, 1 }, { 2, 2 } };
|
||||
|
||||
string json = JsonConvert.SerializeObject(aa);
|
||||
|
||||
Assert.AreEqual(@"{""Before"":""Before!"",""Coordinates"":[[1,1],[1,2],[2,1],[2,2]],""After"":""After!""}", json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeArray3D()
|
||||
{
|
||||
Array3D aa = new Array3D();
|
||||
aa.Before = "Before!";
|
||||
aa.After = "After!";
|
||||
aa.Coordinates = new[, ,] { { { 1, 1, 1 }, { 1, 1, 2 } }, { { 1, 2, 1 }, { 1, 2, 2 } }, { { 2, 1, 1 }, { 2, 1, 2 } }, { { 2, 2, 1 }, { 2, 2, 2 } } };
|
||||
|
||||
string json = JsonConvert.SerializeObject(aa);
|
||||
|
||||
Assert.AreEqual(@"{""Before"":""Before!"",""Coordinates"":[[[1,1,1],[1,1,2]],[[1,2,1],[1,2,2]],[[2,1,1],[2,1,2]],[[2,2,1],[2,2,2]]],""After"":""After!""}", json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeArray2D()
|
||||
{
|
||||
string json = @"{""Before"":""Before!"",""Coordinates"":[[1,1],[1,2],[2,1],[2,2]],""After"":""After!""}";
|
||||
|
||||
Array2D aa = JsonConvert.DeserializeObject<Array2D>(json);
|
||||
|
||||
Assert.AreEqual("Before!", aa.Before);
|
||||
Assert.AreEqual("After!", aa.After);
|
||||
Assert.AreEqual(4, aa.Coordinates.GetLength(0));
|
||||
Assert.AreEqual(2, aa.Coordinates.GetLength(1));
|
||||
Assert.AreEqual(1, aa.Coordinates[0, 0]);
|
||||
Assert.AreEqual(2, aa.Coordinates[1, 1]);
|
||||
|
||||
string after = JsonConvert.SerializeObject(aa);
|
||||
|
||||
Assert.AreEqual(json, after);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeArray2D_WithTooManyItems()
|
||||
{
|
||||
string json = @"{""Before"":""Before!"",""Coordinates"":[[1,1],[1,2,3],[2,1],[2,2]],""After"":""After!""}";
|
||||
|
||||
ExceptionAssert.Throws<Exception>(
|
||||
"Cannot deserialize non-cubical array as multidimensional array.",
|
||||
() => JsonConvert.DeserializeObject<Array2D>(json));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeArray2D_WithTooFewItems()
|
||||
{
|
||||
string json = @"{""Before"":""Before!"",""Coordinates"":[[1,1],[1],[2,1],[2,2]],""After"":""After!""}";
|
||||
|
||||
ExceptionAssert.Throws<Exception>(
|
||||
"Cannot deserialize non-cubical array as multidimensional array.",
|
||||
() => JsonConvert.DeserializeObject<Array2D>(json));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeArray3D()
|
||||
{
|
||||
string json = @"{""Before"":""Before!"",""Coordinates"":[[[1,1,1],[1,1,2]],[[1,2,1],[1,2,2]],[[2,1,1],[2,1,2]],[[2,2,1],[2,2,2]]],""After"":""After!""}";
|
||||
|
||||
Array3D aa = JsonConvert.DeserializeObject<Array3D>(json);
|
||||
|
||||
Assert.AreEqual("Before!", aa.Before);
|
||||
Assert.AreEqual("After!", aa.After);
|
||||
Assert.AreEqual(4, aa.Coordinates.GetLength(0));
|
||||
Assert.AreEqual(2, aa.Coordinates.GetLength(1));
|
||||
Assert.AreEqual(3, aa.Coordinates.GetLength(2));
|
||||
Assert.AreEqual(1, aa.Coordinates[0, 0, 0]);
|
||||
Assert.AreEqual(2, aa.Coordinates[1, 1, 1]);
|
||||
|
||||
string after = JsonConvert.SerializeObject(aa);
|
||||
|
||||
Assert.AreEqual(json, after);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeArray3D_WithTooManyItems()
|
||||
{
|
||||
string json = @"{""Before"":""Before!"",""Coordinates"":[[[1,1,1],[1,1,2,1]],[[1,2,1],[1,2,2]],[[2,1,1],[2,1,2]],[[2,2,1],[2,2,2]]],""After"":""After!""}";
|
||||
|
||||
ExceptionAssert.Throws<Exception>(
|
||||
"Cannot deserialize non-cubical array as multidimensional array.",
|
||||
() => JsonConvert.DeserializeObject<Array3D>(json));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeArray3D_WithBadItems()
|
||||
{
|
||||
string json = @"{""Before"":""Before!"",""Coordinates"":[[[1,1,1],[1,1,2]],[[1,2,1],[1,2,2]],[[2,1,1],[2,1,2]],[[2,2,1],{}]],""After"":""After!""}";
|
||||
|
||||
ExceptionAssert.Throws<JsonSerializationException>(
|
||||
"Unexpected token when deserializing multidimensional array: StartObject. Path 'Coordinates[3][1]', line 1, position 99.",
|
||||
() => JsonConvert.DeserializeObject<Array3D>(json));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeArray3D_WithTooFewItems()
|
||||
{
|
||||
string json = @"{""Before"":""Before!"",""Coordinates"":[[[1,1,1],[1,1]],[[1,2,1],[1,2,2]],[[2,1,1],[2,1,2]],[[2,2,1],[2,2,2]]],""After"":""After!""}";
|
||||
|
||||
ExceptionAssert.Throws<Exception>(
|
||||
"Cannot deserialize non-cubical array as multidimensional array.",
|
||||
() => JsonConvert.DeserializeObject<Array3D>(json));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeEmpty3DArray()
|
||||
{
|
||||
Array3D aa = new Array3D();
|
||||
aa.Before = "Before!";
|
||||
aa.After = "After!";
|
||||
aa.Coordinates = new int[0, 0, 0];
|
||||
|
||||
string json = JsonConvert.SerializeObject(aa);
|
||||
|
||||
Assert.AreEqual(@"{""Before"":""Before!"",""Coordinates"":[],""After"":""After!""}", json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeEmpty3DArray()
|
||||
{
|
||||
string json = @"{""Before"":""Before!"",""Coordinates"":[],""After"":""After!""}";
|
||||
|
||||
Array3D aa = JsonConvert.DeserializeObject<Array3D>(json);
|
||||
|
||||
Assert.AreEqual("Before!", aa.Before);
|
||||
Assert.AreEqual("After!", aa.After);
|
||||
Assert.AreEqual(0, aa.Coordinates.GetLength(0));
|
||||
Assert.AreEqual(0, aa.Coordinates.GetLength(1));
|
||||
Assert.AreEqual(0, aa.Coordinates.GetLength(2));
|
||||
|
||||
string after = JsonConvert.SerializeObject(aa);
|
||||
|
||||
Assert.AreEqual(json, after);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeNull3DArray()
|
||||
{
|
||||
string json = @"{""Before"":""Before!"",""Coordinates"":null,""After"":""After!""}";
|
||||
|
||||
Array3D aa = JsonConvert.DeserializeObject<Array3D>(json);
|
||||
|
||||
Assert.AreEqual("Before!", aa.Before);
|
||||
Assert.AreEqual("After!", aa.After);
|
||||
Assert.AreEqual(null, aa.Coordinates);
|
||||
|
||||
string after = JsonConvert.SerializeObject(aa);
|
||||
|
||||
Assert.AreEqual(json, after);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeSemiEmpty3DArray()
|
||||
{
|
||||
string json = @"{""Before"":""Before!"",""Coordinates"":[[]],""After"":""After!""}";
|
||||
|
||||
Array3D aa = JsonConvert.DeserializeObject<Array3D>(json);
|
||||
|
||||
Assert.AreEqual("Before!", aa.Before);
|
||||
Assert.AreEqual("After!", aa.After);
|
||||
Assert.AreEqual(1, aa.Coordinates.GetLength(0));
|
||||
Assert.AreEqual(0, aa.Coordinates.GetLength(1));
|
||||
Assert.AreEqual(0, aa.Coordinates.GetLength(2));
|
||||
|
||||
string after = JsonConvert.SerializeObject(aa);
|
||||
|
||||
Assert.AreEqual(json, after);
|
||||
}
|
||||
}
|
||||
|
||||
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE)
|
||||
@@ -6939,4 +7119,18 @@ Parameter name: value",
|
||||
public string IgnoreDataMemberAndDataMemberAttribute { get; set; }
|
||||
}
|
||||
#endif
|
||||
|
||||
public class Array2D
|
||||
{
|
||||
public string Before { get; set; }
|
||||
public int[,] Coordinates { get; set; }
|
||||
public string After { get; set; }
|
||||
}
|
||||
|
||||
public class Array3D
|
||||
{
|
||||
public string Before { get; set; }
|
||||
public int[,,] Coordinates { get; set; }
|
||||
public string After { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -91,7 +91,7 @@ using System.Security;
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("4.5.0.0")]
|
||||
#if !PocketPC
|
||||
[assembly: AssemblyFileVersion("4.5.7.15127")]
|
||||
[assembly: AssemblyFileVersion("4.5.8.15131")]
|
||||
#endif
|
||||
|
||||
[assembly: CLSCompliant(true)]
|
||||
|
||||
@@ -457,8 +457,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
property.PropertyType = parameterInfo.ParameterType;
|
||||
|
||||
bool allowNonPublicAccess;
|
||||
bool hasExplicitAttribute;
|
||||
SetPropertySettingsFromAttributes(property, parameterInfo.GetCustomAttributeProvider(), parameterInfo.Name, parameterInfo.Member.DeclaringType, MemberSerialization.OptOut, out allowNonPublicAccess, out hasExplicitAttribute);
|
||||
SetPropertySettingsFromAttributes(property, parameterInfo.GetCustomAttributeProvider(), parameterInfo.Name, parameterInfo.Member.DeclaringType, MemberSerialization.OptOut, out allowNonPublicAccess);
|
||||
|
||||
property.Readable = false;
|
||||
property.Writable = true;
|
||||
@@ -905,13 +904,12 @@ namespace Newtonsoft.Json.Serialization
|
||||
property.ValueProvider = CreateMemberValueProvider(member);
|
||||
|
||||
bool allowNonPublicAccess;
|
||||
bool hasExplicitAttribute;
|
||||
SetPropertySettingsFromAttributes(property, member.GetCustomAttributeProvider(), member.Name, member.DeclaringType, memberSerialization, out allowNonPublicAccess, out hasExplicitAttribute);
|
||||
SetPropertySettingsFromAttributes(property, member.GetCustomAttributeProvider(), member.Name, member.DeclaringType, memberSerialization, out allowNonPublicAccess);
|
||||
|
||||
if (memberSerialization != MemberSerialization.Fields)
|
||||
{
|
||||
property.Readable = ReflectionUtils.CanReadMemberValue(member, allowNonPublicAccess);
|
||||
property.Writable = ReflectionUtils.CanSetMemberValue(member, allowNonPublicAccess, hasExplicitAttribute);
|
||||
property.Writable = ReflectionUtils.CanSetMemberValue(member, allowNonPublicAccess, property.HasMemberAttribute);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -926,10 +924,8 @@ namespace Newtonsoft.Json.Serialization
|
||||
return property;
|
||||
}
|
||||
|
||||
private void SetPropertySettingsFromAttributes(JsonProperty property, ICustomAttributeProvider attributeProvider, string name, Type declaringType, MemberSerialization memberSerialization, out bool allowNonPublicAccess, out bool hasExplicitAttribute)
|
||||
private void SetPropertySettingsFromAttributes(JsonProperty property, ICustomAttributeProvider attributeProvider, string name, Type declaringType, MemberSerialization memberSerialization, out bool allowNonPublicAccess)
|
||||
{
|
||||
hasExplicitAttribute = false;
|
||||
|
||||
#if !PocketPC && !NET20
|
||||
DataContractAttribute dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(declaringType);
|
||||
|
||||
@@ -949,7 +945,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
JsonPropertyAttribute propertyAttribute = JsonTypeReflector.GetAttribute<JsonPropertyAttribute>(attributeProvider);
|
||||
if (propertyAttribute != null)
|
||||
hasExplicitAttribute = true;
|
||||
property.HasMemberAttribute = true;
|
||||
|
||||
string mappedName;
|
||||
if (propertyAttribute != null && propertyAttribute.PropertyName != null)
|
||||
@@ -1039,7 +1035,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
if (dataMemberAttribute != null)
|
||||
{
|
||||
allowNonPublicAccess = true;
|
||||
hasExplicitAttribute = true;
|
||||
property.HasMemberAttribute = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ namespace Newtonsoft.Json.Serialization
|
||||
/// <value>The <see cref="Type"/> of the collection items.</value>
|
||||
public Type CollectionItemType { get; private set; }
|
||||
|
||||
public bool IsMultidimensionalArray { get; private set; }
|
||||
|
||||
private readonly bool _isCollectionItemTypeNullableType;
|
||||
private readonly Type _genericCollectionDefinitionType;
|
||||
private Type _genericWrapperType;
|
||||
@@ -82,6 +84,8 @@ namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
CreatedType = ReflectionUtils.MakeGenericType(typeof(List<>), CollectionItemType);
|
||||
}
|
||||
|
||||
IsMultidimensionalArray = (UnderlyingType.IsArray && UnderlyingType.GetArrayRank() > 1);
|
||||
}
|
||||
|
||||
internal IWrappedCollection CreateWrapper(object list)
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
/// <summary>
|
||||
/// Contract details for a <see cref="Type"/> used by the <see cref="JsonSerializer"/>.
|
||||
/// </summary>
|
||||
public class JsonDynamicContract : JsonContract
|
||||
public class JsonDynamicContract : JsonContainerContract
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the object's properties.
|
||||
|
||||
@@ -107,6 +107,12 @@ namespace Newtonsoft.Json.Serialization
|
||||
/// <value><c>true</c> if writable; otherwise, <c>false</c>.</value>
|
||||
public bool Writable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this <see cref="JsonProperty"/> has a member attribute.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if has a member attribute; otherwise, <c>false</c>.</value>
|
||||
public bool HasMemberAttribute { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default value.
|
||||
/// </summary>
|
||||
|
||||
@@ -28,6 +28,7 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
|
||||
using System.ComponentModel;
|
||||
using System.Dynamic;
|
||||
#endif
|
||||
using System.Globalization;
|
||||
@@ -554,15 +555,26 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
if (contract.OnError != null && isTemporaryListReference)
|
||||
throw JsonSerializationException.Create(reader, "Cannot call OnError on an array or readonly list: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
|
||||
|
||||
PopulateList(arrayContract.CreateWrapper(list), reader, arrayContract, member, id);
|
||||
if (!arrayContract.IsMultidimensionalArray)
|
||||
PopulateList(arrayContract.CreateWrapper(list), reader, arrayContract, member, id);
|
||||
else
|
||||
PopulateMultidimensionalArray(list, reader, arrayContract, member, id);
|
||||
|
||||
// create readonly and fixed sized collections using the temporary list
|
||||
if (isTemporaryListReference)
|
||||
{
|
||||
if (contract.CreatedType.IsArray)
|
||||
list = CollectionUtils.ToArray(((List<object>)list).ToArray(), ReflectionUtils.GetCollectionItemType(contract.CreatedType));
|
||||
if (arrayContract.IsMultidimensionalArray)
|
||||
{
|
||||
list = CollectionUtils.ToMultidimensionalArray(list, ReflectionUtils.GetCollectionItemType(contract.CreatedType), contract.CreatedType.GetArrayRank());
|
||||
}
|
||||
else if (contract.CreatedType.IsArray)
|
||||
{
|
||||
list = CollectionUtils.ToArray(((List<object>) list).ToArray(), ReflectionUtils.GetCollectionItemType(contract.CreatedType));
|
||||
}
|
||||
else if (ReflectionUtils.InheritsGenericDefinition(contract.CreatedType, typeof(ReadOnlyCollection<>)))
|
||||
list = (IList)ReflectionUtils.CreateInstance(contract.CreatedType, list);
|
||||
{
|
||||
list = (IList) ReflectionUtils.CreateInstance(contract.CreatedType, list);
|
||||
}
|
||||
}
|
||||
else if (list is IWrappedCollection)
|
||||
{
|
||||
@@ -851,6 +863,125 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object.");
|
||||
}
|
||||
|
||||
private object PopulateMultidimensionalArray(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, string id)
|
||||
{
|
||||
int rank = contract.UnderlyingType.GetArrayRank();
|
||||
|
||||
if (id != null)
|
||||
Serializer.ReferenceResolver.AddReference(this, id, list);
|
||||
|
||||
contract.InvokeOnDeserializing(list, Serializer.Context);
|
||||
|
||||
int initialDepth = reader.Depth;
|
||||
|
||||
JsonContract collectionItemContract = GetContractSafe(contract.CollectionItemType);
|
||||
JsonConverter collectionItemConverter = GetConverter(collectionItemContract, null, contract, containerProperty);
|
||||
|
||||
int? previousErrorIndex = null;
|
||||
Stack<IList> listStack = new Stack<IList>();
|
||||
listStack.Push(list);
|
||||
IList currentList = list;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (listStack.Count == rank)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (ReadForType(reader, collectionItemContract, collectionItemConverter != null))
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.EndArray:
|
||||
listStack.Pop();
|
||||
currentList = listStack.Peek();
|
||||
break;
|
||||
case JsonToken.Comment:
|
||||
break;
|
||||
default:
|
||||
object value;
|
||||
|
||||
if (collectionItemConverter != null && collectionItemConverter.CanRead)
|
||||
value = collectionItemConverter.ReadJson(reader, contract.CollectionItemType, null, GetInternalSerializer());
|
||||
else
|
||||
value = CreateValueInternal(reader, contract.CollectionItemType, collectionItemContract, null, contract, containerProperty, null);
|
||||
|
||||
currentList.Add(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
JsonPosition errorPosition = reader.GetPosition(initialDepth);
|
||||
|
||||
if (IsErrorHandled(list, contract, errorPosition.Position, reader.Path, ex))
|
||||
{
|
||||
HandleError(reader, true, initialDepth);
|
||||
|
||||
if (previousErrorIndex != null && previousErrorIndex == errorPosition.Position)
|
||||
{
|
||||
// reader index has not moved since previous error handling
|
||||
// break out of reading array to prevent infinite loop
|
||||
throw JsonSerializationException.Create(reader, "Infinite loop detected from error handling.", ex);
|
||||
}
|
||||
else
|
||||
{
|
||||
previousErrorIndex = errorPosition.Position;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (reader.Read())
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.StartArray:
|
||||
IList newList = new List<object>();
|
||||
currentList.Add(newList);
|
||||
listStack.Push(newList);
|
||||
currentList = newList;
|
||||
break;
|
||||
case JsonToken.EndArray:
|
||||
listStack.Pop();
|
||||
|
||||
if (listStack.Count > 0)
|
||||
{
|
||||
currentList = listStack.Peek();
|
||||
}
|
||||
else
|
||||
{
|
||||
contract.InvokeOnDeserialized(list, Serializer.Context);
|
||||
|
||||
return list;
|
||||
}
|
||||
break;
|
||||
case JsonToken.Comment:
|
||||
break;
|
||||
default:
|
||||
throw JsonSerializationException.Create(reader, "Unexpected token when deserializing multidimensional array: " + reader.TokenType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw JsonSerializationException.Create(reader, "Unexpected end when deserializing array.");
|
||||
}
|
||||
|
||||
private object PopulateList(IWrappedCollection wrappedList, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, string id)
|
||||
{
|
||||
object list = wrappedList.UnderlyingCollection;
|
||||
|
||||
@@ -124,7 +124,10 @@ namespace Newtonsoft.Json.Serialization
|
||||
break;
|
||||
case JsonContractType.Array:
|
||||
JsonArrayContract arrayContract = (JsonArrayContract) valueContract;
|
||||
SerializeList(writer, arrayContract.CreateWrapper(value), arrayContract, member, containerContract, containerProperty);
|
||||
if (!arrayContract.IsMultidimensionalArray)
|
||||
SerializeList(writer, arrayContract.CreateWrapper(value), arrayContract, member, containerContract, containerProperty);
|
||||
else
|
||||
SerializeMultidimensionalArray(writer, (Array)value, arrayContract, member, containerContract, containerProperty);
|
||||
break;
|
||||
case JsonContractType.Primitive:
|
||||
SerializePrimitive(writer, value, (JsonPrimitiveContract)valueContract, member, containerContract, containerProperty);
|
||||
@@ -322,39 +325,14 @@ namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!property.Ignored && property.Readable && ShouldSerialize(property, value) && IsSpecified(property, value))
|
||||
{
|
||||
if (property.PropertyContract == null)
|
||||
property.PropertyContract = Serializer.ContractResolver.ResolveContract(property.PropertyType);
|
||||
object memberValue;
|
||||
JsonContract memberContract;
|
||||
|
||||
object memberValue = property.ValueProvider.GetValue(value);
|
||||
JsonContract memberContract = (property.PropertyContract.UnderlyingType.IsSealed()) ? property.PropertyContract : GetContractSafe(memberValue);
|
||||
if (!CalculatePropertyValues(writer, value, contract, member, property, out memberContract, out memberValue))
|
||||
continue;
|
||||
|
||||
if (ShouldWriteProperty(memberValue, property))
|
||||
{
|
||||
string propertyName = property.PropertyName;
|
||||
|
||||
if (ShouldWriteReference(memberValue, property, memberContract, contract, member))
|
||||
{
|
||||
writer.WritePropertyName(propertyName);
|
||||
WriteReference(writer, memberValue);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!CheckForCircularReference(writer, memberValue, property, memberContract, contract, member))
|
||||
continue;
|
||||
|
||||
if (memberValue == null)
|
||||
{
|
||||
Required resolvedRequired = property._required ?? contract.ItemRequired ?? Required.Default;
|
||||
if (resolvedRequired == Required.Always)
|
||||
throw JsonSerializationException.Create(null, writer.ContainerPath, "Cannot write a null value for property '{0}'. Property requires a value.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName), null);
|
||||
}
|
||||
|
||||
writer.WritePropertyName(propertyName);
|
||||
SerializeValue(writer, memberValue, memberContract, property, contract, member);
|
||||
}
|
||||
}
|
||||
writer.WritePropertyName(property.PropertyName);
|
||||
SerializeValue(writer, memberValue, memberContract, property, contract, member);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -372,6 +350,45 @@ namespace Newtonsoft.Json.Serialization
|
||||
contract.InvokeOnSerialized(value, Serializer.Context);
|
||||
}
|
||||
|
||||
private bool CalculatePropertyValues(JsonWriter writer, object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, out JsonContract memberContract, out object memberValue)
|
||||
{
|
||||
if (!property.Ignored && property.Readable && ShouldSerialize(property, value) && IsSpecified(property, value))
|
||||
{
|
||||
if (property.PropertyContract == null)
|
||||
property.PropertyContract = Serializer.ContractResolver.ResolveContract(property.PropertyType);
|
||||
|
||||
memberValue = property.ValueProvider.GetValue(value);
|
||||
memberContract = (property.PropertyContract.UnderlyingType.IsSealed()) ? property.PropertyContract : GetContractSafe(memberValue);
|
||||
|
||||
if (ShouldWriteProperty(memberValue, property))
|
||||
{
|
||||
if (ShouldWriteReference(memberValue, property, memberContract, contract, member))
|
||||
{
|
||||
writer.WritePropertyName(property.PropertyName);
|
||||
WriteReference(writer, memberValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CheckForCircularReference(writer, memberValue, property, memberContract, contract, member))
|
||||
return false;
|
||||
|
||||
if (memberValue == null)
|
||||
{
|
||||
JsonObjectContract objectContract = contract as JsonObjectContract;
|
||||
Required resolvedRequired = property._required ?? ((objectContract != null) ? objectContract.ItemRequired : null) ?? Required.Default;
|
||||
if (resolvedRequired == Required.Always)
|
||||
throw JsonSerializationException.Create(null, writer.ContainerPath, "Cannot write a null value for property '{0}'. Property requires a value.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName), null);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
memberContract = null;
|
||||
memberValue = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void WriteObjectStart(JsonWriter writer, object value, JsonContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
@@ -434,7 +451,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
_serializeStack.Add(values.UnderlyingCollection);
|
||||
|
||||
bool hasWrittenMetadataObject = WriteStartArray(writer, values, contract, member, collectionContract, containerProperty);
|
||||
bool hasWrittenMetadataObject = WriteStartArray(writer, values.UnderlyingCollection, contract, member, collectionContract, containerProperty);
|
||||
|
||||
writer.WriteStartArray();
|
||||
|
||||
@@ -483,7 +500,78 @@ namespace Newtonsoft.Json.Serialization
|
||||
contract.InvokeOnSerialized(values.UnderlyingCollection, Serializer.Context);
|
||||
}
|
||||
|
||||
private bool WriteStartArray(JsonWriter writer, IWrappedCollection values, JsonArrayContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
|
||||
private void SerializeMultidimensionalArray(JsonWriter writer, Array values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
|
||||
{
|
||||
contract.InvokeOnSerializing(values, Serializer.Context);
|
||||
|
||||
_serializeStack.Add(values);
|
||||
|
||||
bool hasWrittenMetadataObject = WriteStartArray(writer, values, contract, member, collectionContract, containerProperty);
|
||||
|
||||
SerializeMultidimensionalArray(writer, values, contract, member, writer.Top, new int[0]);
|
||||
|
||||
if (hasWrittenMetadataObject)
|
||||
writer.WriteEndObject();
|
||||
|
||||
_serializeStack.RemoveAt(_serializeStack.Count - 1);
|
||||
|
||||
contract.InvokeOnSerialized(values, Serializer.Context);
|
||||
}
|
||||
|
||||
private void SerializeMultidimensionalArray(JsonWriter writer, Array values, JsonArrayContract contract, JsonProperty member, int initialDepth, int[] indices)
|
||||
{
|
||||
int dimension = indices.Length;
|
||||
int[] newIndices = new int[dimension + 1];
|
||||
for (int i = 0; i < dimension; i++)
|
||||
{
|
||||
newIndices[i] = indices[i];
|
||||
}
|
||||
|
||||
writer.WriteStartArray();
|
||||
|
||||
for (int i = 0; i < values.GetLength(dimension); i++)
|
||||
{
|
||||
newIndices[dimension] = i;
|
||||
bool isTopLevel = (newIndices.Length == values.Rank);
|
||||
|
||||
if (isTopLevel)
|
||||
{
|
||||
object value = values.GetValue(newIndices);
|
||||
|
||||
try
|
||||
{
|
||||
JsonContract valueContract = contract.FinalItemContract ?? GetContractSafe(values);
|
||||
|
||||
if (ShouldWriteReference(value, null, valueContract, contract, member))
|
||||
{
|
||||
WriteReference(writer, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CheckForCircularReference(writer, value, null, valueContract, contract, member))
|
||||
{
|
||||
SerializeValue(writer, value, valueContract, null, contract, member);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (IsErrorHandled(values, contract, i, writer.ContainerPath, ex))
|
||||
HandleError(writer, initialDepth);
|
||||
else
|
||||
throw;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SerializeMultidimensionalArray(writer, values, contract, member, initialDepth + 1, newIndices);
|
||||
}
|
||||
}
|
||||
|
||||
writer.WriteEndArray();
|
||||
}
|
||||
|
||||
private bool WriteStartArray(JsonWriter writer, object values, JsonArrayContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
|
||||
{
|
||||
bool isReference = ResolveIsReference(contract, member, containerContract, containerProperty) ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Arrays);
|
||||
bool includeTypeDetails = ShouldWriteType(TypeNameHandling.Arrays, contract, member, containerContract, containerProperty);
|
||||
@@ -496,11 +584,11 @@ namespace Newtonsoft.Json.Serialization
|
||||
if (isReference)
|
||||
{
|
||||
writer.WritePropertyName(JsonTypeReflector.IdPropertyName);
|
||||
writer.WriteValue(Serializer.ReferenceResolver.GetReference(this, values.UnderlyingCollection));
|
||||
writer.WriteValue(Serializer.ReferenceResolver.GetReference(this, values));
|
||||
}
|
||||
if (includeTypeDetails)
|
||||
{
|
||||
WriteTypeProperty(writer, values.UnderlyingCollection.GetType());
|
||||
WriteTypeProperty(writer, values.GetType());
|
||||
}
|
||||
writer.WritePropertyName(JsonTypeReflector.ArrayValuesPropertyName);
|
||||
}
|
||||
@@ -552,17 +640,55 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
|
||||
WriteObjectStart(writer, value, contract, member, collectionContract, containerProperty);
|
||||
|
||||
int initialDepth = writer.Top;
|
||||
|
||||
foreach (JsonProperty property in contract.Properties)
|
||||
{
|
||||
// only write non-dynamic properties that have an explicit attribute
|
||||
if (property.HasMemberAttribute)
|
||||
{
|
||||
try
|
||||
{
|
||||
object memberValue;
|
||||
JsonContract memberContract;
|
||||
|
||||
if (!CalculatePropertyValues(writer, value, contract, member, property, out memberContract, out memberValue))
|
||||
continue;
|
||||
|
||||
writer.WritePropertyName(property.PropertyName);
|
||||
SerializeValue(writer, memberValue, memberContract, property, contract, member);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (IsErrorHandled(value, contract, property.PropertyName, writer.ContainerPath, ex))
|
||||
HandleError(writer, initialDepth);
|
||||
else
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string memberName in value.GetDynamicMemberNames())
|
||||
{
|
||||
object memberValue;
|
||||
if (DynamicUtils.TryGetMember(value, memberName, out memberValue))
|
||||
if (value.TryGetMember(memberName, out memberValue))
|
||||
{
|
||||
string resolvedPropertyName = (contract.PropertyNameResolver != null)
|
||||
? contract.PropertyNameResolver(memberName)
|
||||
: memberName;
|
||||
try
|
||||
{
|
||||
string resolvedPropertyName = (contract.PropertyNameResolver != null)
|
||||
? contract.PropertyNameResolver(memberName)
|
||||
: memberName;
|
||||
|
||||
writer.WritePropertyName(resolvedPropertyName);
|
||||
SerializeValue(writer, memberValue, GetContractSafe(memberValue), null, null, member);
|
||||
writer.WritePropertyName(resolvedPropertyName);
|
||||
SerializeValue(writer, memberValue, GetContractSafe(memberValue), null, null, member);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (IsErrorHandled(value, contract, memberName, writer.ContainerPath, ex))
|
||||
HandleError(writer, initialDepth);
|
||||
else
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -326,5 +326,83 @@ namespace Newtonsoft.Json.Utilities
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static IList<int> GetDimensions(IList values)
|
||||
{
|
||||
IList<int> dimensions = new List<int>();
|
||||
|
||||
IList currentArray = values;
|
||||
while (true)
|
||||
{
|
||||
dimensions.Add(currentArray.Count);
|
||||
if (currentArray.Count == 0)
|
||||
break;
|
||||
|
||||
object v = currentArray[0];
|
||||
if (v is IList)
|
||||
currentArray = (IList)v;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
private static void CopyFromJaggedToMultidimensionalArray(IList values, Array multidimensionalArray, int[] indices)
|
||||
{
|
||||
int dimension = indices.Length;
|
||||
if (dimension == multidimensionalArray.Rank)
|
||||
{
|
||||
multidimensionalArray.SetValue(JaggedArrayGetValue(values, indices), indices);
|
||||
return;
|
||||
}
|
||||
|
||||
int dimensionLength = multidimensionalArray.GetLength(dimension);
|
||||
IList list = (IList)JaggedArrayGetValue(values, indices);
|
||||
int currentValuesLength = list.Count;
|
||||
if (currentValuesLength != dimensionLength)
|
||||
throw new Exception("Cannot deserialize non-cubical array as multidimensional array.");
|
||||
|
||||
int[] newIndices = new int[dimension + 1];
|
||||
for (int i = 0; i < dimension; i++)
|
||||
{
|
||||
newIndices[i] = indices[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < multidimensionalArray.GetLength(dimension); i++)
|
||||
{
|
||||
newIndices[dimension] = i;
|
||||
CopyFromJaggedToMultidimensionalArray(values, multidimensionalArray, newIndices);
|
||||
}
|
||||
}
|
||||
|
||||
private static object JaggedArrayGetValue(IList values, int[] indices)
|
||||
{
|
||||
IList currentList = values;
|
||||
for (int i = 0; i < indices.Length; i++)
|
||||
{
|
||||
int index = indices[i];
|
||||
if (i == indices.Length - 1)
|
||||
return currentList[index];
|
||||
else
|
||||
currentList = (IList)currentList[index];
|
||||
}
|
||||
return currentList;
|
||||
}
|
||||
|
||||
public static Array ToMultidimensionalArray(IList values, Type type, int rank)
|
||||
{
|
||||
IList<int> dimensions = GetDimensions(values);
|
||||
|
||||
while (dimensions.Count < rank)
|
||||
{
|
||||
dimensions.Add(0);
|
||||
}
|
||||
|
||||
Array multidimensionalArray = Array.CreateInstance(type, dimensions.ToArray());
|
||||
CopyFromJaggedToMultidimensionalArray(values, multidimensionalArray, new int[0]);
|
||||
|
||||
return multidimensionalArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user