-Fixed error when deserializing nullable structs
-Fixed writing JSON Schema option label -Improved error message when converting JSON with an empty property to XML
This commit is contained in:
@@ -906,6 +906,92 @@ namespace Newtonsoft.Json.Tests.Converters
|
||||
|
||||
Assert.AreEqual(expectedXmlJson, xmlJson);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "XmlNodeConverter cannot convert JSON with an empty property name to XML.")]
|
||||
public void EmptyPropertyName()
|
||||
{
|
||||
string json = @"{
|
||||
""8452309520V2"": {
|
||||
"""": {
|
||||
""CLIENT"": {
|
||||
""ID_EXPIRATION_1"": {
|
||||
""VALUE"": ""12/12/2000"",
|
||||
""DATATYPE"": ""D"",
|
||||
""MSG"": ""Missing Identification Exp. Date 1""
|
||||
},
|
||||
""ID_ISSUEDATE_1"": {
|
||||
""VALUE"": """",
|
||||
""DATATYPE"": ""D"",
|
||||
""MSG"": ""Missing Identification Issue Date 1""
|
||||
}
|
||||
}
|
||||
},
|
||||
""457463534534"": {
|
||||
""ACCOUNT"": {
|
||||
""FUNDING_SOURCE"": {
|
||||
""VALUE"": ""FS0"",
|
||||
""DATATYPE"": ""L"",
|
||||
""MSG"": ""Missing Source of Funds""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}{
|
||||
""34534634535345"": {
|
||||
"""": {
|
||||
""CLIENT"": {
|
||||
""ID_NUMBER_1"": {
|
||||
""VALUE"": """",
|
||||
""DATATYPE"": ""S"",
|
||||
""MSG"": ""Missing Picture ID""
|
||||
},
|
||||
""ID_EXPIRATION_1"": {
|
||||
""VALUE"": ""12/12/2000"",
|
||||
""DATATYPE"": ""D"",
|
||||
""MSG"": ""Missing Picture ID""
|
||||
},
|
||||
""WALK_IN"": {
|
||||
""VALUE"": """",
|
||||
""DATATYPE"": ""L"",
|
||||
""MSG"": ""Missing Walk in""
|
||||
},
|
||||
""PERSONAL_MEETING"": {
|
||||
""VALUE"": ""PM1"",
|
||||
""DATATYPE"": ""L"",
|
||||
""MSG"": ""Missing Met Client in Person""
|
||||
},
|
||||
""ID_ISSUEDATE_1"": {
|
||||
""VALUE"": """",
|
||||
""DATATYPE"": ""D"",
|
||||
""MSG"": ""Missing Picture ID""
|
||||
},
|
||||
""PHOTO_ID"": {
|
||||
""VALUE"": """",
|
||||
""DATATYPE"": ""L"",
|
||||
""MSG"": ""Missing Picture ID""
|
||||
},
|
||||
""ID_TYPE_1"": {
|
||||
""VALUE"": """",
|
||||
""DATATYPE"": ""L"",
|
||||
""MSG"": ""Missing Picture ID""
|
||||
}
|
||||
}
|
||||
},
|
||||
""45635624523"": {
|
||||
""ACCOUNT"": {
|
||||
""FUNDING_SOURCE"": {
|
||||
""VALUE"": ""FS1"",
|
||||
""DATATYPE"": ""L"",
|
||||
""MSG"": ""Missing Source of Funds""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}";
|
||||
|
||||
DeserializeXmlNode(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -512,15 +512,15 @@ namespace Newtonsoft.Json.Tests.Schema
|
||||
""options"": [
|
||||
{
|
||||
""value"": 0,
|
||||
""value"": ""No""
|
||||
""label"": ""No""
|
||||
},
|
||||
{
|
||||
""value"": 1,
|
||||
""value"": ""Asc""
|
||||
""label"": ""Asc""
|
||||
},
|
||||
{
|
||||
""value"": -1,
|
||||
""value"": ""Desc""
|
||||
""label"": ""Desc""
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -340,5 +340,42 @@ namespace Newtonsoft.Json.Tests.Schema
|
||||
]
|
||||
}", json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReadOptions()
|
||||
{
|
||||
JsonSchema schema = JsonSchema.Parse(@"{
|
||||
""type"": ""object"",
|
||||
""properties"": {
|
||||
""x"": {
|
||||
""type"": ""integer"",
|
||||
""enum"": [
|
||||
0,
|
||||
1,
|
||||
-1
|
||||
],
|
||||
""options"": [
|
||||
{
|
||||
""value"": 0,
|
||||
""label"": ""No""
|
||||
},
|
||||
{
|
||||
""value"": 1,
|
||||
""label"": ""Asc""
|
||||
},
|
||||
{
|
||||
""value"": -1,
|
||||
""label"": ""Desc""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}");
|
||||
|
||||
Assert.AreEqual(schema.Properties["x"].Options.Count, 3);
|
||||
Assert.AreEqual(schema.Properties["x"].Options[0], "No");
|
||||
Assert.AreEqual(schema.Properties["x"].Options[1], "Asc");
|
||||
Assert.AreEqual(schema.Properties["x"].Options[-1], "Desc");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3746,5 +3746,86 @@ keyword such as type of business.""
|
||||
Assert.AreEqual(meh.IDontWork, "meh");
|
||||
}
|
||||
|
||||
#if !(SILVERLIGHT || PocketPC || NET20)
|
||||
[DataContract]
|
||||
public struct StructISerializable : ISerializable
|
||||
{
|
||||
private string _name;
|
||||
|
||||
public StructISerializable(SerializationInfo info, StreamingContext context)
|
||||
{
|
||||
_name = info.GetString("Name");
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set { _name = value; }
|
||||
}
|
||||
|
||||
public void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||
{
|
||||
info.AddValue("Name", _name);
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class NullableStructPropertyClass
|
||||
{
|
||||
private StructISerializable _foo1;
|
||||
private StructISerializable? _foo2;
|
||||
|
||||
[DataMember]
|
||||
public StructISerializable Foo1
|
||||
{
|
||||
get { return _foo1; }
|
||||
set { _foo1 = value; }
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public StructISerializable? Foo2
|
||||
{
|
||||
get { return _foo2; }
|
||||
set { _foo2 = value; }
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeNullableStruct()
|
||||
{
|
||||
NullableStructPropertyClass nullableStructPropertyClass = new NullableStructPropertyClass();
|
||||
nullableStructPropertyClass.Foo1 = new StructISerializable() {Name = "foo 1"};
|
||||
nullableStructPropertyClass.Foo2 = new StructISerializable() {Name = "foo 2"};
|
||||
|
||||
NullableStructPropertyClass barWithNull = new NullableStructPropertyClass();
|
||||
barWithNull.Foo1 = new StructISerializable() {Name = "foo 1"};
|
||||
barWithNull.Foo2 = null;
|
||||
|
||||
//throws error on deserialization because bar1.Foo2 is of type Foo?
|
||||
string s = JsonConvert.SerializeObject(nullableStructPropertyClass);
|
||||
NullableStructPropertyClass deserialized = deserialize(s);
|
||||
Assert.AreEqual(deserialized.Foo1.Name, "foo 1");
|
||||
Assert.AreEqual(deserialized.Foo2.Value.Name, "foo 2");
|
||||
|
||||
//no error Foo2 is null
|
||||
s = JsonConvert.SerializeObject(barWithNull);
|
||||
deserialized = deserialize(s);
|
||||
Assert.AreEqual(deserialized.Foo1.Name, "foo 1");
|
||||
Assert.AreEqual(deserialized.Foo2, null);
|
||||
}
|
||||
|
||||
|
||||
static NullableStructPropertyClass deserialize(string serStr)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<NullableStructPropertyClass>(
|
||||
serStr,
|
||||
new JsonSerializerSettings
|
||||
{
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
MissingMemberHandling = MissingMemberHandling.Ignore
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1118,6 +1118,9 @@ namespace Newtonsoft.Json.Converters
|
||||
|
||||
private void ReadElement(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName, XmlNamespaceManager manager)
|
||||
{
|
||||
if (string.IsNullOrEmpty(propertyName))
|
||||
throw new JsonSerializationException("XmlNodeConverter cannot convert JSON with an empty property name to XML.");
|
||||
|
||||
Dictionary<string, string> attributeNameValues = ReadAttributeElements(reader, manager);
|
||||
|
||||
string elementPrefix = MiscellaneousUtils.GetPrefix(propertyName);
|
||||
@@ -1214,50 +1217,59 @@ namespace Newtonsoft.Json.Converters
|
||||
case JsonToken.PropertyName:
|
||||
string attributeName = reader.Value.ToString();
|
||||
string attributeValue;
|
||||
char firstChar = attributeName[0];
|
||||
|
||||
switch (firstChar)
|
||||
if (!string.IsNullOrEmpty(attributeName))
|
||||
{
|
||||
case '@':
|
||||
attributeName = attributeName.Substring(1);
|
||||
reader.Read();
|
||||
attributeValue = reader.Value.ToString();
|
||||
attributeNameValues.Add(attributeName, attributeValue);
|
||||
char firstChar = attributeName[0];
|
||||
|
||||
string namespacePrefix;
|
||||
if (IsNamespaceAttribute(attributeName, out namespacePrefix))
|
||||
{
|
||||
manager.AddNamespace(namespacePrefix, attributeValue);
|
||||
}
|
||||
break;
|
||||
case '$':
|
||||
attributeName = attributeName.Substring(1);
|
||||
reader.Read();
|
||||
attributeValue = reader.Value.ToString();
|
||||
switch (firstChar)
|
||||
{
|
||||
case '@':
|
||||
attributeName = attributeName.Substring(1);
|
||||
reader.Read();
|
||||
attributeValue = reader.Value.ToString();
|
||||
attributeNameValues.Add(attributeName, attributeValue);
|
||||
|
||||
// check that JsonNamespaceUri is in scope
|
||||
// if it isn't then add it to document and namespace manager
|
||||
string jsonPrefix = manager.LookupPrefix(JsonNamespaceUri);
|
||||
if (jsonPrefix == null)
|
||||
{
|
||||
// ensure that the prefix used is free
|
||||
int? i = null;
|
||||
while (manager.LookupNamespace("json" + i) != null)
|
||||
string namespacePrefix;
|
||||
if (IsNamespaceAttribute(attributeName, out namespacePrefix))
|
||||
{
|
||||
i = i.GetValueOrDefault() + 1;
|
||||
manager.AddNamespace(namespacePrefix, attributeValue);
|
||||
}
|
||||
jsonPrefix = "json" + i;
|
||||
break;
|
||||
case '$':
|
||||
attributeName = attributeName.Substring(1);
|
||||
reader.Read();
|
||||
attributeValue = reader.Value.ToString();
|
||||
|
||||
attributeNameValues.Add("xmlns:" + jsonPrefix, JsonNamespaceUri);
|
||||
manager.AddNamespace(jsonPrefix, JsonNamespaceUri);
|
||||
}
|
||||
// check that JsonNamespaceUri is in scope
|
||||
// if it isn't then add it to document and namespace manager
|
||||
string jsonPrefix = manager.LookupPrefix(JsonNamespaceUri);
|
||||
if (jsonPrefix == null)
|
||||
{
|
||||
// ensure that the prefix used is free
|
||||
int? i = null;
|
||||
while (manager.LookupNamespace("json" + i) != null)
|
||||
{
|
||||
i = i.GetValueOrDefault() + 1;
|
||||
}
|
||||
jsonPrefix = "json" + i;
|
||||
|
||||
attributeNameValues.Add(jsonPrefix + ":" + attributeName, attributeValue);
|
||||
break;
|
||||
default:
|
||||
finishedAttributes = true;
|
||||
break;
|
||||
attributeNameValues.Add("xmlns:" + jsonPrefix, JsonNamespaceUri);
|
||||
manager.AddNamespace(jsonPrefix, JsonNamespaceUri);
|
||||
}
|
||||
|
||||
attributeNameValues.Add(jsonPrefix + ":" + attributeName, attributeValue);
|
||||
break;
|
||||
default:
|
||||
finishedAttributes = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
finishedAttributes = true;
|
||||
}
|
||||
|
||||
break;
|
||||
case JsonToken.EndObject:
|
||||
finishedElement = true;
|
||||
|
||||
@@ -136,7 +136,7 @@ namespace Newtonsoft.Json.Schema
|
||||
option.Key.WriteTo(_writer);
|
||||
if (option.Value != null)
|
||||
{
|
||||
_writer.WritePropertyName(JsonSchemaConstants.OptionValuePropertyName);
|
||||
_writer.WritePropertyName(JsonSchemaConstants.OptionLabelPropertyName);
|
||||
_writer.WriteValue(option.Value);
|
||||
}
|
||||
_writer.WriteEndObject();
|
||||
|
||||
@@ -486,38 +486,40 @@ namespace Newtonsoft.Json.Serialization
|
||||
/// <returns>A <see cref="JsonContract"/> for the given type.</returns>
|
||||
protected virtual JsonContract CreateContract(Type objectType)
|
||||
{
|
||||
if (JsonConvert.IsJsonPrimitiveType(objectType))
|
||||
return CreatePrimitiveContract(objectType);
|
||||
Type t = ReflectionUtils.EnsureNotNullableType(objectType);
|
||||
|
||||
if (JsonTypeReflector.GetJsonObjectAttribute(objectType) != null)
|
||||
return CreateObjectContract(objectType);
|
||||
if (JsonConvert.IsJsonPrimitiveType(t))
|
||||
return CreatePrimitiveContract(t);
|
||||
|
||||
if (JsonTypeReflector.GetJsonArrayAttribute(objectType) != null)
|
||||
return CreateArrayContract(objectType);
|
||||
if (JsonTypeReflector.GetJsonObjectAttribute(t) != null)
|
||||
return CreateObjectContract(t);
|
||||
|
||||
if (objectType.IsSubclassOf(typeof(JToken)))
|
||||
return CreateLinqContract(objectType);
|
||||
if (JsonTypeReflector.GetJsonArrayAttribute(t) != null)
|
||||
return CreateArrayContract(t);
|
||||
|
||||
if (CollectionUtils.IsDictionaryType(objectType))
|
||||
return CreateDictionaryContract(objectType);
|
||||
if (t.IsSubclassOf(typeof(JToken)))
|
||||
return CreateLinqContract(t);
|
||||
|
||||
if (typeof(IEnumerable).IsAssignableFrom(objectType))
|
||||
return CreateArrayContract(objectType);
|
||||
if (CollectionUtils.IsDictionaryType(t))
|
||||
return CreateDictionaryContract(t);
|
||||
|
||||
if (CanConvertToString(objectType))
|
||||
return CreateStringContract(objectType);
|
||||
if (typeof(IEnumerable).IsAssignableFrom(t))
|
||||
return CreateArrayContract(t);
|
||||
|
||||
if (CanConvertToString(t))
|
||||
return CreateStringContract(t);
|
||||
|
||||
#if !SILVERLIGHT && !PocketPC
|
||||
if (typeof(ISerializable).IsAssignableFrom(objectType))
|
||||
return CreateISerializableContract(objectType);
|
||||
if (typeof(ISerializable).IsAssignableFrom(t))
|
||||
return CreateISerializableContract(t);
|
||||
#endif
|
||||
|
||||
#if !(NET35 || NET20 || SILVERLIGHT)
|
||||
if (typeof(IDynamicMetaObjectProvider).IsAssignableFrom(objectType))
|
||||
return CreateDynamicContract(objectType);
|
||||
if (typeof(IDynamicMetaObjectProvider).IsAssignableFrom(t))
|
||||
return CreateDynamicContract(t);
|
||||
#endif
|
||||
|
||||
return CreateObjectContract(objectType);
|
||||
return CreateObjectContract(t);
|
||||
}
|
||||
|
||||
internal static bool CanConvertToString(Type type)
|
||||
|
||||
@@ -169,6 +169,13 @@ namespace Newtonsoft.Json.Utilities
|
||||
return (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>));
|
||||
}
|
||||
|
||||
public static Type EnsureNotNullableType(Type t)
|
||||
{
|
||||
return (IsNullableType(t))
|
||||
? Nullable.GetUnderlyingType(t)
|
||||
: t;
|
||||
}
|
||||
|
||||
//public static bool IsValueTypeUnitializedValue(ValueType value)
|
||||
//{
|
||||
// if (value == null)
|
||||
|
||||
Reference in New Issue
Block a user