-Fixed serializing discriminated unions with type name or reference tracking enabled
-Fixed build
This commit is contained in:
@@ -57,4 +57,4 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("7.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("7.0.1.18304")]
|
||||
[assembly: AssemblyFileVersion("7.0.1.18321")]
|
||||
|
||||
@@ -23,11 +23,11 @@
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
#if !(NET35 || NET20 || NETFX_CORE || ASPNETCORE50)
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using Microsoft.FSharp.Core;
|
||||
using Microsoft.FSharp.Reflection;
|
||||
#if !(NET35 || NET20 || NETFX_CORE || ASPNETCORE50)
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -283,6 +283,28 @@ namespace Newtonsoft.Json.Tests.Converters
|
||||
{
|
||||
ExceptionAssert.Throws<JsonSerializationException>(() => JsonConvert.DeserializeObject<Currency>(@"{""Case123"":""AUD""}"), "Unexpected property 'Case123' found when reading union. Path 'Case123', line 1, position 11.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeUnionWithTypeNameHandlingAndReferenceTracking()
|
||||
{
|
||||
string json = JsonConvert.SerializeObject(Shape.NewRectangle(10.0, 5.0), new JsonSerializerSettings
|
||||
{
|
||||
PreserveReferencesHandling = PreserveReferencesHandling.All,
|
||||
TypeNameHandling = TypeNameHandling.All
|
||||
});
|
||||
|
||||
Console.WriteLine(json);
|
||||
|
||||
Assert.AreEqual(@"{""Case"":""Rectangle"",""Fields"":[10.0,5.0]}", json);
|
||||
|
||||
Shape c = JsonConvert.DeserializeObject<Shape>(json);
|
||||
Assert.AreEqual(true, c.IsRectangle);
|
||||
|
||||
Shape.Rectangle r = (Shape.Rectangle)c;
|
||||
|
||||
Assert.AreEqual(5.0, r.length);
|
||||
Assert.AreEqual(10.0, r.width);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -76,4 +76,4 @@ using System.Security;
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly: AssemblyVersion("7.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("7.0.1.18304")]
|
||||
[assembly: AssemblyFileVersion("7.0.1.18321")]
|
||||
|
||||
@@ -57,9 +57,9 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
private readonly char _startingWithChar;
|
||||
|
||||
public DynamicContractResolver(char startingWithChar)
|
||||
#pragma warning disable 612
|
||||
#pragma warning disable 612,618
|
||||
: base(false)
|
||||
#pragma warning restore 612
|
||||
#pragma warning restore 612,618
|
||||
{
|
||||
_startingWithChar = startingWithChar;
|
||||
}
|
||||
|
||||
@@ -3879,6 +3879,7 @@ Path '', line 1, position 1.");
|
||||
}", json);
|
||||
}
|
||||
|
||||
#if !NET20
|
||||
public class DateTimeOffsetWrapper
|
||||
{
|
||||
public DateTimeOffset DateTimeOffsetValue { get; set; }
|
||||
@@ -3907,6 +3908,7 @@ Path '', line 1, position 1.");
|
||||
|
||||
Assert.AreEqual(c.DateTimeOffsetValue, cISO.DateTimeOffsetValue);
|
||||
}
|
||||
#endif
|
||||
|
||||
[Test]
|
||||
public void CircularConstructorDeserialize()
|
||||
@@ -8684,6 +8686,7 @@ Path '', line 1, position 1.");
|
||||
Assert.AreEqual("derived", d.DerivedProperty);
|
||||
}
|
||||
|
||||
#if !(NET20 || NET35 || PORTABLE || PORTABLE40)
|
||||
[Test]
|
||||
public void DeserializeNullableUnsignedLong()
|
||||
{
|
||||
@@ -8705,6 +8708,7 @@ Path '', line 1, position 1.");
|
||||
set;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !NETFX_CORE
|
||||
[Test]
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace Newtonsoft.Json.Converters
|
||||
internal class Union
|
||||
{
|
||||
public List<UnionCase> Cases;
|
||||
public Converter<object, int> TagReader { get; set; }
|
||||
public FSharpFunction TagReader { get; set; }
|
||||
}
|
||||
|
||||
internal class UnionCase
|
||||
@@ -57,8 +57,8 @@ namespace Newtonsoft.Json.Converters
|
||||
public int Tag;
|
||||
public string Name;
|
||||
public PropertyInfo[] Fields;
|
||||
public Converter<object, object[]> FieldReader;
|
||||
public Converter<object[], object> Constructor;
|
||||
public FSharpFunction FieldReader;
|
||||
public FSharpFunction Constructor;
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace Newtonsoft.Json.Converters
|
||||
{
|
||||
Union u = new Union();
|
||||
|
||||
u.TagReader = (Converter<object, int>)FSharpUtils.PreComputeUnionTagReader(null, t, null);
|
||||
u.TagReader = (FSharpFunction)FSharpUtils.PreComputeUnionTagReader(null, t, null);
|
||||
u.Cases = new List<UnionCase>();
|
||||
|
||||
object[] cases = (object[])FSharpUtils.GetUnionCases(null, t, null);
|
||||
@@ -97,8 +97,8 @@ namespace Newtonsoft.Json.Converters
|
||||
unionCase.Tag = (int)FSharpUtils.GetUnionCaseInfoTag(unionCaseInfo);
|
||||
unionCase.Name = (string)FSharpUtils.GetUnionCaseInfoName(unionCaseInfo);
|
||||
unionCase.Fields = (PropertyInfo[])FSharpUtils.GetUnionCaseInfoFields(unionCaseInfo);
|
||||
unionCase.FieldReader = (Converter<object, object[]>)FSharpUtils.PreComputeUnionReader(null, unionCaseInfo, null);
|
||||
unionCase.Constructor = (Converter<object[], object>)FSharpUtils.PreComputeUnionConstructor(null, unionCaseInfo, null);
|
||||
unionCase.FieldReader = (FSharpFunction)FSharpUtils.PreComputeUnionReader(null, unionCaseInfo, null);
|
||||
unionCase.Constructor = (FSharpFunction)FSharpUtils.PreComputeUnionConstructor(null, unionCaseInfo, null);
|
||||
|
||||
u.Cases.Add(unionCase);
|
||||
}
|
||||
@@ -119,7 +119,7 @@ namespace Newtonsoft.Json.Converters
|
||||
Type unionType = UnionTypeLookupCache.Get(value.GetType());
|
||||
Union union = UnionCache.Get(unionType);
|
||||
|
||||
int tag = union.TagReader(value);
|
||||
int tag = (int)union.TagReader.Invoke(value);
|
||||
UnionCase caseInfo = union.Cases.Single(c => c.Tag == tag);
|
||||
|
||||
writer.WriteStartObject();
|
||||
@@ -127,10 +127,15 @@ namespace Newtonsoft.Json.Converters
|
||||
writer.WriteValue(caseInfo.Name);
|
||||
if (caseInfo.Fields != null && caseInfo.Fields.Length > 0)
|
||||
{
|
||||
object[] fields = caseInfo.FieldReader(value);
|
||||
object[] fields = (object[])caseInfo.FieldReader.Invoke(value);
|
||||
|
||||
writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(FieldsPropertyName) : FieldsPropertyName);
|
||||
serializer.Serialize(writer, fields);
|
||||
writer.WriteStartArray();
|
||||
foreach (object field in fields)
|
||||
{
|
||||
serializer.Serialize(writer, field);
|
||||
}
|
||||
writer.WriteEndArray();
|
||||
}
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
@@ -210,7 +215,9 @@ namespace Newtonsoft.Json.Converters
|
||||
}
|
||||
}
|
||||
|
||||
return caseInfo.Constructor(typedFieldValues);
|
||||
object[] args = { typedFieldValues };
|
||||
|
||||
return caseInfo.Constructor.Invoke(args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -139,9 +139,13 @@ namespace Newtonsoft.Json.Converters
|
||||
#if !NET20
|
||||
if (t == typeof(DateTimeOffset))
|
||||
return (reader.Value is DateTimeOffset) ? reader.Value : new DateTimeOffset((DateTime)reader.Value);
|
||||
|
||||
// converter is expected to return a DateTime
|
||||
if (reader.Value is DateTimeOffset)
|
||||
return ((DateTimeOffset)reader.Value).DateTime;
|
||||
#endif
|
||||
|
||||
return (reader.Value is DateTime) ? reader.Value : ((DateTimeOffset)reader.Value).DateTime;
|
||||
return reader.Value;
|
||||
}
|
||||
|
||||
if (reader.TokenType != JsonToken.String)
|
||||
|
||||
@@ -23,8 +23,10 @@
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
using System.Numerics;
|
||||
#if !PORTABLE40
|
||||
#if !(PORTABLE || NET20 || NET35)
|
||||
using System.Numerics;
|
||||
#endif
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
||||
@@ -92,5 +92,5 @@ using System.Security;
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly: AssemblyVersion("7.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("7.0.1.18304")]
|
||||
[assembly: AssemblyFileVersion("7.0.1.18321")]
|
||||
[assembly: CLSCompliant(true)]
|
||||
|
||||
@@ -37,9 +37,9 @@ namespace Newtonsoft.Json.Serialization
|
||||
/// Initializes a new instance of the <see cref="CamelCasePropertyNamesContractResolver"/> class.
|
||||
/// </summary>
|
||||
public CamelCasePropertyNamesContractResolver()
|
||||
#pragma warning disable 612
|
||||
#pragma warning disable 612,618
|
||||
: base(true)
|
||||
#pragma warning restore 612
|
||||
#pragma warning restore 612,618
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -95,9 +95,9 @@ namespace Newtonsoft.Json.Serialization
|
||||
/// </summary>
|
||||
public class DefaultContractResolver : IContractResolver
|
||||
{
|
||||
#pragma warning disable 612
|
||||
#pragma warning disable 612,618
|
||||
private static readonly IContractResolver _instance = new DefaultContractResolver(true);
|
||||
#pragma warning restore 612
|
||||
#pragma warning restore 612,618
|
||||
|
||||
internal static IContractResolver Instance
|
||||
{
|
||||
|
||||
@@ -34,6 +34,25 @@ using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
internal class FSharpFunction
|
||||
{
|
||||
private readonly object _instance;
|
||||
private readonly MethodCall<object, object> _invoker;
|
||||
|
||||
public FSharpFunction(object instance, MethodCall<object, object> invoker)
|
||||
{
|
||||
_instance = instance;
|
||||
_invoker = invoker;
|
||||
}
|
||||
|
||||
public object Invoke(params object[] args)
|
||||
{
|
||||
object o = _invoker(_instance, args);
|
||||
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
internal static class FSharpUtils
|
||||
{
|
||||
private static readonly object Lock = new object();
|
||||
@@ -105,19 +124,20 @@ namespace Newtonsoft.Json.Utilities
|
||||
private static MethodCall<object, object> CreateFSharpFuncCall(Type type, string methodName)
|
||||
{
|
||||
MethodInfo innerMethodInfo = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static);
|
||||
MethodInfo toConvertMethodInfo = innerMethodInfo.ReturnType.GetMethod("ToConverter", BindingFlags.Public | BindingFlags.Static);
|
||||
MethodInfo invokeFunc = innerMethodInfo.ReturnType.GetMethod("Invoke", BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
MethodCall<object, object> inner = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(innerMethodInfo);
|
||||
MethodCall<object, object> toConvert = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(toConvertMethodInfo);
|
||||
MethodCall<object, object> call = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(innerMethodInfo);
|
||||
MethodCall<object, object> invoke = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(invokeFunc);
|
||||
|
||||
MethodCall<object, object> methodCall = (target, args) =>
|
||||
MethodCall<object, object> createFunction = (target, args) =>
|
||||
{
|
||||
object result = inner(target, args);
|
||||
object result = call(target, args);
|
||||
|
||||
return toConvert(null, result);
|
||||
FSharpFunction f = new FSharpFunction(result, invoke);
|
||||
return f;
|
||||
};
|
||||
|
||||
return methodCall;
|
||||
return createFunction;
|
||||
}
|
||||
|
||||
public static ObjectConstructor<object> CreateSeq(Type t)
|
||||
|
||||
Reference in New Issue
Block a user