-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:
JamesNK
2010-10-22 23:23:49 +00:00
parent 1703992773
commit 15ea91fb63
8 changed files with 283 additions and 58 deletions
@@ -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)