I upgraded from Mapster 9.0.0-pre01 to 10.0.7.
After the upgrade, mapping an object that contains a nullable abstract/base-type property fails when the source property value is null.
The mapping is configured with Include<TDerivedSource, TDerivedDestination>(), so I would expect Mapster to use the included derived mapping when the source value is non-null, and simply map null to null when the source value is null.
Repro
public abstract class DtoBase
{
}
public class DtoDerived : DtoBase
{
public string Id { get; set; } = null!;
}
public class DtoFoo
{
public DtoBase? Field { get; set; }
}
public abstract class DomainBase
{
}
public class DomainDerived : DomainBase
{
public string Id { get; set; } = null!;
}
public class DomainFoo
{
public DomainBase? Field { get; set; }
}
Global Configuration:
public static TypeAdapterConfig ConfigureMapster(MappingAssemblyProvider mappingAssemblyProvider)
{
var config = TypeAdapterConfig.GlobalSettings;
config.Default.PreserveReference(true);
config.Default.EnumMappingStrategy(EnumMappingStrategy.ByName);
config.Default.EnableNonPublicMembers(true);
config.Default.MapToConstructor(true);
config.Default.ShallowCopyForSameType(false);
config.AllowImplicitSourceInheritance = true;
config.RequireDestinationMemberSource = true;
foreach (var assembly in mappingAssemblyProvider.GetMapperAssemblies())
{
config.Scan(assembly);
}
config.Compile();
return config;
}
public class MappingConfig : IRegister
{
public void Register(TypeAdapterConfig config)
{
config.ForType<DtoBase, DomainBase>()
.TwoWays()
.Include<DtoDerived, DomainDerived>();
}
}
Test:
[TestFixture]
public class RecordMappingTests
{
[SetUp]
public void SetUp()
{
MappingConfiguration.ConfigureMapster(new MappingAssemblyProvider());
}
[Test]
public void DtoFooWithFieldNull_Maps_To_DomainFoo()
{
var dto = new DtoFoo
{
Field = null
};
var domain = dto.Adapt<DomainFoo>();
Assert.That(domain.Field, Is.Null);
}
[Test]
public void DtoFooWithField_Maps_To_DomainFoo()
{
var dto = new DtoFoo
{
Field = new DtoDerived
{
Id = "id"
}
};
var domain = dto.Adapt<DomainFoo>();
Assert.That(domain.Field, Is.Not.Null);
Assert.That(domain.Field, Is.TypeOf<DomainDerived>());
}
}
The DtoFooWithFieldNull_Maps_To_DomainFoo test fails with:
System.InvalidOperationException : Cannot instantiate type: DomainBase
at lambda_method30(Closure, DtoBase)
at lambda_method32(Closure, Object)
at Mapster.TypeAdapter.Adapt[TDestination](Object source, TypeAdapterConfig config)
at Mapster.TypeAdapter.Adapt[TDestination](Object source)
at RecordMappingTests.RecordMappingTests.DtoFooWithFieldNull_Maps_To_DomainFoo()`
This only happens then the adapt call is made, and the compile() call succeeds. It looks like Mapster is attempting to map the nested Field property through the declared base mapping, even when the source value is null.
I upgraded from Mapster
9.0.0-pre01to10.0.7.After the upgrade, mapping an object that contains a nullable abstract/base-type property fails when the source property value is
null.The mapping is configured with
Include<TDerivedSource, TDerivedDestination>(), so I would expect Mapster to use the included derived mapping when the source value is non-null, and simply mapnulltonullwhen the source value is null.Repro
Global Configuration:
Test:
The DtoFooWithFieldNull_Maps_To_DomainFoo test fails with:
This only happens then the adapt call is made, and the compile() call succeeds. It looks like Mapster is attempting to map the nested Field property through the declared base mapping, even when the source value is null.