mapstruct / mapstruct/mapstruct
Nested target with at least one different property name fails
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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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