riok/mapperly

Not mapping properties generated by other source generators

Cybrosys opened this issue ยท 4 comments

Describe the bug
Mapperly is not finding public properties generated by other source generators.
I am using the MVVM Community Toolkit which has an ObservablePropertyAttribute which generates the public properties of private fields that are decorated with the attribute.

To Reproduce

  1. Create a new project and add dependencies to the MVVM toolkit and Mapperly.
  2. Create a class with a private field and mark it with the ObservablePropertyAtribute.
  3. Declare a mapper and add a mapping method that maps the object to itself (or another object).

Expected behavior
The generated map-method should map the generated public properties.

Code snippets

public record class PersonDto(string FirstName, string LastName);

public partial class Person : ObservableObject
{
    [ObservableProperty] string? _firstName;
    [ObservableProperty] string? _lastName;
}

[Mapper]
public static partial class PersonMapper
{
    public static partial void Map(PersonDto source, Person destination);
    public static partial Person Map(PersonDto source);
}

Generated mapper

public static partial class PersonMapper
{
    public static partial void Map(global::StoreApp.Features.Profile.PersonDto source, global::StoreApp.Features.Profile.Person destination)
    {
    }

    public static partial global::StoreApp.Features.Profile.Person Map(global::StoreApp.Features.Profile.PersonDto source)
    {
        var target = new global::StoreApp.Features.Profile.Person();
        return target;
    }
}

Environment (please complete the following information):

  • Mapperly Version: 3.3.0-next.2
  • CommunityToolkit.Mvvm Version: 8.2.2
  • .NET Version: 8.0-rc2
  • IDE: Visual Studio v17.8.0 Preview 7.0
  • OS: Windows 11 Pro Version 10.0.22621 Build 22621
latonz commented

Chaining source generators is not supported and I don't know any workarounds despite implementing the generated code by hand.
See FAQ and #533

latonz commented

With 3.3.0 (available since 3.3.0-next.2) and .NET 8.0 private members can be mapped with Mapperly. However, I wouldn't recommend this (it disables a lot of IDE features like looking up references). See docs.

With 3.3.0 (available since 3.3.0-next.2) and .NET 8.0 private members can be mapped with Mapperly. However, I wouldn't recommend this (it disables a lot of IDE features like looking up references). See docs.

Thank you for the information. I wouldn't want to map the private fields as it would circumvent the point of using the ObservablePropertyAttribute in the first place.

Just came across this issue, and wanted to share my workaround with I'm doing, it seems to work fine (bindings in WPF). I have a FormViewModel which has all of the fields for the view, and it does its own validation. This gets mapped (partially) to the an object. I'm also using [ObservableProperty] and [NotifyDataErrorInfo]. So the changes here to SettingsForm will propagate to the UI.

    [UserMapping(Default = true)]
    public void DoProfileToForm(Profile profile, SettingsForm to)
    {
        ProfileToForm(profile, to);
        to.TriggerChanges();
    }

Where TriggerChanges() is this in my ViewModel:

    public void TriggerChanges()
    {
        OnPropertyChanged("");
    }

That will trigger it on all properties and update the UI. It's a little annoying because I have to wrap the different mapping methods, but it is easier than mapping all the fields manually :)

But maybe some helpers can be added to make this easier