That Java Guy

  • Home
  • Contact
  • About

Code generators: MapStruct 101

by That Java Guy July 31, 2017 code generation Java MapStruct

By this post I'll be starting a series of posts dedicated to different code generators, which makes our lives easier, and more fun. As we don't need to write boring code!

Did you ever find yourself in a situation where you needed to copy data from one Java bean to another? Or maybe from an Entity to DTO? Does next code look familiar to you ?
MapStruct to the rescue! MapStruct is an Annotation Processor based code generator. It allows you to specify mappings between Java bean types through declaring interface of such mapping. And the code generation part will provide an implementation.

For demo purposes of this post let's start with a simple example. Assume we have an @Embeddable AddressEntity class, as part of our domain model. And we'd like to create Address POJOs from this embeddable.

We could have done it with the help of a constructor:
Or maybe with a static method:
And it looks OK, and seems easy enough to write. But what if we do have more properties? A lot more properties... Or maybe we are just that lazy :). So if we would do it with MapStruct it'll look like this:
Looks easy, right?

Let's look closer at what should be done to create a mapper. First we need to create an interface (called AddressMapper in our case) and put @Mapper annotation on it. This annotation is a marker annotation for MapStruct. It'll find all mappers and generate the implementation for them. If you'd like you can make mappers from abstract classes as well, but personally I prefer interfaces.

As we would like to access our mapper somehow - INSTANCE interface member is defined. To get the generated mapper we need to call Mappers.getMapper( ... ).

Now how this would work on practice and when this code generation will happen? As it's an Annotation Processor based code generator we should include it in our build process. In case of Maven project it can be done by specifying annotation processor in Maven's compiler plugin like this:
So that was easy. But what if we have a more complex data types?

Let's consider UserEntity and User pair and create a mapper for them:
In this case, we see that we don't have one to one match between properties of both types. Some have different names (UserEntity.lastVisit and User.visit), some are inside of value objects (UserEntity.userName and UserEntity.password inside User.credentials), enum is represented as a string, and even some are missing (like id). We also have properties from previously considered addresses pair as well.
Here's a possible way to define a mapper for such type pair:
First notice that @Mapper annotation has additional uses parameter defined. It is needed as we would like our mapper to use the mappings that we defined in AddressMapper for address types. Next let's move to mapping method UserMapper#toUser. There's a few @Mapping annotations declared. It's easy to see that they allow us to define a source property and where it is located in the target type. So this will help us to handle naming mismatch, or cases where properties are inside of other beans. The only thing left to notice here is a default method UserMapper#genderToString. As we see it converts an enum - to a string. This method will be picked up by MapStruct and used in mapping enum to string. It also shows a way on how a complex mapping can be done by hand, if needed. You can provide you own mapping functions with complex logic which later can be used by MapStruct.

And here's a test to make sure that everything works as expected:
MapStruct is interesting not only because it saves time by generating mapping code, but by the concept of mapper by itself. Even if you end up with writing parts of mapping code on your own, a mapper will give you a separation of concerns and you wouldn't need any constructors or factory methods in your bean types.

All the examples with tests and configurations can be found in this GitHub repository.

To be continued...
READ MORE
SHARE :

About Me




Marko Bekhta


Software engineer.


Follow Me

Labels

1z0-803 1z0-804 1z0-810 Bean Validation Certification Code Europe code generation Collections Collectors conference Enum exam Hibernate Hibernate Validator Immutables Java JPA MapStruct OCA OCP Oracle Stream validation
  • Popular
  • Recent
  • Comments
    JPA: Mapping Enums the right way
    Bean Validation: Validation based on multiple properties
    JPA: Ways to map many-to-many relationships with additional information

Instagram

About

Popular Posts

  • JPA: Mapping Enums the right way
    There are quite a few different approaches one can take to map enums in entities. I would separate them into three groups: The ones which ...
  • Bean Validation: Validation based on multiple properties
    Quite often there is a need to apply validation to some of the bean's properties based on the state of the other properties of the s...
  • JPA: Ways to map many-to-many relationships with additional information
    In this post we will take a look at couple of ways how many-to-many relationships, which have additional information, can be mapped to entit...
  • JPA: a handy utility for Enums to combine with AttributeConverter
    As it was discussed in one of the previous posts JPA: Mapping Enums the right way , JPA 2.1 standardized  AttributeConverter s, which can, f...
  • Java 9: What's interesting and new. Collection API
    Java 9 brings a lot of big new features, tools and API enhancements. But somehow the most excitement comes from a few simple additions to...

Labels

  • Certification
  • Code Europe
  • Java
  • Oracle
  • conference
  • exam

Template Created By : ThemeXpose . All Rights Reserved.