-Add support for reading octal and hexadecimal numbers from JSON

-Fix serializing indexed properties
-Fix serializing JRaw properties
This commit is contained in:
JamesNK
2010-01-08 08:12:40 +00:00
parent 324c4e4bc5
commit 75649bfa00
14 changed files with 236 additions and 78 deletions
+12 -5
View File
@@ -20,7 +20,7 @@
equivalent and back again.</p>
<p>For simple scenarios the <a href="./html/Overload_Newtonsoft_Json_JsonConvert_SerializeObject.htm">SerializeObject</a> and <a href="./html/Overload_Newtonsoft_Json_JsonConvert_DeserializeObject.htm">DeserializeObject</a> methods on <a href="./html/T_Newtonsoft_Json_JsonConvert.htm">JsonConvert</a> provide an easy to use wrapper over
<p>For simple scenarios where you want to convert to and from a JSON string the <a href="./html/Overload_Newtonsoft_Json_JsonConvert_SerializeObject.htm">SerializeObject</a> and <a href="./html/Overload_Newtonsoft_Json_JsonConvert_DeserializeObject.htm">DeserializeObject</a> methods on <a href="./html/T_Newtonsoft_Json_JsonConvert.htm">JsonConvert</a> provide an easy to use wrapper over
JsonSerializer.</p>
@@ -55,8 +55,11 @@
<p>For more control over how an object is serialized the JsonSerializer can be used
directly. The JsonSerializer has a number of properties to control its behaviour
when serializing and deserializing.</p>
directly. The JsonSerializer is able to read and write JSON text directly to
a stream via <a href="./html/T_Newtonsoft_Json_JsonTextReader.htm">JsonTextReader</a> and <a href="./html/T_Newtonsoft_Json_JsonTextWriter.htm">JsonTextWriter</a>. Other kinds of JsonWriters can
also be used such as <a href="./html/T_Newtonsoft_Json_Linq_JTokenReader.htm">JTokenReader</a>/<a href="./html/T_Newtonsoft_Json_Linq_JTokenWriter.htm">JTokenWriter</a> to
convert your object to and
from LINQ to JSON objects or <a href="./html/T_Newtonsoft_Json_Bson_BsonReader.htm">BsonReader</a>/<a href="./html/T_Newtonsoft_Json_Bson_BsonWriter.htm">BsonWriter</a> to convert to and from BSON.</p>
<div class="overflowpanel"> <div class="code">
@@ -77,6 +80,9 @@
</div>
</div></div>
<p>JsonSerializer has a number of properties on it to customize how it serializes JSON.
These can also be used with the methods on JsonConvert via the
JsonSerializerSettings overloads.</p>
<h5>ReferenceLoopHandling</h5>
<p>Controls how circular referencing objects are serialized. Error, ignore or
@@ -114,11 +120,12 @@ the member's DefaultValueAttribute. Include or ignore.</p>
<h5>XmlNodeConverter</h5>
<p>Converts an XmlNode to and from JSON. Note that to convert a JSON object it must have only a single property
or you must define a root node name to be inserted when using this converter. This is required because properties are converted into nodes and
well formed XML can only have one root node.</p>
well formed XML can only have one root node. XmlNodeConverter has an option to
insert a root node for you.</p>
<h5>BinaryConverter</h5>
<p>Converts binary data like a byte array or SqlBinary object to JSON. The binary
<p>Converts binary data like the SqlBinary object to JSON. The binary
data is written as a string in JSON and is encoded in Base64.</p>
<h5>CustomCreationConverter</h5>
@@ -620,5 +620,32 @@ bye", reader.Value);
string text = Encoding.UTF8.GetString(data, 0, data.Length);
Assert.AreEqual("Hello world.", text);
}
[Test]
public void ReadOctalNumber()
{
StringReader s = new StringReader(@"[0372, 0xFA, 0XFA]");
JsonTextReader jsonReader = new JsonTextReader(s);
Assert.IsTrue(jsonReader.Read());
Assert.AreEqual(JsonToken.StartArray, jsonReader.TokenType);
Assert.IsTrue(jsonReader.Read());
Assert.AreEqual(JsonToken.Integer, jsonReader.TokenType);
Assert.AreEqual(250, jsonReader.Value);
Assert.IsTrue(jsonReader.Read());
Assert.AreEqual(JsonToken.Integer, jsonReader.TokenType);
Assert.AreEqual(250, jsonReader.Value);
Assert.IsTrue(jsonReader.Read());
Assert.AreEqual(JsonToken.Integer, jsonReader.TokenType);
Assert.AreEqual(250, jsonReader.Value);
Assert.IsTrue(jsonReader.Read());
Assert.AreEqual(JsonToken.EndArray, jsonReader.TokenType);
Assert.IsFalse(jsonReader.Read());
}
}
}
File diff suppressed because one or more lines are too long
@@ -2123,5 +2123,114 @@ keyword such as type of business.""
Assert.AreEqual(1, d.List.Count);
Assert.AreEqual("existing", d.List[0]);
}
public interface IKeyValueId
{
int Id { get; set; }
string Key { get; set; }
string Value { get; set; }
}
public class KeyValueId : IKeyValueId
{
public int Id { get; set; }
public string Key { get; set; }
public string Value { get; set; }
}
public class ThisGenericTest<T> where T : IKeyValueId
{
private Dictionary<string, T> _dict1 = new Dictionary<string, T>();
public string MyProperty { get; set; }
public void Add(T item)
{
this._dict1.Add(item.Key, item);
}
public T this[string key]
{
get { return this._dict1[key]; }
set { this._dict1[key] = value; }
}
public T this[int id]
{
get { return this._dict1.Values.FirstOrDefault(x => x.Id == id); }
set
{
var item = this[id];
if (item == null)
this.Add(value);
else
this._dict1[item.Key] = value;
}
}
public string ToJson()
{
return JsonConvert.SerializeObject(this, Formatting.Indented);
}
public T[] TheItems
{
get { return this._dict1.Values.ToArray<T>(); }
set
{
foreach (var item in value)
this.Add(item);
}
}
}
[Test]
public void IgnoreIndexedProperties()
{
ThisGenericTest<KeyValueId> g = new ThisGenericTest<KeyValueId>();
g.Add(new KeyValueId { Id = 1, Key = "key1", Value = "value1" });
g.Add(new KeyValueId { Id = 2, Key = "key2", Value = "value2" });
g.MyProperty = "some value";
string json = g.ToJson();
Assert.AreEqual(@"{
""MyProperty"": ""some value"",
""TheItems"": [
{
""Id"": 1,
""Key"": ""key1"",
""Value"": ""value1""
},
{
""Id"": 2,
""Key"": ""key2"",
""Value"": ""value2""
}
]
}", json);
ThisGenericTest<KeyValueId> gen = JsonConvert.DeserializeObject<ThisGenericTest<KeyValueId>>(json);
Assert.AreEqual("some value", gen.MyProperty);
}
public class JRawValueTestObject
{
public JRaw Value { get; set; }
}
[Test]
public void JRawValue()
{
JRawValueTestObject deserialized = JsonConvert.DeserializeObject<JRawValueTestObject>("{value:3}");
Assert.AreEqual("3", deserialized.Value.ToString());
deserialized = JsonConvert.DeserializeObject<JRawValueTestObject>("{value:'3'}");
Assert.AreEqual(@"""3""", deserialized.Value.ToString());
}
}
}
@@ -573,11 +573,6 @@ namespace Newtonsoft.Json.Converters
{
return c.OfType<XmlAttribute>().Where(a => a.NamespaceURI != JsonNamespaceUri);
}
private IEnumerable<XmlNode> ValueNodes(XmlNodeList c)
{
return c.OfType<XmlNode>().Where(n => n.NamespaceURI != JsonNamespaceUri);
}
#endregion
/// <summary>
+13 -30
View File
@@ -41,54 +41,39 @@ namespace Newtonsoft.Json
/// <summary>
/// Represents JavaScript's boolean value true as a string. This field is read-only.
/// </summary>
public static readonly string True;
public static readonly string True = "true";
/// <summary>
/// Represents JavaScript's boolean value false as a string. This field is read-only.
/// </summary>
public static readonly string False;
public static readonly string False = "false";
/// <summary>
/// Represents JavaScript's null as a string. This field is read-only.
/// </summary>
public static readonly string Null;
public static readonly string Null = "null";
/// <summary>
/// Represents JavaScript's undefined as a string. This field is read-only.
/// </summary>
public static readonly string Undefined;
public static readonly string Undefined = "undefined";
/// <summary>
/// Represents JavaScript's positive infinity as a string. This field is read-only.
/// </summary>
public static readonly string PositiveInfinity;
public static readonly string PositiveInfinity = "Infinity";
/// <summary>
/// Represents JavaScript's negative infinity as a string. This field is read-only.
/// </summary>
public static readonly string NegativeInfinity;
public static readonly string NegativeInfinity = "-Infinity";
/// <summary>
/// Represents JavaScript's NaN as a string. This field is read-only.
/// </summary>
public static readonly string NaN;
public static readonly string NaN = "NaN";
internal static long InitialJavaScriptDateTicks;
internal static DateTime MinimumJavaScriptDate;
static JsonConvert()
{
True = "true";
False = "false";
Null = "null";
Undefined = "undefined";
PositiveInfinity = "Infinity";
NegativeInfinity = "-Infinity";
NaN = "NaN";
InitialJavaScriptDateTicks = (new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).Ticks;
MinimumJavaScriptDate = new DateTime(100, 1, 1);
}
internal static readonly long InitialJavaScriptDateTicks = 621355968000000000;
/// <summary>
/// Converts the <see cref="DateTime"/> to its JSON string representation.
@@ -409,10 +394,10 @@ namespace Newtonsoft.Json
if (value == null)
return Null;
if (value is IConvertible)
{
IConvertible convertible = (IConvertible)value;
IConvertible convertible = value as IConvertible;
if (convertible != null)
{
switch (convertible.GetTypeCode())
{
case TypeCode.String:
@@ -502,12 +487,10 @@ namespace Newtonsoft.Json
if (value == null)
return true;
if (value is IConvertible)
{
IConvertible convertible = (IConvertible)value;
IConvertible convertible = value as IConvertible;
if (convertible != null)
return IsJsonPrimitiveTypeCode(convertible.GetTypeCode());
}
#if !PocketPC && !NET20
if (value is DateTimeOffset)
@@ -11,7 +11,7 @@ namespace Newtonsoft.Json
/// Instructs the <see cref="JsonSerializer"/> to use the specified <see cref="JsonConverter"/> when serializing the member or class.
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Class, AllowMultiple = false)]
public class JsonConverterAttribute : Attribute
public sealed class JsonConverterAttribute : Attribute
{
private readonly Type _converterType;
-3
View File
@@ -111,7 +111,6 @@ namespace Newtonsoft.Json
protected State CurrentState
{
get { return _currentState; }
private set { _currentState = value; }
}
private int _top;
@@ -172,10 +171,8 @@ namespace Newtonsoft.Json
/// </summary>
protected JsonReader()
{
//_testBuffer = new StringBuilder();
_currentState = State.Start;
_stack = new List<JTokenType>();
_top = 0;
Push(JTokenType.None);
}
+13 -5
View File
@@ -663,6 +663,7 @@ namespace Newtonsoft.Json
private void ParseNumber(char firstChar)
{
char currentChar = firstChar;
bool nonBase10 = (firstChar == '0');
// parse until seperator character or end
bool end = false;
@@ -684,16 +685,23 @@ namespace Newtonsoft.Json
object numberValue;
JsonToken numberType;
if (number.IndexOf(".", StringComparison.OrdinalIgnoreCase) == -1
&& number.IndexOf("e", StringComparison.OrdinalIgnoreCase) == -1)
if (number.IndexOf(".", StringComparison.OrdinalIgnoreCase) != -1
|| number.IndexOf("e", StringComparison.OrdinalIgnoreCase) != -1)
{
numberValue = Convert.ToInt64(number, CultureInfo.InvariantCulture);
numberValue = Convert.ToDouble(number, CultureInfo.InvariantCulture);
numberType = JsonToken.Float;
}
else if (nonBase10)
{
numberValue = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase)
? Convert.ToInt64(number, 16)
: Convert.ToInt64(number, 8);
numberType = JsonToken.Integer;
}
else
{
numberValue = Convert.ToDouble(number, CultureInfo.InvariantCulture);
numberType = JsonToken.Float;
numberValue = Convert.ToInt64(number, CultureInfo.InvariantCulture);
numberType = JsonToken.Integer;
}
_buffer.Position = 0;
-5
View File
@@ -291,12 +291,7 @@ namespace Newtonsoft.Json
if (value == null)
WriteValueInternal(JsonConvert.Null, JsonToken.Null);
else
{
JavaScriptUtils.WriteEscapedJavaScriptString(_writer, value, _quoteChar, true);
//_writer.Write(JavaScriptUtils.EscapeJavaScriptString(value, _quoteChar, false));
//WriteValueInternal(, JsonToken.String);
//JavaScriptUtils.WriteEscapedJavaScriptString(_writer, value, _quoteChar, true);
}
}
/// <summary>
+26
View File
@@ -61,5 +61,31 @@ namespace Newtonsoft.Json.Linq
{
get { return new JEnumerable<JToken>(Extensions.Values<T, JToken>(_enumerable, key)); }
}
/// <summary>
/// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
/// </summary>
/// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
/// <returns>
/// <c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
/// </returns>
public override bool Equals(object obj)
{
if (obj is JEnumerable<T>)
return _enumerable.Equals(((JEnumerable<T>)obj)._enumerable);
return false;
}
/// <summary>
/// Returns a hash code for this instance.
/// </summary>
/// <returns>
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
/// </returns>
public override int GetHashCode()
{
return _enumerable.GetHashCode();
}
}
}
@@ -79,21 +79,14 @@ namespace Newtonsoft.Json.Schema
private JsonSchemaResolver _resolver;
private IList<TypeSchema> _stack = new List<TypeSchema>();
private JsonSchema _currentSchema;
private Type _currentType;
private JsonSchema CurrentSchema
{
get { return _currentSchema; }
}
private Type CurrentType
{
get { return _currentType; }
}
private void Push(TypeSchema typeSchema)
{
_currentType = typeSchema.Type;
_currentSchema = typeSchema.Schema;
_stack.Add(typeSchema);
_resolver.LoadedSchemas.Add(typeSchema.Schema);
@@ -106,12 +99,10 @@ namespace Newtonsoft.Json.Schema
TypeSchema newValue = _stack.LastOrDefault();
if (newValue != null)
{
_currentType = newValue.Type;
_currentSchema = newValue.Schema;
}
else
{
_currentType = null;
_currentSchema = null;
}
@@ -97,18 +97,22 @@ namespace Newtonsoft.Json.Serialization
DataContractAttribute dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(objectType);
#endif
List<MemberInfo> defaultMembers = ReflectionUtils.GetFieldsAndProperties(objectType, DefaultMembersSearchFlags);
List<MemberInfo> allMembers = ReflectionUtils.GetFieldsAndProperties(objectType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
List<MemberInfo> defaultMembers = ReflectionUtils.GetFieldsAndProperties(objectType, DefaultMembersSearchFlags)
.Where(m => !ReflectionUtils.IsIndexedProperty(m)).ToList();
List<MemberInfo> allMembers = ReflectionUtils.GetFieldsAndProperties(objectType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)
.Where(m => !ReflectionUtils.IsIndexedProperty(m)).ToList();
List<MemberInfo> serializableMembers = new List<MemberInfo>();
foreach (MemberInfo member in allMembers)
{
if (defaultMembers.Contains(member))
{
// add all members that are found by default member search
serializableMembers.Add(member);
}
else
{
// add members that are explicitly marked with JsonProperty/DataMember attribute
if (JsonTypeReflector.GetAttribute<JsonPropertyAttribute>(member) != null)
serializableMembers.Add(member);
#if !PocketPC && !NET20
@@ -323,6 +327,11 @@ namespace Newtonsoft.Json.Serialization
{
return CreateObjectContract(objectType);
}
if (objectType.IsSubclassOf(typeof(JToken)))
{
return CreateLinqContract(objectType);
}
if (CollectionUtils.IsDictionaryType(objectType))
{
return CreateDictionaryContract(objectType);
@@ -331,10 +340,6 @@ namespace Newtonsoft.Json.Serialization
{
return CreateArrayContract(objectType);
}
if (objectType.IsSubclassOf(typeof(JToken)))
{
return CreateLinqContract(objectType);
}
return CreateObjectContract(objectType);
}
@@ -550,9 +550,15 @@ namespace Newtonsoft.Json.Utilities
foreach (var groupedMember in groupedMembers)
{
if (groupedMember.Count == 1)
{
distinctMembers.Add(groupedMember.Members.First());
}
else
distinctMembers.Add(groupedMember.Members.Where(m => !IsOverridenGenericMember(m, bindingAttr)).First());
{
var members = groupedMember.Members.Where(m => !IsOverridenGenericMember(m, bindingAttr) || m.Name == "Item");
distinctMembers.AddRange(members);
}
}
return distinctMembers;