Merge branch 'Inverness-feature-iserializable-references'
This commit is contained in:
@@ -33,4 +33,4 @@ using System.Runtime.InteropServices;
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("6.0.0.0")]
|
||||
[assembly: AssemblyVersion("6.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("6.0.6.17905")]
|
||||
[assembly: AssemblyFileVersion("6.0.6.17911")]
|
||||
|
||||
@@ -74,4 +74,4 @@ using System.Security;
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly: AssemblyVersion("6.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("6.0.6.17905")]
|
||||
[assembly: AssemblyFileVersion("6.0.6.17911")]
|
||||
|
||||
@@ -699,6 +699,122 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
Assert.AreEqual(ratio.Denominator, ratio2.Denominator);
|
||||
Assert.AreEqual(ratio.Numerator, ratio2.Numerator);
|
||||
}
|
||||
|
||||
public class PreserveReferencesCallbackTestObject : ISerializable
|
||||
{
|
||||
internal string _stringValue;
|
||||
internal int _intValue;
|
||||
internal PersonReference _person1;
|
||||
internal PersonReference _person2;
|
||||
internal PersonReference _person3;
|
||||
internal PreserveReferencesCallbackTestObject _parent;
|
||||
internal SerializationInfo _serializationInfo;
|
||||
|
||||
public PreserveReferencesCallbackTestObject(string stringValue, int intValue, PersonReference p1, PersonReference p2, PersonReference p3)
|
||||
{
|
||||
_stringValue = stringValue;
|
||||
_intValue = intValue;
|
||||
_person1 = p1;
|
||||
_person2 = p2;
|
||||
_person3 = p3;
|
||||
}
|
||||
|
||||
protected PreserveReferencesCallbackTestObject(SerializationInfo info, StreamingContext context)
|
||||
{
|
||||
_serializationInfo = info;
|
||||
}
|
||||
|
||||
public void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||
{
|
||||
info.AddValue("stringValue", _stringValue);
|
||||
info.AddValue("intValue", _intValue);
|
||||
info.AddValue("person1", _person1, typeof(PersonReference));
|
||||
info.AddValue("person2", _person2, typeof(PersonReference));
|
||||
info.AddValue("person3", _person3, typeof(PersonReference));
|
||||
info.AddValue("parent", _parent, typeof(PreserveReferencesCallbackTestObject));
|
||||
}
|
||||
|
||||
[OnDeserialized]
|
||||
private void OnDeserializedMethod(StreamingContext context)
|
||||
{
|
||||
if (_serializationInfo == null)
|
||||
return;
|
||||
|
||||
_stringValue = _serializationInfo.GetString("stringValue");
|
||||
_intValue = _serializationInfo.GetInt32("intValue");
|
||||
_person1 = (PersonReference)_serializationInfo.GetValue("person1", typeof(PersonReference));
|
||||
_person2 = (PersonReference)_serializationInfo.GetValue("person2", typeof(PersonReference));
|
||||
_person3 = (PersonReference)_serializationInfo.GetValue("person3", typeof(PersonReference));
|
||||
_parent = (PreserveReferencesCallbackTestObject)_serializationInfo.GetValue("parent", typeof(PreserveReferencesCallbackTestObject));
|
||||
|
||||
_serializationInfo = null;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PreserveReferencesCallbackTest()
|
||||
{
|
||||
var p1 = new PersonReference
|
||||
{
|
||||
Name = "John Smith"
|
||||
};
|
||||
var p2 = new PersonReference
|
||||
{
|
||||
Name = "Mary Sue",
|
||||
};
|
||||
|
||||
p1.Spouse = p2;
|
||||
p2.Spouse = p1;
|
||||
|
||||
var obj = new PreserveReferencesCallbackTestObject("string!", 42, p1, p2, p1);
|
||||
obj._parent = obj;
|
||||
|
||||
var settings = new JsonSerializerSettings
|
||||
{
|
||||
PreserveReferencesHandling = PreserveReferencesHandling.All,
|
||||
Formatting = Formatting.Indented
|
||||
};
|
||||
|
||||
string json = JsonConvert.SerializeObject(obj, settings);
|
||||
|
||||
StringAssert.AreEqual(json, @"{
|
||||
""$id"": ""1"",
|
||||
""stringValue"": ""string!"",
|
||||
""intValue"": 42,
|
||||
""person1"": {
|
||||
""$id"": ""2"",
|
||||
""Name"": ""John Smith"",
|
||||
""Spouse"": {
|
||||
""$id"": ""3"",
|
||||
""Name"": ""Mary Sue"",
|
||||
""Spouse"": {
|
||||
""$ref"": ""2""
|
||||
}
|
||||
}
|
||||
},
|
||||
""person2"": {
|
||||
""$ref"": ""3""
|
||||
},
|
||||
""person3"": {
|
||||
""$ref"": ""2""
|
||||
},
|
||||
""parent"": {
|
||||
""$ref"": ""1""
|
||||
}
|
||||
}");
|
||||
|
||||
PreserveReferencesCallbackTestObject obj2 = JsonConvert.DeserializeObject<PreserveReferencesCallbackTestObject>(json);
|
||||
|
||||
Assert.AreEqual(obj._stringValue, obj2._stringValue);
|
||||
Assert.AreEqual(obj._intValue, obj2._intValue);
|
||||
Assert.AreEqual(obj._person1.Name, obj2._person1.Name);
|
||||
Assert.AreEqual(obj._person2.Name, obj2._person2.Name);
|
||||
Assert.AreEqual(obj._person3.Name, obj2._person3.Name);
|
||||
Assert.AreEqual(obj2._person1, obj2._person3);
|
||||
Assert.AreEqual(obj2._person1.Spouse, obj2._person2);
|
||||
Assert.AreEqual(obj2._person2.Spouse, obj2._person1);
|
||||
Assert.AreEqual(obj2._parent, obj2);
|
||||
}
|
||||
#endif
|
||||
|
||||
[Test]
|
||||
@@ -3935,9 +4051,9 @@ Path '', line 1, position 1.");
|
||||
JsonTypeReflector.SetFullyTrusted(false);
|
||||
|
||||
JsonConvert.DeserializeObject<ISerializableTestObject>("{booleanValue:true}");
|
||||
}, @"Type 'Newtonsoft.Json.Tests.Serialization.JsonSerializerTest+ISerializableTestObject' implements ISerializable but cannot be deserialized using the ISerializable interface because the current application is not fully trusted and ISerializable can expose secure data.
|
||||
To fix this error either change the environment to be fully trusted, change the application to not deserialize the type, add JsonObjectAttribute to the type or change the JsonSerializer setting ContractResolver to use a new DefaultContractResolver with IgnoreSerializableInterface set to true.
|
||||
Path 'booleanValue', line 1, position 14.");
|
||||
}, @"Type 'Newtonsoft.Json.Tests.Serialization.JsonSerializerTest+ISerializableTestObject' implements ISerializable but cannot be deserialized using the ISerializable interface because the current application is not fully trusted and ISerializable can expose secure data." + Environment.NewLine +
|
||||
@"To fix this error either change the environment to be fully trusted, change the application to not deserialize the type, add JsonObjectAttribute to the type or change the JsonSerializer setting ContractResolver to use a new DefaultContractResolver with IgnoreSerializableInterface set to true." + Environment.NewLine +
|
||||
@"Path 'booleanValue', line 1, position 14.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -3956,8 +4072,9 @@ Path 'booleanValue', line 1, position 14.");
|
||||
ISerializableTestObject value = new ISerializableTestObject("string!", 0, default(DateTimeOffset), null);
|
||||
|
||||
JsonConvert.SerializeObject(value);
|
||||
}, @"Type 'Newtonsoft.Json.Tests.Serialization.JsonSerializerTest+ISerializableTestObject' implements ISerializable but cannot be serialized using the ISerializable interface because the current application is not fully trusted and ISerializable can expose secure data.
|
||||
To fix this error either change the environment to be fully trusted, change the application to not deserialize the type, add JsonObjectAttribute to the type or change the JsonSerializer setting ContractResolver to use a new DefaultContractResolver with IgnoreSerializableInterface set to true. Path ''.");
|
||||
}, @"Type 'Newtonsoft.Json.Tests.Serialization.JsonSerializerTest+ISerializableTestObject' implements ISerializable but cannot be serialized using the ISerializable interface because the current application is not fully trusted and ISerializable can expose secure data." + Environment.NewLine +
|
||||
@"To fix this error either change the environment to be fully trusted, change the application to not deserialize the type, add JsonObjectAttribute to the type or change the JsonSerializer setting ContractResolver to use a new DefaultContractResolver with IgnoreSerializableInterface set to true." + Environment.NewLine +
|
||||
@"Path ''.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -91,5 +91,5 @@ using System.Security;
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly: AssemblyVersion("6.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("6.0.6.17905")]
|
||||
[assembly: AssemblyFileVersion("6.0.6.17911")]
|
||||
[assembly: CLSCompliant(true)]
|
||||
|
||||
@@ -34,13 +34,18 @@ namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
internal class JsonFormatterConverter : IFormatterConverter
|
||||
{
|
||||
private readonly JsonSerializer _serializer;
|
||||
private readonly JsonSerializerInternalReader _reader;
|
||||
private readonly JsonISerializableContract _contract;
|
||||
private readonly JsonProperty _member;
|
||||
|
||||
public JsonFormatterConverter(JsonSerializer serializer)
|
||||
public JsonFormatterConverter(JsonSerializerInternalReader reader, JsonISerializableContract contract, JsonProperty member)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(serializer, "serializer");
|
||||
ValidationUtils.ArgumentNotNull(reader, "serializer");
|
||||
ValidationUtils.ArgumentNotNull(contract, "contract");
|
||||
|
||||
_serializer = serializer;
|
||||
_reader = reader;
|
||||
_contract = contract;
|
||||
_member = member;
|
||||
}
|
||||
|
||||
private T GetTokenValue<T>(object value)
|
||||
@@ -59,7 +64,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
if (token == null)
|
||||
throw new ArgumentException("Value is not a JToken.", "value");
|
||||
|
||||
return _serializer.Deserialize(token.CreateReader(), type);
|
||||
return _reader.CreateISerializableItem(token, type, _contract, _member);
|
||||
}
|
||||
|
||||
public object Convert(object value, TypeCode typeCode)
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#if !(NETFX_CORE || PORTABLE || PORTABLE40)
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
@@ -50,5 +51,4 @@ namespace Newtonsoft.Json.Serialization
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -58,9 +58,6 @@ namespace Newtonsoft.Json.Serialization
|
||||
}
|
||||
|
||||
private JsonSerializerProxy _internalSerializer;
|
||||
#if !(NETFX_CORE || PORTABLE40 || PORTABLE)
|
||||
private JsonFormatterConverter _formatterConverter;
|
||||
#endif
|
||||
|
||||
public JsonSerializerInternalReader(JsonSerializer serializer)
|
||||
: base(serializer)
|
||||
@@ -193,16 +190,6 @@ namespace Newtonsoft.Json.Serialization
|
||||
return _internalSerializer;
|
||||
}
|
||||
|
||||
#if !(NETFX_CORE || PORTABLE40 || PORTABLE)
|
||||
private JsonFormatterConverter GetFormatterConverter()
|
||||
{
|
||||
if (_formatterConverter == null)
|
||||
_formatterConverter = new JsonFormatterConverter(GetInternalSerializer());
|
||||
|
||||
return _formatterConverter;
|
||||
}
|
||||
#endif
|
||||
|
||||
private JToken CreateJToken(JsonReader reader, JsonContract contract)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(reader, "reader");
|
||||
@@ -1468,7 +1455,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
|
||||
TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Deserializing {0} using ISerializable constructor.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)), null);
|
||||
|
||||
SerializationInfo serializationInfo = new SerializationInfo(contract.UnderlyingType, GetFormatterConverter());
|
||||
SerializationInfo serializationInfo = new SerializationInfo(contract.UnderlyingType, new JsonFormatterConverter(this, contract, member));
|
||||
|
||||
bool finished = false;
|
||||
do
|
||||
@@ -1479,17 +1466,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
string memberName = reader.Value.ToString();
|
||||
if (!reader.Read())
|
||||
throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
|
||||
|
||||
if (reader.TokenType == JsonToken.StartObject)
|
||||
{
|
||||
// this will read any potential type names embedded in json
|
||||
object o = CreateObject(reader, null, null, null, contract, member, null);
|
||||
serializationInfo.AddValue(memberName, o);
|
||||
}
|
||||
else
|
||||
{
|
||||
serializationInfo.AddValue(memberName, JToken.ReadFrom(reader));
|
||||
}
|
||||
serializationInfo.AddValue(memberName, JToken.ReadFrom(reader));
|
||||
break;
|
||||
case JsonToken.Comment:
|
||||
break;
|
||||
@@ -1518,6 +1495,23 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
return createdObject;
|
||||
}
|
||||
|
||||
internal object CreateISerializableItem(JToken token, Type type, JsonISerializableContract contract, JsonProperty member)
|
||||
{
|
||||
JsonContract itemContract = GetContractSafe(type);
|
||||
JsonConverter itemConverter = GetConverter(itemContract, null, contract, member);
|
||||
|
||||
JsonReader tokenReader = token.CreateReader();
|
||||
CheckedRead(tokenReader); // Move to first token
|
||||
|
||||
object result;
|
||||
if (itemConverter != null && itemConverter.CanRead)
|
||||
result = DeserializeConvertable(itemConverter, tokenReader, type, null);
|
||||
else
|
||||
result = CreateValueInternal(tokenReader, type, itemContract, null, contract, member, null);
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !(NET35 || NET20 || PORTABLE40)
|
||||
|
||||
@@ -752,7 +752,12 @@ namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
JsonContract valueContract = GetContractSafe(serializationEntry.Value);
|
||||
|
||||
if (CheckForCircularReference(writer, serializationEntry.Value, null, valueContract, contract, member))
|
||||
if (ShouldWriteReference(serializationEntry.Value, null, valueContract, contract, member))
|
||||
{
|
||||
writer.WritePropertyName(serializationEntry.Name);
|
||||
WriteReference(writer, serializationEntry.Value);
|
||||
}
|
||||
else if (CheckForCircularReference(writer, serializationEntry.Value, null, valueContract, contract, member))
|
||||
{
|
||||
writer.WritePropertyName(serializationEntry.Name);
|
||||
SerializeValue(writer, serializationEntry.Value, valueContract, null, contract, member);
|
||||
|
||||
Reference in New Issue
Block a user