-Added GetSchema, CanRead, CanWrite to JsonConverter

-Fix CustomCreationConverter erroring when writing JSON
This commit is contained in:
JamesNK
2010-02-06 22:55:36 +00:00
parent 992985bd7b
commit c7facae789
17 changed files with 223 additions and 38 deletions
+1 -1
View File
@@ -18,7 +18,7 @@
)
}
task default -depends Build
task default -depends Test
task Clean {
Set-Location $baseDir
+2 -1
View File
@@ -1 +1,2 @@
powershell -Command "& {Import-Module ..\Tools\PSake\psake.psm1; Invoke-psake .\build.ps1 %*}"
powershell -Command "& {Import-Module ..\Tools\PSake\psake.psm1; Invoke-psake .\build.ps1 %*}"
pause
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json.Converters;
using NUnit.Framework;
namespace Newtonsoft.Json.Tests.Converters
{
@@ -87,5 +88,62 @@ namespace Newtonsoft.Json.Tests.Converters
Console.WriteLine(employee.JobTitle);
// Support
}
public class MyClass
{
public string Value { get; set; }
[JsonConverter(typeof(MyThingConverter))]
public IThing Thing { get; set; }
}
public interface IThing
{
int Number { get; }
}
public class MyThing : IThing
{
public int Number { get; set; }
}
public class MyThingConverter : CustomCreationConverter<IThing>
{
public override IThing Create(Type objectType)
{
return new MyThing();
}
}
[Test]
public void AssertDoesDeserialize()
{
const string json = @"{
""Value"": ""A value"",
""Thing"": {
""Number"": 123
}
}
";
MyClass myClass = JsonConvert.DeserializeObject<MyClass>(json);
Assert.IsNotNull(myClass);
Assert.AreEqual("A value", myClass.Value);
Assert.IsNotNull(myClass.Thing);
Assert.AreEqual(123, myClass.Thing.Number);
}
[Test]
public void AssertShouldSerializeTest()
{
MyClass myClass = new MyClass
{
Value = "Foo",
Thing = new MyThing { Number = 456, }
};
string json = JsonConvert.SerializeObject(myClass); // <-- Exception here
const string expected = @"{""Value"":""Foo"",""Thing"":{""Number"":456}}";
Assert.AreEqual(expected, json);
}
}
}
@@ -0,0 +1,64 @@
#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
#if !SILVERLIGHT && !PocketPC
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using Newtonsoft.Json.Converters;
using NUnit.Framework;
namespace Newtonsoft.Json.Tests.Converters
{
public class HtmlColorConverterTests : TestFixtureBase
{
[Test]
public void WriteJsonTest()
{
string json;
json = JsonConvert.SerializeObject(Color.DarkGray, new HtmlColorConverter());
Assert.AreEqual(@"""DarkGray""", json);
json = JsonConvert.SerializeObject(Color.FromArgb(255, 1, 2, 3), new HtmlColorConverter());
Assert.AreEqual(@"""#010203""", json);
}
[Test]
public void ReadJsonTest()
{
string json = @"""#010203""";
Color c = JsonConvert.DeserializeObject<Color>(json, new HtmlColorConverter());
Assert.AreEqual(c.A, 255);
Assert.AreEqual(c.R, 1);
Assert.AreEqual(c.G, 2);
Assert.AreEqual(c.B, 3);
}
}
}
#endif
@@ -62,8 +62,10 @@
<Compile Include="Bson\BsonReaderTests.cs" />
<Compile Include="Bson\BsonWriterTests.cs" />
<Compile Include="Converters\BinaryConverterTests.cs" />
<Compile Include="Converters\CustomCreationConverterTests.cs" />
<Compile Include="Converters\DataSetConverterTests.cs" />
<Compile Include="Converters\DataTableConverterTests.cs" />
<Compile Include="Converters\HtmlColorConverterTests.cs" />
<Compile Include="Converters\StringEnumConverterTests.cs" />
<Compile Include="Linq\ComponentModel\BindingTests.cs" />
<Compile Include="Linq\ComponentModel\JPropertyDescriptorTests.cs" />
@@ -57,6 +57,7 @@
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Security" />
<Reference Include="System.Web" />
<Reference Include="System.Xml" />
@@ -68,6 +69,7 @@
<Compile Include="Converters\CustomCreationConverterTests.cs" />
<Compile Include="Converters\DataSetConverterTests.cs" />
<Compile Include="Converters\DataTableConverterTests.cs" />
<Compile Include="Converters\HtmlColorConverterTests.cs" />
<Compile Include="Converters\StringEnumConverterTests.cs" />
<Compile Include="JsonArrayAttributeTests.cs" />
<Compile Include="ExceptionTests.cs" />
@@ -71,8 +71,10 @@
<Compile Include="Bson\BsonReaderTests.cs" />
<Compile Include="Bson\BsonWriterTests.cs" />
<Compile Include="Converters\BinaryConverterTests.cs" />
<Compile Include="Converters\CustomCreationConverterTests.cs" />
<Compile Include="Converters\DataSetConverterTests.cs" />
<Compile Include="Converters\DataTableConverterTests.cs" />
<Compile Include="Converters\HtmlColorConverterTests.cs" />
<Compile Include="Converters\StringEnumConverterTests.cs" />
<Compile Include="ExceptionTests.cs" />
<Compile Include="JsonArrayAttributeTests.cs" />
@@ -63,6 +63,7 @@
<Reference Include="System.Data.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Runtime.Serialization">
<RequiredTargetFramework>3.0</RequiredTargetFramework>
</Reference>
@@ -89,6 +90,7 @@
<Compile Include="Converters\DataTableConverterTests.cs" />
<Compile Include="Converters\DataSetConverterTests.cs" />
<Compile Include="Converters\CustomCreationConverterTests.cs" />
<Compile Include="Converters\HtmlColorConverterTests.cs" />
<Compile Include="Converters\StringEnumConverterTests.cs" />
<Compile Include="FileSystemEntityModel.Designer.cs">
<AutoGen>True</AutoGen>
@@ -79,5 +79,16 @@ namespace Newtonsoft.Json.Converters
{
return typeof (T).IsAssignableFrom(objectType);
}
/// <summary>
/// Gets a value indicating whether this <see cref="JsonConverter"/> can write JSON.
/// </summary>
/// <value>
/// <c>true</c> if this <see cref="JsonConverter"/> can write JSON; otherwise, <c>false</c>.
/// </value>
public override bool CanWrite
{
get { return false; }
}
}
}
@@ -68,6 +68,17 @@ namespace Newtonsoft.Json.Converters
{
throw new NotImplementedException();
}
/// <summary>
/// Gets a value indicating whether this <see cref="JsonConverter"/> can read JSON.
/// </summary>
/// <value>
/// <c>true</c> if this <see cref="JsonConverter"/> can read JSON; otherwise, <c>false</c>.
/// </value>
public override bool CanRead
{
get { return false; }
}
}
}
#endif
+28
View File
@@ -27,6 +27,7 @@ using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json.Utilities;
using Newtonsoft.Json.Schema;
namespace Newtonsoft.Json
{
@@ -60,5 +61,32 @@ namespace Newtonsoft.Json
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
/// </returns>
public abstract bool CanConvert(Type objectType);
/// <summary>
/// Gets the <see cref="JsonSchema"/> of the JSON produced by the JsonConverter.
/// </summary>
/// <returns>The <see cref="JsonSchema"/> of the JSON produced by the JsonConverter.</returns>
public virtual JsonSchema GetSchema()
{
return null;
}
/// <summary>
/// Gets a value indicating whether this <see cref="JsonConverter"/> can read JSON.
/// </summary>
/// <value><c>true</c> if this <see cref="JsonConverter"/> can read JSON; otherwise, <c>false</c>.</value>
public virtual bool CanRead
{
get { return true; }
}
/// <summary>
/// Gets a value indicating whether this <see cref="JsonConverter"/> can write JSON.
/// </summary>
/// <value><c>true</c> if this <see cref="JsonConverter"/> can write JSON; otherwise, <c>false</c>.</value>
public virtual bool CanWrite
{
get { return true; }
}
}
}
+6 -14
View File
@@ -432,18 +432,14 @@ namespace Newtonsoft.Json
serializerWriter.Serialize(jsonWriter, value);
}
internal bool HasMatchingConverter(Type type, out JsonConverter matchingConverter)
internal JsonConverter GetMatchingConverter(Type type)
{
if (HasMatchingConverter(_converters, type, out matchingConverter))
return true;
return false;
return GetMatchingConverter(_converters, type);
}
internal static bool HasMatchingConverter(IList<JsonConverter> converters, Type objectType, out JsonConverter matchingConverter)
internal static JsonConverter GetMatchingConverter(IList<JsonConverter> converters, Type objectType)
{
if (objectType == null)
throw new ArgumentNullException("objectType");
ValidationUtils.ArgumentNotNull(objectType, "objectType");
if (converters != null)
{
@@ -452,15 +448,11 @@ namespace Newtonsoft.Json
JsonConverter converter = converters[i];
if (converter.CanConvert(objectType))
{
matchingConverter = converter;
return true;
}
return converter;
}
}
matchingConverter = null;
return false;
return null;
}
internal void OnError(ErrorEventArgs e)
+1 -1
View File
@@ -273,7 +273,7 @@ namespace Newtonsoft.Json.Linq
{
JsonConverter matchingConverter;
if (value != null && JsonSerializer.HasMatchingConverter(converters, value.GetType(), out matchingConverter))
if (value != null && ((matchingConverter = JsonSerializer.GetMatchingConverter(converters, value.GetType())) != null))
matchingConverter.WriteJson(writer, value, new JsonSerializer());
else
defaultWrite(value);
@@ -234,6 +234,15 @@ namespace Newtonsoft.Json.Schema
throw new Exception("Unresolved circular reference for type '{0}'. Explicitly define an Id for the type using a JsonObject/JsonArray attribute or automatically generate a type Id using the UndefinedSchemaIdHandling property.".FormatWith(CultureInfo.InvariantCulture, type));
}
JsonContract contract = ContractResolver.ResolveContract(type);
JsonConverter converter;
if ((converter = contract.Converter) != null || (converter = contract.InternalConverter) != null)
{
JsonSchema converterSchema = converter.GetSchema();
if (converterSchema != null)
return converterSchema;
}
Push(new TypeSchema(type, new JsonSchema()));
if (explicitId != null)
@@ -244,8 +253,7 @@ namespace Newtonsoft.Json.Schema
CurrentSchema.Title = GetTitle(type);
CurrentSchema.Description = GetDescription(type);
JsonContract contract = ContractResolver.ResolveContract(type);
if (contract.Converter != null || contract.InternalConverter != null)
if (converter != null)
{
// todo: Add GetSchema to JsonConverter and use here?
CurrentSchema.Type = JsonSchemaType.Any;
@@ -204,9 +204,7 @@ namespace Newtonsoft.Json.Serialization
contract.Converter = ResolveContractConverter(contract.UnderlyingType);
// then see whether object is compadible with any of the built in converters
JsonConverter internalConverter;
if (JsonSerializer.HasMatchingConverter(BuiltInConverters, contract.UnderlyingType, out internalConverter))
contract.InternalConverter = internalConverter;
contract.InternalConverter = JsonSerializer.GetMatchingConverter(BuiltInConverters, contract.UnderlyingType);
if (ReflectionUtils.HasDefaultConstructor(contract.CreatedType, true)
|| contract.CreatedType.IsValueType)
@@ -179,24 +179,29 @@ namespace Newtonsoft.Json.Serialization
private object CreateValue(JsonReader reader, Type objectType, JsonContract contract, object existingValue, JsonConverter memberConverter)
{
JsonConverter converter;
// member attribute converter
JsonConverter converter = null;
if (memberConverter != null)
return memberConverter.ReadJson(reader, objectType, GetInternalSerializer());
{
// member attribute converter
converter = memberConverter;
}
else if (contract != null)
{
JsonConverter matchingConverter;
if (contract.Converter != null)
// class attribute converter
converter = contract.Converter;
else if ((matchingConverter = Serializer.GetMatchingConverter(contract.UnderlyingType)) != null)
// passed in converters
converter = matchingConverter;
else if (contract.InternalConverter != null)
// internally specified converter
converter = contract.InternalConverter;
}
// class attribute converter
if (contract != null && contract.Converter != null)
return contract.Converter.ReadJson(reader, objectType, GetInternalSerializer());
// passed in converters
if (objectType != null && Serializer.HasMatchingConverter(objectType, out converter))
if (converter != null && converter.CanRead)
return converter.ReadJson(reader, objectType, GetInternalSerializer());
// internally specified converter
if (contract != null && contract.InternalConverter != null)
return contract.InternalConverter.ReadJson(reader, objectType, GetInternalSerializer());
if (contract is JsonLinqContract)
return CreateJToken(reader, contract);
@@ -90,10 +90,11 @@ namespace Newtonsoft.Json.Serialization
return;
}
if (converter != null
if ((converter != null
|| ((converter = contract.Converter) != null)
|| Serializer.HasMatchingConverter(contract.UnderlyingType, out converter)
|| ((converter = Serializer.GetMatchingConverter(contract.UnderlyingType)) != null)
|| ((converter = contract.InternalConverter) != null))
&& converter.CanWrite)
{
SerializeConvertable(writer, converter, value, contract);
}