Skip to content

Commit

Permalink
Serialization: check type has public constructor before composing ser…
Browse files Browse the repository at this point in the history
…ializer
  • Loading branch information
HermanSchoenfeld committed May 28, 2024
1 parent bea28ac commit 4cd3e29
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 4 deletions.
10 changes: 6 additions & 4 deletions src/Hydrogen/Serialization/Builder/CompositeSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ public override TItem Deserialize(EndianBinaryReader reader, SerializationContex

}


public static class CompositeSerializer {
public static CompositeSerializer<TItem> Create<TItem>(Func<TItem> activator, MemberSerializationBinding[] memberBindings)
=> new CompositeSerializer<TItem>(activator, memberBindings);
Expand All @@ -111,11 +110,14 @@ public static IItemSerializer Create(Type itemType)
.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null)
.Invoke(null);

public static void Configure(IItemSerializer serializer, Type itemType, IEnumerable<MemberSerializationBinding> memberBindings)
=> Configure(serializer, Tools.Lambda.CastFunc( () => itemType.ActivateWithCompatibleArgs(), itemType), memberBindings);
public static void Configure(IItemSerializer serializer, Type itemType, IEnumerable<MemberSerializationBinding> memberBindings) {
var constructor = itemType.FindCompatibleConstructor(Array.Empty<Type>());
Guard.Ensure(constructor is not null, $"Unable to compose a serializer for type '{itemType.ToStringCS()}' as it did not have a public parameterless constructor");
Configure(serializer, Tools.Lambda.CastFunc(() => constructor.Invoke(null), itemType), memberBindings);
}

public static void Configure(IItemSerializer serializer, Delegate activator, IEnumerable<MemberSerializationBinding> memberBindings) {
Guard.Ensure(serializer.GetType().IsConstructedGenericTypeOf(typeof(CompositeSerializer<>)), "Serializer must be a CompositeSerializer");
Guard.Ensure(serializer.GetType().IsConstructedGenericTypeOf(typeof(CompositeSerializer<>)), $"Serializer must be a {typeof(CompositeSerializer<>).ToStringCS()}");
serializer
.GetType()
.GetMethod(nameof(CompositeSerializer<object>.Configure), BindingFlags.Instance | BindingFlags.NonPublic)
Expand Down
15 changes: 15 additions & 0 deletions tests/Hydrogen.Tests/Serialization/SerializerBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,17 @@ public class GenericType<T1, T2> {
public T2 Prop2 { get; set; }
}

public class NoConstructorClass {
private NoConstructorClass() {
}

public NoConstructorClass(string prop1) {
Prop1 = prop1;
}
public string Prop1 { get; set; }

}

[Test]
public void TestObject_1() {
// test object
Expand Down Expand Up @@ -636,4 +647,8 @@ public void SerializableMembersInBaseFirstOrder() {
Assert.That(members[3].Name, Is.EqualTo("Prop4"));
}

[Test]
public void NoSerializerForUnconstructableClass() {
Assert.That (() => ItemSerializer<NoConstructorClass>.Default, Throws.InvalidOperationException);
}
}

0 comments on commit 4cd3e29

Please sign in to comment.