-Improved error when serializing FileInfo/DirectoryInfo without ISerializable

This commit is contained in:
James Newton-King
2018-01-01 18:47:12 +13:00
parent eb85ba3f7c
commit 92fea48779
7 changed files with 150 additions and 31 deletions
@@ -28,7 +28,9 @@ using System;
using System.Data;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Utilities;
#if DNXCORE50
using Xunit;
using Test = Xunit.FactAttribute;
@@ -45,9 +47,13 @@ namespace Newtonsoft.Json.Tests.Issues
[Test]
public void Test()
{
Type t = typeof(FileSystemInfo);
Assert.IsTrue(t.ImplementInterface(typeof(ISerializable)));
DefaultContractResolver resolver = new DefaultContractResolver();
JsonContract contract = resolver.ResolveContract(typeof(DirectoryInfo));
JsonContract contract = resolver.ResolveContract(t);
Assert.AreEqual(JsonContractType.Object, contract.ContractType);
}
@@ -0,0 +1,76 @@
#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;
using System.IO;
#if DNXCORE50
using System.Reflection;
using Xunit;
using Test = Xunit.FactAttribute;
using Assert = Newtonsoft.Json.Tests.XUnitAssert;
#else
using NUnit.Framework;
#endif
namespace Newtonsoft.Json.Tests.Issues
{
[TestFixture]
public class Issue1541 : TestFixtureBase
{
#if DNXCORE50
[Test]
public void Test_DirectoryInfo()
{
FileInfo fileInfo = new FileInfo(TestFixtureBase.ResolvePath("large.json"));
ExceptionAssert.Throws<JsonSerializationException>(
() => JsonConvert.SerializeObject(fileInfo.Directory),
"Unable to serialize instance of 'System.IO.DirectoryInfo'.");
}
[Test]
public void Test_FileInfo()
{
FileInfo fileInfo = new FileInfo(TestFixtureBase.ResolvePath("large.json"));
ExceptionAssert.Throws<JsonSerializationException>(
() => JsonConvert.SerializeObject(fileInfo),
"Unable to serialize instance of 'System.IO.FileInfo'.");
}
#if !(NETSTANDARD1_0 || NETSTANDARD1_3)
[Test]
public void Test_DriveInfo()
{
DriveInfo drive = DriveInfo.GetDrives()[0];
ExceptionAssert.Throws<JsonSerializationException>(
() => JsonConvert.SerializeObject(drive),
"Unable to serialize instance of 'System.IO.DriveInfo'.");
}
#endif
#endif
}
}
@@ -51,7 +51,7 @@ namespace Newtonsoft.Json.Tests.Utilities
{
Type enumType = expected.GetType();
Enum result = (Enum)EnumUtils.ParseEnumName(value, false, false, enumType);
Enum result = (Enum)EnumUtils.ParseEnum(enumType, value, false);
Assert.AreEqual(expected, result);
}
@@ -63,7 +63,7 @@ namespace Newtonsoft.Json.Tests.Utilities
{
try
{
EnumUtils.ParseEnumName(value, false, false, enumType);
EnumUtils.ParseEnum(enumType, value, false);
}
catch (Exception ex) when (ex.GetType() == exceptionType)
{
@@ -138,7 +138,12 @@ namespace Newtonsoft.Json.Converters
{
string enumText = reader.Value.ToString();
return EnumUtils.ParseEnumName(enumText, isNullable, !AllowIntegerValues, t);
if (enumText == string.Empty && isNullable)
{
return null;
}
return EnumUtils.ParseEnum(t, enumText, !AllowIntegerValues);
}
if (reader.TokenType == JsonToken.Integer)
@@ -35,6 +35,7 @@ using System.ComponentModel;
using System.Dynamic;
#endif
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
#if HAVE_CAS
@@ -64,6 +65,13 @@ namespace Newtonsoft.Json.Serialization
// Json.NET Schema requires a property
internal static IContractResolver Instance => _instance;
private static readonly string[] BlacklistedTypeNames =
{
"System.IO.DriveInfo",
"System.IO.FileInfo",
"System.IO.DirectoryInfo"
};
private static readonly JsonConverter[] BuiltInConverters =
{
#if HAVE_ENTITY_FRAMEWORK
@@ -308,6 +316,13 @@ namespace Newtonsoft.Json.Serialization
/// <returns>A <see cref="JsonObjectContract"/> for the given type.</returns>
protected virtual JsonObjectContract CreateObjectContract(Type objectType)
{
// serializing DirectoryInfo without ISerializable will stackoverflow
// https://github.com/JamesNK/Newtonsoft.Json/issues/1541
if (Array.IndexOf(BlacklistedTypeNames, objectType.FullName) != -1)
{
throw new JsonSerializationException("Unable to serialize instance of '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
}
JsonObjectContract contract = new JsonObjectContract(objectType);
InitializeContract(contract);
+43
View File
@@ -0,0 +1,43 @@
#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
namespace Newtonsoft.Json.Utilities
{
internal class EnumInfo
{
public EnumInfo(bool isFlags, ulong[] values, string[] names, string[] resolvedNames)
{
IsFlags = isFlags;
Values = values;
Names = names;
ResolvedNames = resolvedNames;
}
public readonly bool IsFlags;
public readonly ulong[] Values;
public readonly string[] Names;
public readonly string[] ResolvedNames;
}
}
+1 -27
View File
@@ -113,16 +113,6 @@ namespace Newtonsoft.Json.Utilities
return selectedFlagsValues;
}
public static object ParseEnumName(string enumText, bool isNullable, bool disallowValue, Type t)
{
if (enumText == string.Empty && isNullable)
{
return null;
}
return ParseEnum(t, enumText, disallowValue);
}
public static bool TryToString(Type enumType, object value, bool camelCaseText, out string name)
{
EnumInfo enumInfo = ValuesAndNamesPerEnum.Get(enumType);
@@ -257,7 +247,7 @@ namespace Newtonsoft.Json.Utilities
}
}
private static object ParseEnum(Type enumType, string value, bool disallowNumber)
public static object ParseEnum(Type enumType, string value, bool disallowNumber)
{
ValidationUtils.ArgumentNotNull(enumType, nameof(enumType));
ValidationUtils.ArgumentNotNull(value, nameof(value));
@@ -406,20 +396,4 @@ namespace Newtonsoft.Json.Utilities
return null;
}
}
internal class EnumInfo
{
public EnumInfo(bool isFlags, ulong[] values, string[] names, string[] resolvedNames)
{
IsFlags = isFlags;
Values = values;
Names = names;
ResolvedNames = resolvedNames;
}
public readonly bool IsFlags;
public readonly ulong[] Values;
public readonly string[] Names;
public readonly string[] ResolvedNames;
}
}