How to use MapStruct to map to immutable types?

3,590 views
Skip to first unread message

Axel von Engel

unread,
May 2, 2018, 3:50:45 AM5/2/18
to mapstruct-users
Hello everyone,

we're currently looking at different mapping frameworks, since we had some troubles with the way Orika is configured. I like MapStruct pretty much so far, only problem is we usually make the model types immutable, if possible.

I created an example project to illustrate this better: https://github.com/avonengel/mapstruct-immutable

So far, I found that providing a hand-written method that maps to the immutable model works, as long as that model does not contain references to another mapped type. In the example, SomeType contains a java.util.UUID, which also requires a Mapper, as it does not have an accessible no-arg constructor, but needs to be constructed using the static fromString method. So how do I use the StringToUuidMapper from within that hand-written method? Of course I could just call Mappers.getMapper, but what would be the point of the Spring integration, then? Also, this will fail as soon as the Mapper I depend on has yet another dependency: Mappers.getMapper doesn't initialize @Autowired fields - or at least that would be very strange.

Any suggestions? The only workable way to get around this was to create builders for each immutable type (which is a good idea anyway), and make MapStruct map to the builder class instead. Then write a hand-written mapping method to call build() on the builder.

Cheers
Axel

Filip Hrisafov

unread,
May 4, 2018, 3:06:25 PM5/4/18
to mapstruct-users
Hey Axel,


We are really glad that you like the project.

Thanks for the example project. Currently MapStruct is not able to create immutable types through a constructor. We have issue #73 for such support.

Calling Mappers.getMapper is only meant if you are using the default component model. In case of Spring you would have to use injections to get a hold of your mappers.

You have multiple choices going forward:

* Use an abstract class as your mapper. In this class you can inject your other mapper through a setter and then use it from there
* Use a builder

In case you use a builder in 1.2.0.Final you would have to map against the builder. However, starting from the next 1.3.0.Beta1 release (that should come out soon) there will be out of the box support for builders.

The only thing that you would need to do is to make sure that there is a single public static parameterless method on your type.

I hope this helps you. In case you have any other questions feel free to ask them here or in our gitter chat.

Cheers,
Filip
Reply all
Reply to author
Forward
0 new messages