Reputation: 21
I'm trying to use MapStruct to map two objects. I have been searching for a while and I haven't been able to find anything, though I'm new to programming so I'm sure it's easier than I'm making it.
Here is some stripped back code (Note that the real code is more complex, with the child object from the arraylist not being the same type as the destination objects child variable as it is here):
SourceObject
public class SourceObject {
public ArrayList<ListObject> list = new ArrayList<ListObject>();
public SourceObject() {
list.add(new ListObject());
}
}
ListObject
public class ListObject {
public DetailsObject details = new DetailsObject();
public ListObject() {
details.forename="SourceForename";
details.surname="SourceSurname";
}
}
DestinationObject
public class DestinationObject {
public DetailsObject details = new DetailsObject();
public DestinationObject() {
details.forename="DestinationForename";
details.surname="DestinationSurname";
}
}
DetailsObject
public class DetailsObject {
public String forename;
public String surname;
}
Mapper
@Mappings({
@Mapping(target="details.forename", source="list.get(0).details.forename"),
@Mapping(target="details.surname", source="list.get(0).details.surname"),
})
DestinationObject toDestination(SourceObject source);
This will work fine if I put DetailsObject directly inside SourceObject, but becomes a problem when I try to take it from the list. The error I get is:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.5.1:compile (default-compile) on project template: Compilation failure: Compilation failure:
[ERROR] .../src/main/java/Mapper/SourceToDestinationMap.java:[12,13] No property named "list.get(0).details.surname" exists in source parameter(s). Did you mean "list.empty"?
[ERROR] .../src/main/java/Mapper/SourceToDestinationMap.java:[11,9] No property named "list.get(0).details.forename" exists in source parameter(s). Did you mean "list.empty"?
EDIT: Current state of the mapper:
@Mapper
public interface SourceToDestinationMap {
@Mapping(target = "details", source = "list")
DestinationObject toDestination(SourceObject source);
default DetailsObject map(List<ListObject> source) {
return map(source.get(0));
}
DetailsObject map(ListObject source);
}
Upvotes: 1
Views: 18183
Reputation: 1
You could also create a "wrapper" method (getFirstElement) on the SourceObject:
public class SourceObject {
public ArrayList<ListObject> list = new ArrayList<ListObject>();
public SourceObject() {
list.add(new ListObject());
}
public getFirstElement(){
return list.get(0);
}
So in your initial mapping you can say:
@Mappings({
@Mapping(target="details.forename", source="firstElement.details.forename"),
@Mapping(target="details.surname", source="firstElement.details.surname"),
})
DestinationObject toDestination(SourceObject source);
Upvotes: 0
Reputation: 21423
The mapping you are trying to do is not possible, since you are mixing bean properties and bean functions.
You can't use @Mapping(source = "list.get(0).XXX")
. Using indexes to access elements of a list is not yet supported see #1321.
A way to solve your problem would be to use Qualifiers in the same way that they are used in the mapstruct-iterable-to-non-iterable example.
Or you can provide your own method that would perform the mapping.
@Mapper
public interface MyMapper {
@Mapping(target = "details", source = "list")
DestinationObject toDestination(SourceObject source);
default DetailsObject map(List<ListObject> source) {
return source != null && !source.isEmpty() ? map(source.get(0)) : null;
}
DetailsObject map(ListObject source);
}
MapStruct will then generate the correct code.
Another alternative would be to use @Mapping(expression="java()"
.
Your mapper will then look like:
@Mapper
public interface MyMapper {
@Mapping(target = "details.forename", expression = "java(source.list.get(0).details.forename)")
@Mapping(target = "details.surname", expression = "java(source.list.get(0).details.surname)")
DestinationObject toDestination(SourceObject source);
}
Note for expression
. MapStruct will use the text from the expression as is, and won't perform any validation checks. Therefore it can be a bit brittle, as there won't be null
and empty checks.
Upvotes: 10