mapperly: Cannot map `Value` or `HasValue` Property of `Nullable`

Describe the bug I upgraded from next-2 to next-3 and now I am receiving a build error

ModelMapper.g.cs(705,78): error CS1061: 'JsonElement' does not contain a definition for 'Value' and no accessible extension method 'Value' accepting a first argument of type 'JsonElement' could be found (are you missing a using directive or an assembly reference?)

It looks like the generated code is calling .Value twice:

// Generated code
        {
            var target = new global::SellerAmend()
            {
                Kind = source.Kind,
                SellerPartnerId = source.SellerPartnerId,
                SellerLoanId = source.SellerLoanId,
                DateCreated = source.DateCreated
            };
            if (source.ListingAmendment != null)
            {
                                                                   // .Value.Value should just be .Value
                target.ListingAmendmentValue = source.ListingAmendment.Value.Value.ToString();
            }

            return target;
        }

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 15 (6 by maintainers)

Most upvoted comments

@TimothyMakkison The test you provided, which should reproduce the bug described by OP, fails on v2.8.0. So this probably exists since a longer time and isn’t a regression of v2.9.0-next.3

@TimothyMakkison sorry my bad, I adjusted the test to verify that the bug does not exist. If I use exact your version, it fails on v2.8.0 as well as on v2.9.0-next.3. The problem is that the target property has a auto-flattened name of ending with Value. When resolving the name, autoflattening resolves it to P.Value (the value property of Nullable<T>). Then when building the mapping, the builder encounters a nullable value type and adds another .Value to access the value inside the null if condition. It relates to https://github.com/riok/mapperly/issues/572. If Nullable<T> properties are treated as T while resolving mappable members, the problem shouldn’t occur.

Here’s a repro:

[Mapper(PropertyNameMappingStrategy = PropertyNameMappingStrategy.CaseInsensitive)]
public class MapperClass
{
    public static partial Car MapCar(CarDto input);
    public static partial CarDto MapCar(Car input);
}

public record CarDto()
{
    public JsonElement? Amendment { get; set; }
}

public record Car()
{
    [JsonIgnore, System.Runtime.Serialization.IgnoreDataMember]
    public OtherThing? AmendmentMetadata
    {
        get => Amendment?.Deserialize<OtherThing>(JsonExtensions.JsonOptions);
    }

    [JsonIgnore, System.Runtime.Serialization.DataMember]
    public string? AmendmentValue
    {
        get => Amendment?.GetRawText();
        set => Amendment = value != null ? JsonSerializer.Deserialize<JsonElement>(value) : null;
    }
    
    [JsonInclude, System.Runtime.Serialization.IgnoreDataMember]
    public JsonElement? Amendment { get; set; }
}

public class OtherThing
{
    public string? Value { get; set; }
}

Thanks for the bug report, I’ll look into it.