mapstruct / mapstruct/mapstruct

Nested target with at least one different property name fails

Open
#2,580 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Java
Stars
7.7k
Forks
1.1k
PR merge metrics
No merged PRs in 30d

Description

I am using 1.4.2.Final.

A simplified version of what I am trying to achieve is below:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Flat {

    private String root;
    private String different;

    private String property1;
    private String property2;

    private String property3;
    private String property4;

    private String property5;
    private String property6;

}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Nested {

    private String root;
    private String _different;

    private NestedA nestedA;
    private NestedB nestedB;
    private NestedC nestedC;

}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class NestedA {

    private String _property1; // --> this is the problem
    private String property2;

}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class NestedB {

    private String property3;
    private String property4;

}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class NestedC {

    private String property5;
    private String property6;

}

@Mapper
public interface FlatToNestedMapper {

    @Mapping(source = "different", target = "_different")
    @Mapping(source = ".", target = "nestedA")
    @Mapping(source = "property1", target = "nestedA._property1") // --> BUG: doesn't work with previous line
    @Mapping(source = ".", target = "nestedB")
    @Mapping(source = ".", target = "nestedC")
    Nested toNested(Flat flat);

    @Mapping(target = "different", source = "_different")
    @Mapping(target = ".", source = "nestedA")
    @Mapping(target = "property1", source = "nestedA._property1")
    @Mapping(target = ".", source = "nestedB")
    @Mapping(target = ".", source = "nestedC")
    Flat toFlat(Nested nested);

}

The above mapping works fine except for either _property1 or the remaining properties.

Here is the print of the result:

--- TO NESTED ---
Source: Flat(root=root, different=different, property1=1, property2=2, property3=3, property4=4, property5=5, property6=6)
Target: Nested(root=root, _different=different, nestedA=NestedA(_property1=1, property2=null), nestedB=NestedB(property3=3, property4=4), nestedC=NestedC(property5=5, property6=6)) // --> notice property2=null

--- TO FLAT ---
Target: Nested(root=root, _different=different, nestedA=NestedA(_property1=1, property2=2), nestedB=NestedB(property3=3, property4=4), nestedC=NestedC(property5=5, property6=6))
Source: Flat(root=root, different=different, property1=1, property2=2, property3=3, property4=4, property5=5, property6=6)

Notice property2=null in the to nested segment. If I try to map the whole object together with a specific property of a different name, one of them will fail:

@Mapping(source = ".", target = "nestedA")
@Mapping(source = "property1", target = "nestedA._property1") // --> BUG: doesn't work with previous line

However, everything works in the opposite direction:

@Mapping(target = ".", source = "nestedA")
@Mapping(target = "property1", source = "nestedA._property1")

It looks like a bug to me, especially when compared with the fact that all works in the opposite direction. Overall, the above example is a powerful mapping scenario, which is almost fully supported by Mapstruct. It's just that small detail that forces an alternative solution.

WORKAROUND

Of course, if I comment the culprit line as in:

@Mapping(source = ".", target = "nestedA")
//@Mapping(source = "property1", target = "nestedA._property1") // --> BUG: doesn't work with previous line

and add an @AfterMethod like the below, all will work:

@AfterMapping
default void update(Flat flat, @MappingTarget Nested nested) {
    nested.getNestedA().set_property1(flat.getProperty1());
}

But it would be cleaner to simply support the described attempted scenario.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the mapper with the shown @Mapping(source = ".", target = "nestedA") and nestedA._property1 mappings. Trace how these overlapping mappings are processed for the toNested direction, then verify that both _property1 and property2 are retained in the generated result without needing the @AfterMapping workaround.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.