Thanks to visit codestin.com
Credit goes to github.com

Skip to content

target="." doesn't disambiguate multiple mappings #3818

@TrianguloY

Description

@TrianguloY

Expected behavior

using @Mapping( target = ".", source = "record" ) should be equivalent as adding several @Mapping( target = "x", source = "record.x" ) for all the properties on 'record' (unless there is already another explicit @Mapping with it).
Source: https://mapstruct.org/documentation/dev/reference/html/#mapping-nested-bean-properties-to-current-target

In particular, a code like this one:

@Mapper
public interface Example {

  record Sample(
      String first,
      String second,
      String third
  ) {}

  @Mapping(target = ".", source = "main")
  @Mapping(target = "third", source = "secondary.third")
  Sample merge(Sample main, Sample secondary);
}

Should be valid and generate a mapping equivalent to return new Sample(main.first, main.second, secondary.third).
From a user perspective, this mapping means: 'Use everything from main, except 'third' from secondary.

Actual behavior

With the code above, mapstructs reports the following two errors:

Several possible source properties for target property "first".
Several possible source properties for target property "second".

It appears that the @Mapping(target = ".", source = "main") is not used for disambiguation.

Steps to reproduce the problem

Here are other examples with different outcomes:

Specify all fields: works

The following code:

@Mapper
public interface Example {

  record Sample(
      String first,
      String second,
      String third
  ) {}
  
  @Mapping(target = "first", source = "main.first")
  @Mapping(target = "second", source = "main.second")
  @Mapping(target = "third", source = "secondary.third")
  Sample merge(Sample main, Sample secondary);
}

Correctly compiles are generates the expected mapping (equivalent to return new Sample(main.first, main.second, secondary.third))

Secondary object without duplicated fields: works

The following code:

@Mapper
public interface Example {

  record Sample(
      String first,
      String second,
      String third
  ) {}

  record DifferentSample(
      String third
  ) {}

  @Mapping(target = ".", source = "main")
  @Mapping(target = "third", source = "secondary.third")
  Sample merge(Sample main, DifferentSample secondary);
}

Correctly compiles are generates the expected mapping (equivalent to return new Sample(main.first, main.second, secondary.third)).
In this case there is no ambiguity.

Double target=".": same outcome

The following two pieces of code:

@Mapper
public interface Example {

  record Sample(
      String first,
      String second,
      String third
  ) {}

  @Mapping(target = ".", source = "main")
  @Mapping(target = ".", source = "secondary")
  @Mapping(target = "third", source = "secondary.third")
  Sample merge(Sample main, Sample secondary);
}
@Mapper
public interface Example {

  record Sample(
      String first,
      String second,
      String third
  ) {}

  @Mapping(target = "third", source = "secondary.third")
  Sample merge(Sample main, Sample secondary);
}

Generates the same outcome as the 'expected behavior' example: Several possible source properties for target property "first"/"second".

Based on this it appears as if something like @Mapping(target = ".", source = "value") is implicitly added to all mappings with a single parameter value, which means that explicitly adding it doesn't really do anything, instead of disambiguating.


Extra, if this were working as expected, suggestions like #3161 would not need any extra 'PrimaryMapping' annotation, as that would be fixed with a target="." mapping.

@Mapping(target = "borrowed", source = "tblB.borrowed")
@Mapping(target = ".", source = "tblA")
EntityA toEntity(TblA tblA, TblB tblB)

MapStruct Version

1.6.3

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions