diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
index 3a2e9352..b0bff76e 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
@@ -235,6 +235,7 @@
+
diff --git a/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs
index ce2e34ad..5dd5c424 100644
--- a/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs
@@ -108,6 +108,155 @@ namespace Newtonsoft.Json.Tests.Serialization
[TestFixture]
public class ContractResolverTests : TestFixtureBase
{
+ [Test]
+ public void ListInterface()
+ {
+ var resolver = new DefaultContractResolver();
+ var contract = (JsonArrayContract)resolver.ResolveContract(typeof(IList));
+
+ Assert.IsTrue(contract.IsInstantiable);
+ Assert.AreEqual(typeof(List), contract.CreatedType);
+ Assert.IsNotNull(contract.DefaultCreator);
+ }
+
+ [Test]
+ public void AbstractTestClass()
+ {
+ var resolver = new DefaultContractResolver();
+ var contract = (JsonObjectContract)resolver.ResolveContract(typeof(AbstractTestClass));
+
+ Assert.IsFalse(contract.IsInstantiable);
+ Assert.IsNull(contract.DefaultCreator);
+ Assert.IsNull(contract.OverrideCreator);
+
+ ExceptionAssert.Throws(
+ "Could not create an instance of type Newtonsoft.Json.Tests.Serialization.AbstractTestClass. Type is an interface or abstract class and cannot be instantiated. Path 'Value', line 1, position 7.",
+ () => JsonConvert.DeserializeObject(@"{Value:'Value!'}", new JsonSerializerSettings
+ {
+ ContractResolver = resolver
+ }));
+
+ contract.DefaultCreator = () => new AbstractImplementationTestClass();
+
+ var o = JsonConvert.DeserializeObject(@"{Value:'Value!'}", new JsonSerializerSettings
+ {
+ ContractResolver = resolver
+ });
+
+ Assert.AreEqual("Value!", o.Value);
+ }
+
+ [Test]
+ public void AbstractListTestClass()
+ {
+ var resolver = new DefaultContractResolver();
+ var contract = (JsonArrayContract)resolver.ResolveContract(typeof(AbstractListTestClass));
+
+ Assert.IsFalse(contract.IsInstantiable);
+ Assert.IsNull(contract.DefaultCreator);
+ Assert.IsNull(contract.ParametrizedCreator);
+
+ ExceptionAssert.Throws(
+ "Could not create an instance of type Newtonsoft.Json.Tests.Serialization.AbstractListTestClass`1[System.Int32]. Type is an interface or abstract class and cannot be instantiated. Path '', line 1, position 1.",
+ () => JsonConvert.DeserializeObject>(@"[1,2]", new JsonSerializerSettings
+ {
+ ContractResolver = resolver
+ }));
+
+ contract.DefaultCreator = () => new AbstractImplementationListTestClass();
+
+ var l = JsonConvert.DeserializeObject>(@"[1,2]", new JsonSerializerSettings
+ {
+ ContractResolver = resolver
+ });
+
+ Assert.AreEqual(2, l.Count);
+ Assert.AreEqual(1, l[0]);
+ Assert.AreEqual(2, l[1]);
+ }
+
+ public class CustomList : List
+ {
+ }
+
+ [Test]
+ public void ListInterfaceDefaultCreator()
+ {
+ var resolver = new DefaultContractResolver();
+ var contract = (JsonArrayContract)resolver.ResolveContract(typeof(IList));
+
+ Assert.IsTrue(contract.IsInstantiable);
+ Assert.IsNotNull(contract.DefaultCreator);
+
+ contract.DefaultCreator = () => new CustomList();
+
+ var l = JsonConvert.DeserializeObject>(@"[1,2,3]", new JsonSerializerSettings
+ {
+ ContractResolver = resolver
+ });
+
+ Assert.AreEqual(typeof(CustomList), l.GetType());
+ Assert.AreEqual(3, l.Count);
+ Assert.AreEqual(1, l[0]);
+ Assert.AreEqual(2, l[1]);
+ Assert.AreEqual(3, l[2]);
+ }
+
+ public class CustomDictionary : Dictionary
+ {
+ }
+
+ [Test]
+ public void DictionaryInterfaceDefaultCreator()
+ {
+ var resolver = new DefaultContractResolver();
+ var contract = (JsonDictionaryContract)resolver.ResolveContract(typeof(IDictionary));
+
+ Assert.IsTrue(contract.IsInstantiable);
+ Assert.IsNotNull(contract.DefaultCreator);
+
+ contract.DefaultCreator = () => new CustomDictionary();
+
+ var d = JsonConvert.DeserializeObject>(@"{key1:1,key2:2}", new JsonSerializerSettings
+ {
+ ContractResolver = resolver
+ });
+
+ Assert.AreEqual(typeof(CustomDictionary), d.GetType());
+ Assert.AreEqual(2, d.Count);
+ Assert.AreEqual(1, d["key1"]);
+ Assert.AreEqual(2, d["key2"]);
+ }
+
+ [Test]
+ public void AbstractDictionaryTestClass()
+ {
+ var resolver = new DefaultContractResolver();
+ var contract = (JsonDictionaryContract)resolver.ResolveContract(typeof(AbstractDictionaryTestClass));
+
+ Assert.IsFalse(contract.IsInstantiable);
+ Assert.IsNull(contract.DefaultCreator);
+ Assert.IsNull(contract.ParametrizedCreator);
+
+ ExceptionAssert.Throws(
+ "Could not create an instance of type Newtonsoft.Json.Tests.Serialization.AbstractDictionaryTestClass`2[System.String,System.Int32]. Type is an interface or abstract class and cannot be instantiated. Path 'key1', line 1, position 6.",
+ () => JsonConvert.DeserializeObject>(@"{key1:1,key2:2}", new JsonSerializerSettings
+ {
+ ContractResolver = resolver
+ }));
+
+ contract.DefaultCreator = () => new AbstractImplementationDictionaryTestClass();
+
+ var d = JsonConvert.DeserializeObject>(@"{key1:1,key2:2}", new JsonSerializerSettings
+ {
+ ContractResolver = resolver
+ });
+
+ Assert.AreEqual(2, d.Count);
+ Assert.AreEqual(1, d["key1"]);
+ Assert.AreEqual(2, d["key2"]);
+ }
+
[Test]
public void SerializeWithEscapedPropertyName()
{
diff --git a/Src/Newtonsoft.Json.Tests/Serialization/DynamicConcreteTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/DynamicConcreteTests.cs
new file mode 100644
index 00000000..adcdf329
--- /dev/null
+++ b/Src/Newtonsoft.Json.Tests/Serialization/DynamicConcreteTests.cs
@@ -0,0 +1,281 @@
+#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.Reflection;
+using System.Reflection.Emit;
+using Newtonsoft.Json.Serialization;
+using Newtonsoft.Json.Tests.TestObjects;
+using System;
+using System.Linq;
+
+#if !NETFX_CORE
+using NUnit.Framework;
+#else
+using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
+using TestFixture = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestClassAttribute;
+using Test = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestMethodAttribute;
+#endif
+
+namespace Newtonsoft.Json.Tests.Serialization
+{
+ [TestFixture]
+ public class DynamicConcreteTests : TestFixtureBase
+ {
+ [Test]
+ public void UseDynamicConcreteIfTargetObjectTypeIsAnInterfaceWithNoBackingClass()
+ {
+ string json = @"{Name:""Name!""}";
+
+ var c = JsonConvert.DeserializeObject(json, new JsonSerializerSettings
+ {
+ ContractResolver = new DynamicConcreteContractResolver()
+ });
+
+ Assert.AreEqual("Name!", c.Name);
+ }
+
+ [Test]
+ public void UseDynamicConcreteIfTargetObjectTypeIsAnAbstractClassWithNoConcrete()
+ {
+ string json = @"{Name:""Name!"", Game:""Same""}";
+
+ var c = JsonConvert.DeserializeObject(json, new JsonSerializerSettings
+ {
+ ContractResolver = new DynamicConcreteContractResolver()
+ });
+
+ Assert.AreEqual("Name!", c.Name);
+ Assert.AreEqual("Same", c.Game);
+ }
+
+ [Test]
+ public void AnyMethodsExposedByDynamicConcreteAreHarmless()
+ {
+ string json = @"{Name:""Name!""}";
+
+ var c = JsonConvert.DeserializeObject(json, new JsonSerializerSettings
+ {
+ ContractResolver = new DynamicConcreteContractResolver()
+ });
+
+ c.FuncWithRefType(10, null);
+ c.FuncWithValType_1();
+ c.FuncWithValType_2();
+ }
+ }
+
+ public abstract class AbstractWithNoConcrete
+ {
+ public string Name { get; set; }
+ public abstract string Game { get; set; }
+ }
+
+ public interface IInterfaceWithNoConcrete
+ {
+ string Name { get; set; }
+ object FuncWithRefType(int a, object b);
+ int FuncWithValType_1();
+ bool FuncWithValType_2();
+ }
+
+ public class DynamicConcreteContractResolver : DefaultContractResolver
+ {
+ protected override JsonContract CreateContract(Type objectType)
+ {
+ JsonContract contract = base.CreateContract(objectType);
+ if (contract.CreatedType.IsAbstract || contract.CreatedType.IsInterface)
+ contract.DefaultCreator = () => DynamicConcrete.GetInstanceFor(contract.CreatedType);
+
+ return contract;
+ }
+ }
+
+ ///
+ /// Creates run-time backing types for abstract classes and interfaces
+ ///
+ public static class DynamicConcrete
+ {
+ ///
+ /// Get an empty instance of a dynamic proxy for type T.
+ /// All public fields are writable and all properties have both getters and setters.
+ ///
+ public static T GetInstanceFor()
+ {
+ return (T)GetInstanceFor(typeof(T));
+ }
+
+ static readonly ModuleBuilder ModuleBuilder;
+ static readonly AssemblyBuilder DynamicAssembly;
+
+ ///
+ /// Get an empty instance of a dynamic proxy for the given type.
+ /// All public fields are writable and all properties have both getters and setters.
+ ///
+ public static object GetInstanceFor(Type targetType)
+ {
+ lock (DynamicAssembly)
+ {
+ var constructedType = DynamicAssembly.GetType(ProxyName(targetType)) ?? GetConstructedType(targetType);
+ var instance = Activator.CreateInstance(constructedType);
+ return instance;
+ }
+ }
+
+ static string ProxyName(Type targetType)
+ {
+ return targetType.Name + "Proxy";
+ }
+
+ static DynamicConcrete()
+ {
+ var assemblyName = new AssemblyName("DynImpl");
+ DynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
+ ModuleBuilder = DynamicAssembly.DefineDynamicModule("DynImplModule");
+ }
+
+ static Type GetConstructedType(Type targetType)
+ {
+ var typeBuilder = ModuleBuilder.DefineType(targetType.Name + "Proxy", TypeAttributes.Public);
+
+ var ctorBuilder = typeBuilder.DefineConstructor(
+ MethodAttributes.Public,
+ CallingConventions.Standard,
+ new Type[] { });
+ var ilGenerator = ctorBuilder.GetILGenerator();
+ ilGenerator.Emit(OpCodes.Ret);
+
+ IncludeType(targetType, typeBuilder);
+
+ foreach (var face in targetType.GetInterfaces())
+ IncludeType(face, typeBuilder);
+
+ return typeBuilder.CreateType();
+ }
+
+ static void IncludeType(Type typeOfT, TypeBuilder typeBuilder)
+ {
+ var methodInfos = typeOfT.GetMethods();
+ foreach (var methodInfo in methodInfos)
+ {
+ if (methodInfo.Name.StartsWith("set_")) continue; // we always add a set for a get.
+
+ if (methodInfo.Name.StartsWith("get_"))
+ {
+ BindProperty(typeBuilder, methodInfo);
+ }
+ else
+ {
+ if (methodInfo.IsAbstract) BindMethod(typeBuilder, methodInfo);
+ }
+ }
+
+ if (typeOfT.IsInterface) typeBuilder.AddInterfaceImplementation(typeOfT);
+ else if (typeOfT.IsAbstract) typeBuilder.SetParent(typeOfT);
+ }
+
+ static void BindMethod(TypeBuilder typeBuilder, MethodInfo methodInfo)
+ {
+ var args = methodInfo.GetParameters().Select(p => p.ParameterType).ToArray();
+ var methodBuilder = typeBuilder.DefineMethod(
+ methodInfo.Name,
+ MethodAttributes.Public | MethodAttributes.Virtual,
+ CallingConventions.HasThis,
+ methodInfo.ReturnType,
+ args
+ );
+
+ var methodILGen = methodBuilder.GetILGenerator();
+ if (methodInfo.ReturnType == typeof(void))
+ {
+ methodILGen.Emit(OpCodes.Ret);
+ }
+ else
+ {
+ if (methodInfo.ReturnType.IsPrimitive)
+ {
+ methodILGen.Emit(OpCodes.Ldc_I4_0);
+ }
+ else if (methodInfo.ReturnType.IsValueType || methodInfo.ReturnType.IsEnum)
+ {
+ var getMethod = typeof(Activator).GetMethod("CreateInstance",
+ new[] { typeof(Type) });
+ var lb = methodILGen.DeclareLocal(methodInfo.ReturnType);
+ if (lb.LocalType != null)
+ {
+ methodILGen.Emit(OpCodes.Ldtoken, lb.LocalType);
+ methodILGen.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
+ methodILGen.Emit(OpCodes.Callvirt, getMethod);
+ methodILGen.Emit(OpCodes.Unbox_Any, lb.LocalType);
+ }
+ }
+ else
+ {
+ methodILGen.Emit(OpCodes.Ldnull);
+ }
+ methodILGen.Emit(OpCodes.Ret);
+ }
+ typeBuilder.DefineMethodOverride(methodBuilder, methodInfo);
+ }
+
+ ///
+ /// Bind a new property into a type builder with getters and setters.
+ ///
+ public static void BindProperty(TypeBuilder typeBuilder, MethodInfo methodInfo)
+ {
+ // Backing Field
+ var propertyName = methodInfo.Name.Replace("get_", "");
+ var propertyType = methodInfo.ReturnType;
+ var backingField = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
+
+ //Getter
+ var backingGet = typeBuilder.DefineMethod("get_" + propertyName, MethodAttributes.Public |
+ MethodAttributes.SpecialName | MethodAttributes.Virtual |
+ MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
+ var getIl = backingGet.GetILGenerator();
+
+ getIl.Emit(OpCodes.Ldarg_0);
+ getIl.Emit(OpCodes.Ldfld, backingField);
+ getIl.Emit(OpCodes.Ret);
+
+
+ //Setter
+ var backingSet = typeBuilder.DefineMethod("set_" + propertyName, MethodAttributes.Public |
+ MethodAttributes.SpecialName | MethodAttributes.Virtual |
+ MethodAttributes.HideBySig, null, new[] { propertyType });
+
+ var setIl = backingSet.GetILGenerator();
+
+ setIl.Emit(OpCodes.Ldarg_0);
+ setIl.Emit(OpCodes.Ldarg_1);
+ setIl.Emit(OpCodes.Stfld, backingField);
+ setIl.Emit(OpCodes.Ret);
+
+ // Property
+ var propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.None, propertyType, null);
+ propertyBuilder.SetGetMethod(backingGet);
+ propertyBuilder.SetSetMethod(backingSet);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs
index 5c504b09..eddf7607 100644
--- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs
+++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs
@@ -7898,6 +7898,31 @@ Parameter name: value",
}
}
+ public abstract class AbstractTestClass
+ {
+ public string Value { get; set; }
+ }
+
+ public class AbstractImplementationTestClass : AbstractTestClass
+ {
+ }
+
+ public abstract class AbstractListTestClass : List
+ {
+ }
+
+ public class AbstractImplementationListTestClass : AbstractListTestClass
+ {
+ }
+
+ public abstract class AbstractDictionaryTestClass : Dictionary
+ {
+ }
+
+ public class AbstractImplementationDictionaryTestClass : AbstractDictionaryTestClass
+ {
+ }
+
public class PublicConstructorOverridenByJsonConstructor
{
public string Value { get; private set; }
diff --git a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs
index ff88ee30..245a295c 100644
--- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs
+++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs
@@ -375,34 +375,37 @@ namespace Newtonsoft.Json.Serialization
if (attribute != null)
contract.ItemRequired = attribute._itemRequired;
- ConstructorInfo overrideConstructor = GetAttributeConstructor(contract.NonNullableUnderlyingType);
+ if (contract.IsInstantiable)
+ {
+ ConstructorInfo overrideConstructor = GetAttributeConstructor(contract.NonNullableUnderlyingType);
- // check if a JsonConstructorAttribute has been defined and use that
- if (overrideConstructor != null)
- {
-#pragma warning disable 618
- contract.OverrideConstructor = overrideConstructor;
-#pragma warning restore 618
- contract.CreatorParameters.AddRange(CreateConstructorParameters(overrideConstructor, contract.Properties));
- }
- else if (contract.MemberSerialization == MemberSerialization.Fields)
- {
-#if !(NETFX_CORE || PORTABLE40 || PORTABLE)
- // mimic DataContractSerializer behaviour when populating fields by overriding default creator to create an uninitialized object
- // note that this is only possible when the application is fully trusted so fall back to using the default constructor (if available) in partial trust
- if (JsonTypeReflector.FullyTrusted)
- contract.DefaultCreator = contract.GetUninitializedObject;
-#endif
- }
- else if (contract.DefaultCreator == null || contract.DefaultCreatorNonPublic)
- {
- ConstructorInfo constructor = GetParametrizedConstructor(contract.NonNullableUnderlyingType);
- if (constructor != null)
+ // check if a JsonConstructorAttribute has been defined and use that
+ if (overrideConstructor != null)
{
#pragma warning disable 618
- contract.ParametrizedConstructor = constructor;
+ contract.OverrideConstructor = overrideConstructor;
#pragma warning restore 618
- contract.CreatorParameters.AddRange(CreateConstructorParameters(constructor, contract.Properties));
+ contract.CreatorParameters.AddRange(CreateConstructorParameters(overrideConstructor, contract.Properties));
+ }
+ else if (contract.MemberSerialization == MemberSerialization.Fields)
+ {
+#if !(NETFX_CORE || PORTABLE40 || PORTABLE)
+ // mimic DataContractSerializer behaviour when populating fields by overriding default creator to create an uninitialized object
+ // note that this is only possible when the application is fully trusted so fall back to using the default constructor (if available) in partial trust
+ if (JsonTypeReflector.FullyTrusted)
+ contract.DefaultCreator = contract.GetUninitializedObject;
+#endif
+ }
+ else if (contract.DefaultCreator == null || contract.DefaultCreatorNonPublic)
+ {
+ ConstructorInfo constructor = GetParametrizedConstructor(contract.NonNullableUnderlyingType);
+ if (constructor != null)
+ {
+#pragma warning disable 618
+ contract.ParametrizedConstructor = constructor;
+#pragma warning restore 618
+ contract.CreatorParameters.AddRange(CreateConstructorParameters(constructor, contract.Properties));
+ }
}
}
@@ -703,8 +706,8 @@ namespace Newtonsoft.Json.Serialization
// then see whether object is compadible with any of the built in converters
contract.InternalConverter = JsonSerializer.GetMatchingConverter(BuiltInConverters, contract.NonNullableUnderlyingType);
- if (ReflectionUtils.HasDefaultConstructor(contract.CreatedType, true)
- || contract.CreatedType.IsValueType())
+ if (contract.IsInstantiable
+ && (ReflectionUtils.HasDefaultConstructor(contract.CreatedType, true) || contract.CreatedType.IsValueType()))
{
contract.DefaultCreator = GetDefaultCreator(contract.CreatedType);
diff --git a/Src/Newtonsoft.Json/Serialization/JsonContract.cs b/Src/Newtonsoft.Json/Serialization/JsonContract.cs
index b1cf0a78..dfc8a19b 100644
--- a/Src/Newtonsoft.Json/Serialization/JsonContract.cs
+++ b/Src/Newtonsoft.Json/Serialization/JsonContract.cs
@@ -86,12 +86,12 @@ namespace Newtonsoft.Json.Serialization
{
internal bool IsNullable;
internal bool IsConvertable;
- internal bool IsSealed;
internal bool IsEnum;
internal Type NonNullableUnderlyingType;
internal ReadType InternalReadType;
internal JsonContractType ContractType;
internal bool IsReadOnlyOrFixedSize;
+ internal bool IsSealed;
internal bool IsInstantiable;
private List _onDeserializedCallbacks;
@@ -99,6 +99,7 @@ namespace Newtonsoft.Json.Serialization
private IList _onSerializedCallbacks;
private IList _onSerializingCallbacks;
private IList _onErrorCallbacks;
+ private Type _createdType;
///
/// Gets the underlying type for the contract.
@@ -110,7 +111,17 @@ namespace Newtonsoft.Json.Serialization
/// Gets or sets the type created during deserialization.
///
/// The type created during deserialization.
- public Type CreatedType { get; set; }
+ public Type CreatedType
+ {
+ get { return _createdType; }
+ set
+ {
+ _createdType = value;
+
+ IsSealed = _createdType.IsSealed();
+ IsInstantiable = !(_createdType.IsInterface() || _createdType.IsAbstract());
+ }
+ }
///
/// Gets or sets whether this type contract is serialized as a reference.
@@ -296,9 +307,6 @@ namespace Newtonsoft.Json.Serialization
UnderlyingType = underlyingType;
- IsSealed = underlyingType.IsSealed();
- IsInstantiable = !(underlyingType.IsInterface() || underlyingType.IsAbstract());
-
IsNullable = ReflectionUtils.IsNullable(underlyingType);
NonNullableUnderlyingType = (IsNullable && ReflectionUtils.IsNullableType(underlyingType)) ? Nullable.GetUnderlyingType(underlyingType) : underlyingType;
diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs
index ca275474..27a2d315 100644
--- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs
+++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs
@@ -1036,6 +1036,9 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
}
else
{
+ if (!contract.IsInstantiable)
+ throw JsonSerializationException.Create(reader, "Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
+
throw JsonSerializationException.Create(reader, "Unable to find a constructor to use for type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
}
}
@@ -1064,6 +1067,9 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
}
else
{
+ if (!contract.IsInstantiable)
+ throw JsonSerializationException.Create(reader, "Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
+
throw JsonSerializationException.Create(reader, "Unable to find a default constructor to use for type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
}
}
@@ -1825,9 +1831,6 @@ To fix this error either change the environment to be fully trusted, change the
{
object newObject = null;
- if (!objectContract.IsInstantiable)
- throw JsonSerializationException.Create(reader, "Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType));
-
if (objectContract.OverrideCreator != null)
{
if (objectContract.CreatorParameters.Count > 0)
@@ -1854,7 +1857,12 @@ To fix this error either change the environment to be fully trusted, change the
}
if (newObject == null)
+ {
+ if (!objectContract.IsInstantiable)
+ throw JsonSerializationException.Create(reader, "Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType));
+
throw JsonSerializationException.Create(reader, "Unable to find a constructor to use for type {0}. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType));
+ }
createdFromNonDefaultCreator = false;
return newObject;