Reputation: 4913
I am trying to map from one nested object to another with some custom mappings, and I also need to add an additional field that is not present in the source object by using a second method parameter. I am getting either a compiler error when the target type uses constructor mapping or incomplete mapping when using mutable objects.
Is this a bug? Or am I missing something?
Some non-optimal workarounds:
My Model
record FromInner1(String a, String b, String c) {}
record FromInner2(String d, String e) {}
record FromOuter(FromInner1 inner1, FromInner2 inner2) {}
record ToInner1(String a, String b, String c) {}
record ToInner2(String d, String e, String additional) {}
record ToOuter(ToInner1 inner1, ToInner2 inner2) {}
My Mapper
@Mapping(target = "inner2.d", source = "fromOuter.inner2.d", qualifiedByName = "transform")
//@Mapping(target = "inner2.e", source = "fromOuter.inner2.e")
@Mapping(target = "inner2.additional", source = "additionalField")
ToOuter toOuter(FromOuter fromOuter, String additionalField);
@Named("transform")
default String transform(String original) {
return original.trim().toUpperCase();
}
Compiler Errors
java: Property "d" has no write accessor in ToInner2 for target name "inner2.d".
java: Property "additional" has no write accessor in ToInner2 for target name "inner2.additional".
Mutable Model
Using a mutable model, i.e., using the same fields, but making a no-args constructor, all-args constructor getters and setters for all the fields results in the following result test result
@Test
void toOuter() {
assertThat(
mapper.toOuter(
new FromOuter(new FromInner1("a", "b", "c"), new FromInner2(" d ", "e")),
"additional"))
.isEqualTo(new ToOuter(new ToInner1("a", "b", "c"), new ToInner2("D", "e", "additional")));
}
Expected :ToOuter(inner1=ToInner1(a=a, b=b, c=c), inner2=ToInner2(d=D, e=e, additional=additional))
Actual :ToOuter(inner1=ToInner1(a=a, b=b, c=c), inner2=ToInner2(d=D, e=null, additional=additional))
Workaround
@Mapping(target = "inner2", expression = "java(toInner2(fromOuter.inner2(), additionalField))") //compiles, but does not change anything
ToOuter toOuter(FromOuter fromOuter, String additionalField);
@Named("transform")
default String transform(String original) {
return original.trim().toUpperCase();
}
@Mapping(target = "d", source = "fromInner2.d", qualifiedByName = "transform")
@Mapping(target = "additional", source = "additionalField")
ToInner2 toInner2(FromInner2 fromInner2, String additionalField);
Upvotes: 0
Views: 29