Deserialization of abstract record class fails
rmja opened this issue · 3 comments
rmja commented
Consider this case:
public abstract record class Animal(DateTime Timestamp)
{
}
[CborDiscriminator("dog")]
public record class Dog(string Color, DateTime Timestamp) : Ingress(Timestamp)
{
// This example fails if this empty constructor is not present
private Dog() : this("black", default)
{
}
}
public static class DataIngressCborOptions
{
public static readonly CborOptions Value = new();
static DataIngressCborOptions()
{
Value.Registry.DiscriminatorConventionRegistry.RegisterConvention(new AttributeBasedDiscriminatorConvention<string>(Value.Registry));
Value.Registry.DiscriminatorConventionRegistry.RegisterType(typeof(Dog));
}
}
Cbor.Deserialize<Animal[]>(..., DataIngressCborOptions.Value);
In the example, if the Dog
ctor is not defined, _constructor
is never assigned in ObjectConverter
causing the exception A CreatorMapping should be defined for interfaces or abstract classes
.
mcatanzariti commented
I could not repro the problem in this test:
https://github.com/dahomey-technologies/Dahomey.Cbor/blob/master/src/Dahomey.Cbor.Tests/Issues/Issue0091.cs
rmja commented
Ok. I will try and reproduce this and get back
rmja commented
@mcatanzariti The serialization/deserialization needs to be done on the abstract type. Here is a modified version of Issue0091.cs that fails:
#if NET6_0_OR_GREATER
using Dahomey.Cbor.Attributes;
using Dahomey.Cbor.Serialization.Conventions;
using System;
using Xunit;
namespace Dahomey.Cbor.Tests.Issues
{
public class Issue0091
{
public abstract record class Animal(DateTime Timestamp)
{
}
[CborDiscriminator("dog")]
public record class Dog(string Color, DateTime Timestamp) : Animal(Timestamp)
{
// This example does not fail if this empty constructor is present
//private Dog() : this("black", default)
//{
//}
}
[Fact]
public void TestReadWrite()
{
CborOptions options = new CborOptions();
options.Registry.DiscriminatorConventionRegistry.RegisterConvention(new AttributeBasedDiscriminatorConvention<string>(options.Registry));
options.Registry.DiscriminatorConventionRegistry.RegisterType(typeof(Dog));
Dog dog = new("black", DateTime.Parse("2022-10-24T14:05:08Z"));
var cbor = Helper.Write<Animal>(dog, options);
Animal deserialized = Helper.Read<Animal>(cbor, options);
Assert.NotNull(deserialized);
Dog dog2 = Assert.IsType<Dog>(deserialized);
Assert.Equal(dog.Color, dog2.Color);
Assert.Equal(dog.Timestamp, dog2.Timestamp);
}
}
}
#endif