-Fixed type name handling when a property already has a base type assigned

This commit is contained in:
James Newton-King
2014-04-26 15:16:47 +12:00
parent aa76b5aecb
commit b40d705644
2 changed files with 71 additions and 5 deletions
@@ -1740,6 +1740,34 @@ namespace Newtonsoft.Json.Tests.Serialization
}
}
}
#if !NET20
[Test]
public void ExistingBaseValue()
{
string json = @"{
""itemIdentifier"": {
""$type"": ""Newtonsoft.Json.Tests.Serialization.ReportItemKeys, Newtonsoft.Json.Tests"",
""dataType"": 0,
""wantedUnitID"": 1,
""application"": 3,
""id"": 101,
""name"": ""Machine""
},
""isBusinessEntity"": false,
""isKeyItem"": true,
""summarizeOnThisItem"": false
}";
GroupingInfo g = JsonConvert.DeserializeObject<GroupingInfo>(json, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects
});
ReportItemKeys item = (ReportItemKeys)g.ItemIdentifier;
Assert.AreEqual(1, item.WantedUnitID);
}
#endif
}
#if !NETFX_CORE
@@ -1941,6 +1969,42 @@ namespace Newtonsoft.Json.Tests.Serialization
public string String { get; set; }
public int Integer { get; set; }
}
#if !NET20
[DataContract]
public class GroupingInfo
{
[DataMember]
public ApplicationItemKeys ItemIdentifier { get; set; }
public GroupingInfo()
{
ItemIdentifier = new ApplicationItemKeys();
}
}
[DataContract]
public class ApplicationItemKeys
{
[DataMember]
public int ID { get; set; }
[DataMember]
public string Name { get; set; }
}
[DataContract]
public class ReportItemKeys : ApplicationItemKeys
{
protected ulong _wantedUnit;
[DataMember]
public ulong WantedUnitID
{
get { return _wantedUnit; }
set { _wantedUnit = value; }
}
}
#endif
}
#endif
@@ -374,6 +374,7 @@ namespace Newtonsoft.Json.Serialization
{
string id;
object newValue;
Type resolvedObjectType = objectType;
if (Serializer.SpecialPropertyHandling == SpecialPropertyHandling.ReadAhead)
{
@@ -389,13 +390,13 @@ namespace Newtonsoft.Json.Serialization
reader = tokenReader;
}
if (ReadSpecialPropertiesToken(tokenReader, ref objectType, ref contract, member, containerContract, containerMember, existingValue, out newValue, out id))
if (ReadSpecialPropertiesToken(tokenReader, ref resolvedObjectType, ref contract, member, containerContract, containerMember, existingValue, out newValue, out id))
return newValue;
}
else
{
CheckedRead(reader);
if (ReadSpecialProperties(reader, ref objectType, ref contract, member, containerContract, containerMember, existingValue, out newValue, out id))
if (ReadSpecialProperties(reader, ref resolvedObjectType, ref contract, member, containerContract, containerMember, existingValue, out newValue, out id))
return newValue;
}
@@ -409,7 +410,8 @@ namespace Newtonsoft.Json.Serialization
bool createdFromNonDefaultConstructor = false;
JsonObjectContract objectContract = (JsonObjectContract)contract;
object targetObject;
if (existingValue != null)
// check that if type name handling is being used that the existing value is compatible with the specified type
if (existingValue != null && (resolvedObjectType == objectType || resolvedObjectType.IsInstanceOfType(existingValue)))
targetObject = existingValue;
else
targetObject = CreateNewObject(reader, objectContract, member, containerMember, id, out createdFromNonDefaultConstructor);
@@ -433,7 +435,7 @@ namespace Newtonsoft.Json.Serialization
if (reader.TokenType == JsonToken.StartObject)
throw JsonSerializationException.Create(reader, "Unexpected token when deserializing primitive value: " + reader.TokenType);
object value = CreateValueInternal(reader, objectType, primitiveContract, member, null, null, existingValue);
object value = CreateValueInternal(reader, resolvedObjectType, primitiveContract, member, null, null, existingValue);
CheckedRead(reader);
return value;
@@ -503,7 +505,7 @@ namespace Newtonsoft.Json.Serialization
throw JsonSerializationException.Create(reader, @"Cannot deserialize the current JSON object (e.g. {{""name"":""value""}}) into type '{0}' because the type requires a {1} to deserialize correctly.
To fix this error either change the JSON to a {1} or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
".FormatWith(CultureInfo.InvariantCulture, objectType, GetExpectedDescription(contract)));
".FormatWith(CultureInfo.InvariantCulture, resolvedObjectType, GetExpectedDescription(contract)));
}
private bool ReadSpecialPropertiesToken(JTokenReader reader, ref Type objectType, ref JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue, out object newValue, out string id)