-Added even more detail to no root XML element exception message when converting JSON to XML. Seriously, if you still get stuck here you're an idiot

-Added NullValueHandling, DefaultValueHandling and ReferenceLoopHandling to JsonPropertyAttribute
-Change JsonMemberMapping from a struct to a class. Now has too many properties for a struct
This commit is contained in:
JamesNK
2009-04-22 05:56:34 +00:00
parent 3e22e30261
commit affb9ec906
15 changed files with 183 additions and 74 deletions
@@ -32,6 +32,7 @@ using NUnit.Framework;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Utilities;
using System.Globalization;
using System.Xml;
namespace Newtonsoft.Json.Tests.Converters
{
@@ -255,5 +256,26 @@ namespace Newtonsoft.Json.Tests.Converters
string json2 = JsonConvert.SerializeObject(c, new IsoDateTimeConverter() { DateTimeStyles = DateTimeStyles.AssumeUniversal });
Assert.AreNotEqual(json, json2);
}
[Test]
public void BlogCodeSample()
{
Person p = new Person
{
Name = "Keith",
BirthDate = new DateTime(1980, 3, 8),
LastModified = new DateTime(2009, 4, 12, 20, 44, 55),
};
string jsonText = JsonConvert.SerializeObject(p, new IsoDateTimeConverter());
// {
// "Name": "Keith",
// "BirthDate": "1980-03-08T00:00:00",
// "LastModified": "2009-04-12T20:44:55"
// }
Console.WriteLine(jsonText);
}
}
}
@@ -31,6 +31,7 @@ using System.IO;
using System.Xml;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Utilities;
using Newtonsoft.Json.Linq;
namespace Newtonsoft.Json.Tests.Converters
{
@@ -348,7 +349,7 @@ namespace Newtonsoft.Json.Tests.Converters
}
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document.")]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifing a DeserializeRootElementName.")]
public void RootObjectMultipleProperties()
{
XmlDocument newDoc = (XmlDocument)JsonConvert.DeserializeXmlNode(@"{Prop1:1,Prop2:2}");
@@ -417,7 +418,7 @@ namespace Newtonsoft.Json.Tests.Converters
}
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document.")]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifing a DeserializeRootElementName.")]
public void MultipleRootProperties()
{
string strJSON = @"{
@@ -26,7 +26,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.Serialization.Json;
using System.Text;
using Newtonsoft.Json.Utilities;
using NUnit.Framework;
@@ -293,42 +292,5 @@ now brown cow?", '"', true);
Assert.AreEqual(JsonConvert.NegativeInfinity, JsonConvert.ToString(double.NegativeInfinity));
Assert.AreEqual(JsonConvert.NaN, JsonConvert.ToString(double.NaN));
}
[Test]
public void DateTimeOffsetToString()
{
DateTimeOffset dt = new DateTimeOffset(2000, 12, 20, 0, 0, 0, TimeSpan.Zero);
dt = DateTimeOffset.Now;
Console.WriteLine(JsonConvert.ToString(dt));
Console.WriteLine(JsonConvert.ToString(new DateTimeOffset(2000, 12, 20, 0, 0, 0, TimeSpan.FromHours(13))));
Console.WriteLine(JsonConvert.ToString(DateTime.Now));
Console.WriteLine(JsonConvert.ToString(DateTime.Now.ToUniversalTime()));
MemoryStream ms = new MemoryStream();
DataContractJsonSerializer s = new DataContractJsonSerializer(typeof(DateTime));
s.WriteObject(ms, DateTime.Now);
string json = Encoding.UTF8.GetString(ms.ToArray());
Console.WriteLine(AreEqual(DateTime.Now));
Console.WriteLine(AreEqual(DateTime.UtcNow));
Console.WriteLine(AreEqual(DateTimeOffset.Now));
Console.WriteLine(AreEqual(DateTimeOffset.UtcNow));
}
private bool AreEqual(object value)
{
MemoryStream ms = new MemoryStream();
DataContractJsonSerializer s = new DataContractJsonSerializer(value.GetType());
s.WriteObject(ms, value);
string dataContractJson = Encoding.UTF8.GetString(ms.ToArray());
string jsonNetJson = JsonConvert.SerializeObject(value);
bool result = (dataContractJson == jsonNetJson);
Console.WriteLine(StringUtils.FormatWith("DataContract: {0}, Json.NET: {1}, Equal: {2}", CultureInfo.InvariantCulture, dataContractJson, jsonNetJson, result));
return result;
}
}
}
@@ -1422,6 +1422,7 @@ keyword such as type of business.""
public SubKlass(string subprop) { SubProp = subprop; }
}
[Test]
public void DeserializePropertiesOnToNonDefaultConstructor()
{
SubKlass i = new SubKlass("my subprop");
@@ -1436,20 +1437,39 @@ keyword such as type of business.""
Assert.AreEqual(@"{""SubProp"":""my subprop"",""SuperProp"":""overrided superprop""}", newJson);
}
public class BrowserDateTimeTestClass
[Test]
public void JsonPropertyWithHandlingValues()
{
public DateTime utc { get; set; }
public DateTime local { get; set; }
JsonPropertyWithHandlingValues o = new JsonPropertyWithHandlingValues();
o.DefaultValueHandlingIgnoreProperty = "Default!";
o.DefaultValueHandlingIncludeProperty = "Default!";
string json = JsonConvert.SerializeObject(o, Formatting.Indented);
Assert.AreEqual(@"{
""DefaultValueHandlingIncludeProperty"": ""Default!"",
""NullValueHandlingIncludeProperty"": null,
""ReferenceLoopHandlingErrorProperty"": null,
""ReferenceLoopHandlingIgnoreProperty"": null,
""ReferenceLoopHandlingSerializeProperty"": null
}", json);
json = JsonConvert.SerializeObject(o, Formatting.Indented, new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore});
Assert.AreEqual(@"{
""DefaultValueHandlingIncludeProperty"": ""Default!"",
""NullValueHandlingIncludeProperty"": null
}", json);
}
public void BrowserNativeJsonDeserialization()
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Self referencing loop")]
public void JsonPropertyWithHandlingValues_ReferenceLoopError()
{
DateTime dt = DateTime.Now;
string browserJson = @"{""utc"":""2009-04-11T05:58:39Z"",""local"":""2009-04-11T05:58:39Z""}";
JsonPropertyWithHandlingValues o = new JsonPropertyWithHandlingValues();
o.ReferenceLoopHandlingErrorProperty = o;
BrowserDateTimeTestClass c = JsonConvert.DeserializeObject<BrowserDateTimeTestClass>(browserJson);
Console.WriteLine(c.utc);
JsonConvert.SerializeObject(o, Formatting.Indented, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
}
}
}
@@ -86,6 +86,7 @@
<Compile Include="TestObjects\Invoice.cs" />
<Compile Include="TestObjects\JaggedArray.cs" />
<Compile Include="TestObjects\JsonIgnoreAttributeTestClass.cs" />
<Compile Include="TestObjects\JsonPropertyWithHandlingValues.cs" />
<Compile Include="TestObjects\MemberConverterPrecedenceClassConverter.cs" />
<Compile Include="TestObjects\MethodExecutorObject.cs" />
<Compile Include="TestObjects\MyClass.cs" />
@@ -91,6 +91,7 @@
<Compile Include="TestObjects\Invoice.cs" />
<Compile Include="TestObjects\JaggedArray.cs" />
<Compile Include="TestObjects\JsonIgnoreAttributeTestClass.cs" />
<Compile Include="TestObjects\JsonPropertyWithHandlingValues.cs" />
<Compile Include="TestObjects\MemberConverterPrecedenceClassConverter.cs" />
<Compile Include="TestObjects\MethodExecutorObject.cs" />
<Compile Include="TestObjects\MyClass.cs" />
@@ -97,6 +97,7 @@
<Compile Include="TestObjects\ConverterPrecedenceClass.cs" />
<Compile Include="TestObjects\ConverterPrecedenceClassConverter.cs" />
<Compile Include="TestObjects\CircularReferenceWithIdClass.cs" />
<Compile Include="TestObjects\JsonPropertyWithHandlingValues.cs" />
<Compile Include="TestObjects\DefaultValueAttributeTestClass.cs" />
<Compile Include="TestObjects\DoubleClass.cs" />
<Compile Include="TestObjects\GenericImpl.cs" />
@@ -125,6 +125,14 @@ namespace Newtonsoft.Json.Tests.Schema
}
";
//JsonSchema schema;
//using (JsonTextReader reader = new JsonTextReader(new StringReader(schemaJson)))
//{
// JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver());
// schema = builder.Parse(reader);
//}
JsonSchema schema = JsonSchema.Parse(schemaJson);
JObject person = JObject.Parse(@"{
@@ -0,0 +1,55 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
using System.ComponentModel;
namespace Newtonsoft.Json.Tests.TestObjects
{
public class JsonPropertyWithHandlingValues
{
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
[DefaultValue("Default!")]
public string DefaultValueHandlingIgnoreProperty { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Include)]
[DefaultValue("Default!")]
public string DefaultValueHandlingIncludeProperty { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string NullValueHandlingIgnoreProperty { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Include)]
public string NullValueHandlingIncludeProperty { get; set; }
[JsonProperty(ReferenceLoopHandling = ReferenceLoopHandling.Error)]
public JsonPropertyWithHandlingValues ReferenceLoopHandlingErrorProperty { get; set; }
[JsonProperty(ReferenceLoopHandling = ReferenceLoopHandling.Ignore)]
public JsonPropertyWithHandlingValues ReferenceLoopHandlingIgnoreProperty { get; set; }
[JsonProperty(ReferenceLoopHandling = ReferenceLoopHandling.Serialize)]
public JsonPropertyWithHandlingValues ReferenceLoopHandlingSerializeProperty { get; set; }
}
}
@@ -491,7 +491,7 @@ namespace Newtonsoft.Json.Converters
{
case JsonToken.PropertyName:
if (currentNode.NodeType == XmlNodeType.Document && document.DocumentElement != null)
throw new JsonSerializationException("JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document.");
throw new JsonSerializationException("JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifing a DeserializeRootElementName.");
string propertyName = reader.Value.ToString();
reader.Read();
+3 -3
View File
@@ -658,12 +658,12 @@ namespace Newtonsoft.Json
/// Deserializes the XmlNode from a JSON string nested in a root elment.
/// </summary>
/// <param name="value">The JSON string.</param>
/// <param name="rootElementName">The root element name.</param>
/// <param name="deserializeRootElementName">The name of the root element to append when deserializing.</param>
/// <returns>The deserialized XmlNode</returns>
public static XmlNode DeserializeXmlNode(string value, string rootElementName)
public static XmlNode DeserializeXmlNode(string value, string deserializeRootElementName)
{
XmlNodeConverter converter = new XmlNodeConverter();
converter.DeserializeRootElementName = rootElementName;
converter.DeserializeRootElementName = deserializeRootElementName;
return (XmlDocument)DeserializeObject(value, typeof(XmlDocument), converter);
}
+26 -13
View File
@@ -8,24 +8,37 @@ namespace Newtonsoft.Json
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
public sealed class JsonPropertyAttribute : Attribute
{
private string _propertyName;
private bool _isRequired;
// yuck. can't set nullable properties on an attribute in C#
// have to use this approach to get an unset default state
internal NullValueHandling? _nullValueHandling;
internal DefaultValueHandling? _defaultValueHandling;
internal ReferenceLoopHandling? _referenceLoopHandling;
public NullValueHandling NullValueHandling
{
get { return _nullValueHandling ?? default(NullValueHandling); }
set { _nullValueHandling = value; }
}
public DefaultValueHandling DefaultValueHandling
{
get { return _defaultValueHandling ?? default(DefaultValueHandling); }
set { _defaultValueHandling = value; }
}
public ReferenceLoopHandling ReferenceLoopHandling
{
get { return _referenceLoopHandling ?? default(ReferenceLoopHandling); }
set { _referenceLoopHandling = value; }
}
/// <summary>
/// Gets or sets the name of the property.
/// </summary>
/// <value>The name of the property.</value>
public string PropertyName
{
get { return _propertyName; }
set { _propertyName = value; }
}
public string PropertyName { get; set; }
public bool IsRequired
{
get { return _isRequired; }
set { _isRequired = value; }
}
public bool IsRequired { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="JsonPropertyAttribute"/> class.
@@ -40,7 +53,7 @@ namespace Newtonsoft.Json
/// <param name="propertyName">Name of the property.</param>
public JsonPropertyAttribute(string propertyName)
{
_propertyName = propertyName;
PropertyName = propertyName;
}
}
}
+5 -5
View File
@@ -437,10 +437,10 @@ namespace Newtonsoft.Json
private bool ShouldSetMappingValue(JsonMemberMapping memberMapping, object value)
{
if (_nullValueHandling == NullValueHandling.Ignore && value == null)
if (memberMapping.NullValueHandling.GetValueOrDefault(_nullValueHandling) == NullValueHandling.Ignore && value == null)
return false;
if (_defaultValueHandling == DefaultValueHandling.Ignore && Equals(value, memberMapping.DefaultValue))
if (memberMapping.DefaultValueHandling.GetValueOrDefault(_defaultValueHandling) == DefaultValueHandling.Ignore && Equals(value, memberMapping.DefaultValue))
return false;
if (!memberMapping.Writable)
@@ -814,15 +814,15 @@ namespace Newtonsoft.Json
{
object memberValue = ReflectionUtils.GetMemberValue(member, value);
if (_nullValueHandling == NullValueHandling.Ignore && memberValue == null)
if (memberMapping.NullValueHandling.GetValueOrDefault(_nullValueHandling) == NullValueHandling.Ignore && memberValue == null)
return;
if (_defaultValueHandling == DefaultValueHandling.Ignore && object.Equals(memberValue, defaultValue))
if (memberMapping.DefaultValueHandling.GetValueOrDefault(_defaultValueHandling) == DefaultValueHandling.Ignore && object.Equals(memberValue, defaultValue))
return;
if (writer.SerializeStack.IndexOf(memberValue) != -1)
{
switch (_referenceLoopHandling)
switch (memberMapping.ReferenceLoopHandling.GetValueOrDefault(_referenceLoopHandling))
{
case ReferenceLoopHandling.Error:
throw new JsonSerializationException("Self referencing loop");
@@ -115,7 +115,11 @@ namespace Newtonsoft.Json.Serialization
DefaultValueAttribute defaultValueAttribute = ReflectionUtils.GetAttribute<DefaultValueAttribute>(member, true);
object defaultValue = (defaultValueAttribute != null) ? defaultValueAttribute.Value : null;
return new JsonMemberMapping(resolvedMappedName, member, ignored, readable, writable, memberConverter, defaultValue, required);
NullValueHandling? nullValueHandling = (propertyAttribute != null) ? propertyAttribute._nullValueHandling : null;
DefaultValueHandling? defaultValueHandling = (propertyAttribute != null) ? propertyAttribute._defaultValueHandling : null;
ReferenceLoopHandling? referenceLoopHandling = (propertyAttribute != null) ? propertyAttribute._referenceLoopHandling : null;
return new JsonMemberMapping(resolvedMappedName, member, ignored, readable, writable, memberConverter, defaultValue, required, nullValueHandling, defaultValueHandling, referenceLoopHandling);
}
protected virtual string ResolveMappingName(string mappedName)
@@ -30,7 +30,7 @@ using System.Reflection;
namespace Newtonsoft.Json.Serialization
{
public struct JsonMemberMapping
public class JsonMemberMapping
{
private readonly string _mappingName;
private readonly MemberInfo _member;
@@ -40,8 +40,11 @@ namespace Newtonsoft.Json.Serialization
private readonly JsonConverter _memberConverter;
private readonly object _defaultValue;
private readonly bool _required;
private readonly NullValueHandling? _nullValueHandling;
private readonly DefaultValueHandling? _defaultValueHandling;
private readonly ReferenceLoopHandling? _referenceLoopHandling;
public JsonMemberMapping(string mappingName, MemberInfo member, bool ignored, bool readable, bool writable, JsonConverter memberConverter, object defaultValue, bool required)
public JsonMemberMapping(string mappingName, MemberInfo member, bool ignored, bool readable, bool writable, JsonConverter memberConverter, object defaultValue, bool required, NullValueHandling? nullValueHandling, DefaultValueHandling? defaultValueHandling, ReferenceLoopHandling? referenceLoopHandling)
{
_mappingName = mappingName;
_member = member;
@@ -51,6 +54,9 @@ namespace Newtonsoft.Json.Serialization
_memberConverter = memberConverter;
_defaultValue = defaultValue;
_required = required;
_nullValueHandling = nullValueHandling;
_defaultValueHandling = defaultValueHandling;
_referenceLoopHandling = referenceLoopHandling;
}
public string MappingName
@@ -92,5 +98,20 @@ namespace Newtonsoft.Json.Serialization
{
get { return _required; }
}
public NullValueHandling? NullValueHandling
{
get { return _nullValueHandling; }
}
public DefaultValueHandling? DefaultValueHandling
{
get { return _defaultValueHandling; }
}
public ReferenceLoopHandling? ReferenceLoopHandling
{
get { return _referenceLoopHandling; }
}
}
}