Skip to content

Constructor mapping does not work properly for abstract parameters #811

@runekeylane

Description

@runekeylane

Hello,

I have an issue with Mapster when using the MapToConstructor functionality.

If I have a ctor parameter that has an abstract type, and that parameter is null I get the following exception:

System.InvalidOperationException : Cannot instantiate type: AbstractDomainTestClass

I think Mapster should be able to handle null values in ctors for abstract types.

The following code showcases the issue:

using Mapster;
using MapsterMapper;
using NUnit.Framework;

public class MapsterCtorTests
{
    private Mapper _mapper;

    [SetUp]
    public void Setup()
    {
        _mapper = new Mapper();

        _mapper.Config.Default.MapToConstructor(true);

        _mapper.Config.NewConfig<AbstractDtoTestClass, AbstractDomainTestClass>()
            .Include<DerivedDtoTestClass, DerivedDomainTestClass>();
    }

    [Test(Description = "This works as expected")]
    public void Dto_To_Domain_MapsCorrectly()
    {
        var dtoDerived = new DerivedDtoTestClass
        {
            DerivedProperty = "DerivedValue",
            AbstractProperty = "AbstractValue"
        };

        var dto = new DtoTestClass
        {
            AbstractType = dtoDerived
        };

        var domain = dto.Adapt<DomainTestClass>();

        Assert.Multiple(() =>
        {
            Assert.That(domain.AbstractType, Is.Not.Null, "Abstract type not mapped correctly");
            Assert.That(domain.AbstractType, Is.TypeOf<DerivedDomainTestClass>(), "Abstract type not mapped correctly");

            var domainDerived = (DerivedDomainTestClass)domain.AbstractType;
            Assert.That(domainDerived.DerivedProperty, Is.EqualTo(dtoDerived.DerivedProperty), "Derived property not mapped correctly");
            Assert.That(domainDerived.AbstractProperty, Is.EqualTo(dtoDerived.AbstractProperty), "Abstract property not mapped correctly");
        });
    }

    [Test(Description = "This does not work, Mapster throws a InvalidOperationException with the following message: Cannot instantiate type: AbstractDomainTestClass")]
    public void Dto_To_Domain_AbstractClassNull_MapsCorrectly()
    {
        var dto = new DtoTestClass
        {
            AbstractType = null
        };

        var domain = dto.Adapt<DomainTestClass>();

        Assert.That(domain.AbstractType, Is.Null, "Abstract type not mapped correctly");
    }

    #region Immutable classes with private setters, map via ctors
    private abstract class AbstractDomainTestClass
    {
        public string AbstractProperty { get; private set; }

        protected AbstractDomainTestClass(string abstractProperty)
        {
            AbstractProperty = abstractProperty;
        }
    }

    private class DerivedDomainTestClass : AbstractDomainTestClass
    {
        public string DerivedProperty { get; private set; }

        /// <inheritdoc />
        public DerivedDomainTestClass(string abstractProperty, string derivedProperty)
            : base(abstractProperty)
        {
            DerivedProperty = derivedProperty;
        }
    }

    private class DomainTestClass
    {
        public AbstractDomainTestClass AbstractType { get; private set; }

        public DomainTestClass(
            AbstractDomainTestClass abstractType)
        {
            AbstractType = abstractType;
        }
    }
    #endregion

    #region DTO classes
    private abstract class AbstractDtoTestClass
    {
        public string AbstractProperty { get; set; }
    }

    private class DerivedDtoTestClass : AbstractDtoTestClass
    {
        public string DerivedProperty { get; set; }
    }

    private class DtoTestClass
    {
        public AbstractDtoTestClass AbstractType { get; set; }
    }
    #endregion
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions