Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit db834fb

Browse files
committed
Merge pull request #1917 from khdang/xmlserializer_protected_constructor
Fix XmlSerializer issue when deserializing type with protected parameterless constructor
2 parents 41b90e6 + 977d580 commit db834fb

File tree

3 files changed

+90
-0
lines changed

3 files changed

+90
-0
lines changed

src/System.Runtime.Serialization.Xml/tests/SerializationTypes.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2109,3 +2109,13 @@ public class TypeWithXmlDocumentProperty
21092109
{
21102110
public XmlDocument Document;
21112111
}
2112+
2113+
public class TypeWithNonParameterlessConstructor
2114+
{
2115+
public string StringProperty { get; set; }
2116+
2117+
public TypeWithNonParameterlessConstructor(string value)
2118+
{
2119+
StringProperty = value;
2120+
}
2121+
}

src/System.Xml.XmlSerializer/src/System/Xml/Serialization/XmlSerializationWriterILGen.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2416,6 +2416,66 @@ internal void ILGenForCreateInstance(CodeGenerator ilg, Type type, Type cast, bo
24162416
}
24172417
}
24182418

2419+
Label labelReturn = ilg.DefineLabel();
2420+
Label labelEndIf = ilg.DefineLabel();
2421+
2422+
// TypeInfo typeInfo = type.GetTypeInfo();
2423+
// typeInfo not declared explicitly
2424+
ilg.Ldc(type);
2425+
MethodInfo getTypeInfoMehod = typeof(IntrospectionExtensions).GetMethod(
2426+
"GetTypeInfo",
2427+
CodeGenerator.StaticBindingFlags,
2428+
new[] { typeof(Type) }
2429+
);
2430+
ilg.Call(getTypeInfoMehod);
2431+
2432+
// IEnumerator<ConstructorInfo> e = typeInfo.DeclaredConstructors.GetEnumerator();
2433+
LocalBuilder enumerator = ilg.DeclareLocal(typeof(IEnumerator<>).MakeGenericType(typeof(ConstructorInfo)), "e");
2434+
MethodInfo getDeclaredConstructors = typeof(TypeInfo).GetMethod("get_DeclaredConstructors");
2435+
MethodInfo getEnumerator = typeof(IEnumerable<>).MakeGenericType(typeof(ConstructorInfo)).GetMethod("GetEnumerator");
2436+
ilg.Call(getDeclaredConstructors);
2437+
ilg.Call(getEnumerator);
2438+
ilg.Stloc(enumerator);
2439+
2440+
ilg.WhileBegin();
2441+
// ConstructorInfo constructorInfo = e.Current();
2442+
MethodInfo enumeratorCurrent = typeof(IEnumerator).GetMethod("get_Current");
2443+
ilg.Ldloc(enumerator);
2444+
ilg.Call(enumeratorCurrent);
2445+
LocalBuilder constructorInfo = ilg.DeclareLocal(typeof(ConstructorInfo), "constructorInfo");
2446+
ilg.Stloc(constructorInfo);
2447+
2448+
// if (!constructorInfo.IsStatic && constructorInfo.GetParameters.Length() == 0)
2449+
ilg.Ldloc(constructorInfo);
2450+
MethodInfo constructorIsStatic = typeof(ConstructorInfo).GetMethod("get_IsStatic");
2451+
ilg.Call(constructorIsStatic);
2452+
ilg.Brtrue(labelEndIf);
2453+
ilg.Ldloc(constructorInfo);
2454+
MethodInfo constructorGetParameters = typeof(ConstructorInfo).GetMethod("GetParameters");
2455+
ilg.Call(constructorGetParameters);
2456+
ilg.Ldlen();
2457+
ilg.Ldc(0);
2458+
ilg.Cne();
2459+
ilg.Brtrue(labelEndIf);
2460+
2461+
// constructorInfo.Invoke(null);
2462+
MethodInfo constructorInvoke = typeof(ConstructorInfo).GetMethod("Invoke", new Type[] { typeof(object[]) });
2463+
ilg.Ldloc(constructorInfo);
2464+
ilg.Load(null);
2465+
ilg.Call(constructorInvoke);
2466+
ilg.Br(labelReturn);
2467+
2468+
ilg.MarkLabel(labelEndIf);
2469+
ilg.WhileBeginCondition(); // while (e.MoveNext())
2470+
MethodInfo IEnumeratorMoveNext = typeof(IEnumerator).GetMethod(
2471+
"MoveNext",
2472+
CodeGenerator.InstanceBindingFlags,
2473+
Array.Empty<Type>());
2474+
ilg.Ldloc(enumerator);
2475+
ilg.Call(IEnumeratorMoveNext);
2476+
ilg.WhileEndCondition();
2477+
ilg.WhileEnd();
2478+
24192479
MethodInfo Activator_CreateInstance = typeof(Activator).GetMethod(
24202480
"CreateInstance",
24212481
CodeGenerator.StaticBindingFlags,
@@ -2425,6 +2485,7 @@ internal void ILGenForCreateInstance(CodeGenerator ilg, Type type, Type cast, bo
24252485
ilg.Call(Activator_CreateInstance);
24262486
if (cast != null)
24272487
ilg.ConvertValue(Activator_CreateInstance.ReturnType, cast);
2488+
ilg.MarkLabel(labelReturn);
24282489
}
24292490

24302491
internal void WriteLocalDecl(string variableName, SourceInfo initValue)

src/System.Xml.XmlSerializer/tests/XmlSerializerTests.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Globalization;
99
using System.IO;
1010
using System.Linq;
11+
using System.Reflection;
1112
using System.Xml;
1213
using System.Xml.Serialization;
1314
using System.Xml.Linq;
@@ -1111,6 +1112,24 @@ public static void Xml_TypeWithMismatchBetweenAttributeAndPropertyType()
11111112
Assert.StrictEqual(value.IntValue, actual.IntValue);
11121113
}
11131114

1115+
[Fact]
1116+
public static void Xml_TypeWithNonPublicDefaultConstructor()
1117+
{
1118+
TypeInfo ti = IntrospectionExtensions.GetTypeInfo(typeof(TypeWithNonPublicDefaultConstructor));
1119+
TypeWithNonPublicDefaultConstructor value = null;
1120+
value = (TypeWithNonPublicDefaultConstructor)FindDefaultConstructor(ti).Invoke(null);
1121+
Assert.StrictEqual("Mr. FooName", value.Name);
1122+
var actual = SerializeAndDeserialize(value, "<?xml version=\"1.0\"?>" + Environment.NewLine + "<TypeWithNonPublicDefaultConstructor xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" + Environment.NewLine + " <Name>Mr. FooName</Name>" + Environment.NewLine + "</TypeWithNonPublicDefaultConstructor>");
1123+
Assert.StrictEqual(value.Name, actual.Name);
1124+
}
1125+
1126+
[Fact]
1127+
public static void Xml_TypeWithNonParameterlessConstructor()
1128+
{
1129+
var obj = new TypeWithNonParameterlessConstructor("string value");
1130+
Assert.Throws<InvalidOperationException>(() => { SerializeAndDeserialize(obj, string.Empty); });
1131+
}
1132+
11141133
private static T SerializeAndDeserialize<T>(T value, string baseline, Func<XmlSerializer> serializerFactory = null)
11151134
{
11161135
XmlSerializer serializer = new XmlSerializer(typeof(T));

0 commit comments

Comments
 (0)