diff options
author | JamesNK <james@newtonking.com> | 2010-10-23 03:23:49 +0400 |
---|---|---|
committer | JamesNK <james@newtonking.com> | 2010-10-23 03:23:49 +0400 |
commit | 15ea91fb63f40e7ea0a1dfb1057b949d424bb63c (patch) | |
tree | e12599cdabebf833c4ceb281acd03e069034f4b7 /Src | |
parent | 1703992773b08532d2adad1bf073c849b35a8f88 (diff) |
-Fixed error when deserializing nullable structs
-Fixed writing JSON Schema option label
-Improved error message when converting JSON with an empty property to XML
Diffstat (limited to 'Src')
8 files changed, 286 insertions, 61 deletions
diff --git a/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs b/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs index 1865a17..6c49c1e 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs @@ -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
\ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaGeneratorTests.cs b/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaGeneratorTests.cs index 8cb6a69..eb48444 100644 --- a/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaGeneratorTests.cs +++ b/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaGeneratorTests.cs @@ -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""
}
]
}
diff --git a/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaTests.cs b/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaTests.cs index 4051ea9..7459ce0 100644 --- a/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaTests.cs +++ b/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaTests.cs @@ -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");
+ }
}
}
diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs index 8178da5..5ece94d 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs @@ -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
}
}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs index c73050c..e8b5c22 100644 --- a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs @@ -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);
-
- string namespacePrefix;
- if (IsNamespaceAttribute(attributeName, out namespacePrefix))
- {
- manager.AddNamespace(namespacePrefix, attributeValue);
- }
- break;
- case '$':
- attributeName = attributeName.Substring(1);
- reader.Read();
- attributeValue = reader.Value.ToString();
-
- // 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)
+ char firstChar = attributeName[0];
+
+ switch (firstChar)
+ {
+ case '@':
+ attributeName = attributeName.Substring(1);
+ reader.Read();
+ attributeValue = reader.Value.ToString();
+ attributeNameValues.Add(attributeName, attributeValue);
+
+ string namespacePrefix;
+ if (IsNamespaceAttribute(attributeName, out namespacePrefix))
{
- i = i.GetValueOrDefault() + 1;
+ manager.AddNamespace(namespacePrefix, attributeValue);
+ }
+ break;
+ case '$':
+ attributeName = attributeName.Substring(1);
+ reader.Read();
+ attributeValue = reader.Value.ToString();
+
+ // 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("xmlns:" + jsonPrefix, JsonNamespaceUri);
+ manager.AddNamespace(jsonPrefix, JsonNamespaceUri);
}
- jsonPrefix = "json" + i;
-
- attributeNameValues.Add("xmlns:" + jsonPrefix, JsonNamespaceUri);
- manager.AddNamespace(jsonPrefix, JsonNamespaceUri);
- }
- attributeNameValues.Add(jsonPrefix + ":" + attributeName, attributeValue);
- break;
- default:
- finishedAttributes = true;
- break;
+ attributeNameValues.Add(jsonPrefix + ":" + attributeName, attributeValue);
+ break;
+ default:
+ finishedAttributes = true;
+ break;
+ }
}
+ else
+ {
+ finishedAttributes = true;
+ }
+
break;
case JsonToken.EndObject:
finishedElement = true;
diff --git a/Src/Newtonsoft.Json/Schema/JsonSchemaWriter.cs b/Src/Newtonsoft.Json/Schema/JsonSchemaWriter.cs index 2d5d2a6..c3f9d50 100644 --- a/Src/Newtonsoft.Json/Schema/JsonSchemaWriter.cs +++ b/Src/Newtonsoft.Json/Schema/JsonSchemaWriter.cs @@ -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();
diff --git a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs index b840b5a..edc91df 100644 --- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs @@ -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)
diff --git a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs index e2bb83b..d5f557a 100644 --- a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs @@ -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)
|