Issue
On our project, it's customary to use mapstruct for all mappings. In this unique case, I'm not creating an Entity, but rather a DTO. However this DTO requires I generate a UUID, and I'd rather not use the expression option.
@Mapping(target = "trackId", expression = "java(UUID.randomUUID().toString())")
FileUploadRequest inventoryToFileUpload(Inventory inventory);
I'd much rather have the compiler as a friend at all times in life. Also what do you do if the generation strategy isn't a 30 character width one-liner?
My preferred method is as follows:
@Mapping(target = "trackId", qualifiedByName = "generateUUID"),
FileUploadRequest inventoryToFileUpload(Inventory inventory);
@Named("generateUUID")
default String generateUuid() {
return UUID.randomUUID().toString();
}
Sadly the above does not work. I have to give it a source, which is nonsense. Or maybe there's a way of specifying I don't rely on any parameter?
Here is code that does work:
// Ommiting other mappings for clarity
@Mapping(target = "trackId", source = "id", qualifiedByName = "generateUUID")
FileUploadRequest inventoryToFileUpload(Inventory inventory);
@Named("generateUUID")
default String generateUuid(final String nonsense) {
return UUID.randomUUID().toString();
}
This generates the following line of code
fileUploadRequest.setTrackId(this.generateUuid(inventory.getId()));
But ... the parameter is superflous, as can easily be seen. I know that this does not ACTUALLY matter. But it seems either like an oversight, or me not understanding how to declare that I do not have a source for this, I just want the mapper to call my method.
Again, expression
is not a valid answer, please do not propose it. UNLESS you can do expression = "java(generateUuid())"
?
Solution
MapStruct is about mapping between different objects. That's why you can't use an empty method (without expression
).
What I would suggest is to indeed use Mapping#expression
. However, to simplify it for you, you can use something like:
public class MappingUtils {
public static String GENERATE_UUID_EXPRESSION = "java(<package>.MappingUtils.generateUuid())"
public static String generateUuid() {
return UUID.randomUUID().toString();
}
}
And then in your mappers you can do:
@Mapper
public interface MyMapper {
@Mapping(target = "trackId", expression = MappingUtils. GENERATE_UUID_EXPRESSION)
FileUploadRequest inventoryToFileUpload(Inventory inventory);
}
Doing this you have the expression in a single place and you have a a method that performs the generation.
The generated code will use the full qualified name of the MappingUtils
. In case you want to avoid that you will need to add MappingUtils
to Mapper#imports
and then use MappingUtils.class.getName()
instead in your expression.
Note: You'll need to replace what is in <package>
with the package location of the MappingUtils
.
Answered By - Filip
Answer Checked By - Katrina (JavaFixing Volunteer)