-Added support for converting byte array JValues to Guid

-Added support for deserializing byte arrays to Guid
-Changed Guids to be serialized as binary UUID in BSON
-Changed JsonNet35BinaryCompatibility on BsonReader to be obsolete
This commit is contained in:
James Newton-King
2013-04-07 15:07:35 +12:00
parent 1abcfb1ace
commit 341656e7eb
11 changed files with 130 additions and 18 deletions
@@ -24,6 +24,7 @@
#endregion
using System;
using System.Collections.Generic;
using System.Globalization;
#if !(NET20 || NET35 || SILVERLIGHT || PORTABLE)
using System.Numerics;
@@ -94,6 +95,76 @@ namespace Newtonsoft.Json.Tests.Bson
Assert.AreEqual(JsonToken.None, reader.TokenType);
}
[Test]
public void ReadGuid_Text()
{
byte[] data = HexToBytes("31-00-00-00-02-30-00-25-00-00-00-64-38-32-31-65-65-64-37-2D-34-62-35-63-2D-34-33-63-39-2D-38-61-63-32-2D-36-39-32-38-65-35-37-39-62-37-30-35-00-00");
MemoryStream ms = new MemoryStream(data);
BsonReader reader = new BsonReader(ms);
reader.ReadRootValueAsArray = true;
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.String, reader.TokenType);
Assert.AreEqual("d821eed7-4b5c-43c9-8ac2-6928e579b705", reader.Value);
Assert.AreEqual(typeof(string), reader.ValueType);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
Assert.IsFalse(reader.Read());
Assert.AreEqual(JsonToken.None, reader.TokenType);
ms = new MemoryStream(data);
reader = new BsonReader(ms);
reader.ReadRootValueAsArray = true;
JsonSerializer serializer = new JsonSerializer();
IList<Guid> l = serializer.Deserialize<IList<Guid>>(reader);
Assert.AreEqual(1, l.Count);
Assert.AreEqual(new Guid("D821EED7-4B5C-43C9-8AC2-6928E579B705"), l[0]);
}
[Test]
public void ReadGuid_Bytes()
{
byte[] data = HexToBytes("1D-00-00-00-05-30-00-10-00-00-00-04-D7-EE-21-D8-5C-4B-C9-43-8A-C2-69-28-E5-79-B7-05-00");
MemoryStream ms = new MemoryStream(data);
BsonReader reader = new BsonReader(ms);
reader.ReadRootValueAsArray = true;
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
Guid g = new Guid("D821EED7-4B5C-43C9-8AC2-6928E579B705");
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.Bytes, reader.TokenType);
CollectionAssert.AreEqual(g.ToByteArray(), (byte[])reader.Value);
Assert.AreEqual(typeof(byte[]), reader.ValueType);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
Assert.IsFalse(reader.Read());
Assert.AreEqual(JsonToken.None, reader.TokenType);
ms = new MemoryStream(data);
reader = new BsonReader(ms);
reader.ReadRootValueAsArray = true;
JsonSerializer serializer = new JsonSerializer();
IList<Guid> l = serializer.Deserialize<IList<Guid>>(reader);
Assert.AreEqual(1, l.Count);
Assert.AreEqual(g, l[0]);
}
[Test]
public void ReadDouble()
{
@@ -128,6 +128,23 @@ namespace Newtonsoft.Json.Tests.Bson
Assert.AreEqual("10-00-00-00-01-30-00-8F-C2-F5-28-5C-FF-58-40-00", bson);
}
[Test]
public void WriteGuid()
{
Guid g = new Guid("D821EED7-4B5C-43C9-8AC2-6928E579B705");
MemoryStream ms = new MemoryStream();
BsonWriter writer = new BsonWriter(ms);
writer.WriteStartArray();
writer.WriteValue(g);
writer.WriteEnd();
string bson = BytesToHex(ms.ToArray());
Console.WriteLine(bson);
Assert.AreEqual("1D-00-00-00-05-30-00-10-00-00-00-04-D7-EE-21-D8-5C-4B-C9-43-8A-C2-69-28-E5-79-B7-05-00", bson);
}
[Test]
public void WriteArrayBsonFromSite()
{
@@ -319,6 +319,8 @@ namespace Newtonsoft.Json.Tests.Linq
Assert.AreEqual(null, (Uri)(new JValue((object)null)));
Assert.AreEqual(Convert.ToBase64String(Encoding.UTF8.GetBytes("hi")), (string)(new JValue(Encoding.UTF8.GetBytes("hi"))));
CollectionAssert.AreEquivalent((byte[])Encoding.UTF8.GetBytes("hi"), (byte[])(new JValue(Convert.ToBase64String(Encoding.UTF8.GetBytes("hi")))));
Assert.AreEqual(new Guid("46EFE013-B56A-4E83-99E4-4DCE7678A5BC"), (Guid)(new JValue(new Guid("46EFE013-B56A-4E83-99E4-4DCE7678A5BC").ToByteArray())));
Assert.AreEqual(new Guid("46EFE013-B56A-4E83-99E4-4DCE7678A5BC"), (Guid?)(new JValue(new Guid("46EFE013-B56A-4E83-99E4-4DCE7678A5BC").ToByteArray())));
Assert.AreEqual(null, (Uri)(JValue)null);
Assert.AreEqual(null, (int?)(JValue)null);
+4 -2
View File
@@ -32,8 +32,10 @@ namespace Newtonsoft.Json.Bson
Binary = 0x00,
Function = 0x01,
[Obsolete("This type has been deprecated in the BSON specification. Use Binary instead.")]
Data = 0x02,
Uuid = 0x03,
BinaryOld = 0x02,
[Obsolete("This type has been deprecated in the BSON specification. Use Uuid instead.")]
UuidOld = 0x03,
Uuid = 0x04,
Md5 = 0x05,
UserDefined = 0x80
}
+3 -3
View File
@@ -161,11 +161,11 @@ namespace Newtonsoft.Json.Bson
break;
case BsonType.Binary:
{
BsonValue value = (BsonValue)t;
BsonBinary value = (BsonBinary)t;
byte[] data = (byte[])value.Value;
_writer.Write(data.Length);
_writer.Write((byte)BsonBinaryType.Binary);
_writer.Write((byte)value.BinaryType);
_writer.Write(data);
}
break;
@@ -298,7 +298,7 @@ namespace Newtonsoft.Json.Bson
return 8;
case BsonType.Binary:
{
BsonValue value = (BsonValue)t;
BsonBinary value = (BsonBinary)t;
byte[] data = (byte[])value.Value;
value.CalculatedSize = 4 + 1 + data.Length;
+2 -1
View File
@@ -89,6 +89,7 @@ namespace Newtonsoft.Json.Bson
/// <value>
/// <c>true</c> if binary data reading will be compatible with incorrect Json.NET 3.5 written binary; otherwise, <c>false</c>.
/// </value>
[Obsolete("JsonNet35BinaryCompatibility will be removed in a future version of Json.NET.")]
public bool JsonNet35BinaryCompatibility
{
get { return _jsonNet35BinaryCompatibility; }
@@ -608,7 +609,7 @@ namespace Newtonsoft.Json.Bson
#pragma warning disable 612,618
// the old binary type has the data length repeated in the data for some reason
if (binaryType == BsonBinaryType.Data && !_jsonNet35BinaryCompatibility)
if (binaryType == BsonBinaryType.BinaryOld && !_jsonNet35BinaryCompatibility)
{
dataLength = ReadInt32();
}
+11
View File
@@ -121,6 +121,17 @@ namespace Newtonsoft.Json.Bson
}
}
internal class BsonBinary : BsonValue
{
public BsonBinaryType BinaryType { get; set; }
public BsonBinary(byte[] value, BsonBinaryType binaryType)
: base(value, BsonType.Binary)
{
BinaryType = binaryType;
}
}
internal class BsonRegex : BsonToken
{
public BsonString Pattern { get; set; }
+1 -1
View File
@@ -25,7 +25,7 @@
namespace Newtonsoft.Json.Bson
{
internal enum BsonType : sbyte
internal enum BsonType : sbyte
{
Number = 1,
String = 2,
+3 -3
View File
@@ -429,7 +429,7 @@ namespace Newtonsoft.Json.Bson
public override void WriteValue(byte[] value)
{
base.WriteValue(value);
AddValue(value, BsonType.Binary);
AddToken(new BsonBinary(value, BsonBinaryType.Binary));
}
/// <summary>
@@ -439,7 +439,7 @@ namespace Newtonsoft.Json.Bson
public override void WriteValue(Guid value)
{
base.WriteValue(value);
AddToken(new BsonString(value.ToString(), true));
AddToken(new BsonBinary(value.ToByteArray(), BsonBinaryType.Uuid));
}
/// <summary>
@@ -470,7 +470,7 @@ namespace Newtonsoft.Json.Bson
public override void WriteValue(BigInteger value)
{
base.WriteValue(value);
AddToken(new BsonValue(value.ToByteArray(), BsonType.Binary));
AddToken(new BsonBinary(value.ToByteArray(), BsonBinaryType.Binary));
}
#endif
#endregion
+8 -2
View File
@@ -69,7 +69,7 @@ namespace Newtonsoft.Json.Linq
private static readonly JTokenType[] NumberTypes = new[] { JTokenType.Integer, JTokenType.Float, JTokenType.String, JTokenType.Comment, JTokenType.Raw, JTokenType.Boolean };
private static readonly JTokenType[] BigIntegerTypes = new[] { JTokenType.Integer, JTokenType.Float, JTokenType.String, JTokenType.Comment, JTokenType.Raw, JTokenType.Boolean, JTokenType.Bytes };
private static readonly JTokenType[] StringTypes = new[] { JTokenType.Date, JTokenType.Integer, JTokenType.Float, JTokenType.String, JTokenType.Comment, JTokenType.Raw, JTokenType.Boolean, JTokenType.Bytes, JTokenType.Guid, JTokenType.TimeSpan, JTokenType.Uri };
private static readonly JTokenType[] GuidTypes = new[] { JTokenType.String, JTokenType.Comment, JTokenType.Raw, JTokenType.Guid };
private static readonly JTokenType[] GuidTypes = new[] { JTokenType.String, JTokenType.Comment, JTokenType.Raw, JTokenType.Guid, JTokenType.Bytes };
private static readonly JTokenType[] TimeSpanTypes = new[] { JTokenType.String, JTokenType.Comment, JTokenType.Raw, JTokenType.TimeSpan };
private static readonly JTokenType[] UriTypes = new[] { JTokenType.String, JTokenType.Comment, JTokenType.Raw, JTokenType.Uri };
private static readonly JTokenType[] CharTypes = new[] { JTokenType.Integer, JTokenType.Float, JTokenType.String, JTokenType.Comment, JTokenType.Raw };
@@ -1093,7 +1093,10 @@ namespace Newtonsoft.Json.Linq
if (v == null || !ValidateToken(v, GuidTypes, false))
throw new ArgumentException("Can not convert {0} to Guid.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
return (v.Value is Guid) ? (Guid)v.Value : new Guid(Convert.ToString(v.Value, CultureInfo.InvariantCulture));
if (v.Value is byte[])
return new Guid((byte[]) v.Value);
return (v.Value is Guid) ? (Guid) v.Value : new Guid(Convert.ToString(v.Value, CultureInfo.InvariantCulture));
}
/// <summary>
@@ -1113,6 +1116,9 @@ namespace Newtonsoft.Json.Linq
if (v.Value == null)
return null;
if (v.Value is byte[])
return new Guid((byte[])v.Value);
return (v.Value is Guid) ? (Guid)v.Value : new Guid(Convert.ToString(v.Value, CultureInfo.InvariantCulture));
}
@@ -371,17 +371,14 @@ namespace Newtonsoft.Json.Utilities
return System.Convert.ChangeType(initialValue, targetType, culture);
}
if (initialValue is string && typeof(Type).IsAssignableFrom(targetType))
return Type.GetType((string) initialValue, true);
if (targetType.IsInterface() || targetType.IsGenericTypeDefinition() || targetType.IsAbstract())
throw new ArgumentException("Target type {0} is not a value type or a non-abstract class.".FormatWith(CultureInfo.InvariantCulture, targetType), "targetType");
#if !NET20
if (initialValue is DateTime && targetType == typeof(DateTimeOffset))
return new DateTimeOffset((DateTime)initialValue);
#endif
if (initialValue is byte[] && targetType == typeof(Guid))
return new Guid((byte[]) initialValue);
if (initialValue is string)
{
if (targetType == typeof (Guid))
@@ -390,6 +387,8 @@ namespace Newtonsoft.Json.Utilities
return new Uri((string) initialValue, UriKind.RelativeOrAbsolute);
if (targetType == typeof(TimeSpan))
return ParseTimeSpan((string) initialValue);
if (typeof(Type).IsAssignableFrom(targetType))
return Type.GetType((string) initialValue, true);
}
#if !(NET20 || NET35 || SILVERLIGHT || PORTABLE40 || PORTABLE)
@@ -399,6 +398,9 @@ namespace Newtonsoft.Json.Utilities
return FromBigInteger((BigInteger)initialValue, targetType);
#endif
if (targetType.IsInterface() || targetType.IsGenericTypeDefinition() || targetType.IsAbstract())
throw new ArgumentException("Target type {0} is not a value type or a non-abstract class.".FormatWith(CultureInfo.InvariantCulture, targetType), "targetType");
#if !(NETFX_CORE || PORTABLE40 || PORTABLE)
// see if source or target types have a TypeConverter that converts between the two
TypeConverter toConverter = GetConverter(initialType);