In this post under MapStruct, I will show with example how to call custom mapping method from another mapper interface code.
In previous post, I showed you how to add custom mapping method to a mapper interface.
But what if the same custom mapping method is also required by another mapper interface, we cannot copy paste the custom mapping code in another mapper interface.
This will result in code duplication which we have to avoid as much as possible.
We have to write the code in such a way that the same custom mapping method is shared by both the mapper interface.
In this post I will show how to do that.
For our example, I will create the below pojo classes.
Person
package package36;public class Person { private int id; private String name; private Address address; //Removed getter and setter for brevity}
Student
package package36;public class Student { private int id; private String name; private Address address; //Removed getter and setter for brevity}
As you see from the above pojo classes, both “Person” and “Student” class depends upon “Address” class, which is as shown below
package package36;public class Address { private String addressLine1; private String addressLine2; private String state; private String country; //Removed getter and setter for brevity}
Now lets see the corresponding DTO classes to which we have to map
PersonDTO
package package36;public class PersonDTO { private int id; private String name; private AddressDTO addressDTO; //Removed getter, setter and toString for brevity}
StudentDTO
package package36;public class StudentDTO { private int id; private String name; private AddressDTO addressDTO; //Removed getter, setter and toString for brevity}
AddressDTO
package package36;public class AddressDTO { private String streetLine; private String state; private String country; //Removed getter, setter and toString for brevity}
If you see “Address” and “AddressDTO” classes, they have different ways to store address information.
“Address” class has two properties to store street address “addressLine1” and “addressLine2”, whereas “AddressDTO” has only one property “addressLine”.
So we need a custom mapper to map “Address” objects to “AddressDTO” objects and it should be shared by both “PersonMapper” and “StudentMapper” interface.
Below is the class containing the custom mapping method
AddressMapper
package package36;public class AddressMapper { public AddressDTO addressToAddressDTO(Address address) { AddressDTO addressDTO = new AddressDTO(); addressDTO.setAddressLine(address.getAddressLine1() + ", " + address.getAddressLine2()); addressDTO.setState(address.getState()); addressDTO.setCountry(address.getCountry()); return addressDTO; }}
Now the above code should be shared by “PersonMapper” and “StudentMapper”. So we will use the “uses” attribute of “@Mapper” annotation as shown below
PersonMapper
package package36;import org.mapstruct.Mapper;import org.mapstruct.Mapping;@Mapper(uses = AddressMapper.class)public interface PersonMapper { @Mapping(target = "addressDTO", source = "address") PersonDTO getDTOFromModel(Person person);}
In the above code at line 6, I use “@Mapper” annotation with “uses” attribute and specifying “AddressMapper” class object as value.
Similarly for “StudentMapper” also as shown below
StudentMapper
package package36;import org.mapstruct.Mapper;import org.mapstruct.Mapping;@Mapper(uses = AddressMapper.class)public interface StudentMapper { @Mapping(target = "addressDTO", source = "address") StudentDTO getDTOFromModel(Student student);}
In the above code also at line 6, I use “@Mapper” annotation with “uses” attribute and specifying “AddressMapper” class object as value.
In this way I am sharing the address mapper code between “PersonMapper” and “AddressMapper” interface.
Using the “uses” attribute of “@Mapper” I am instructing the MapStruct framework to use “AddressMapper” class when mapping “Address” property to “AddressDTO” property.
Below is the main class for your reference
Main class
package package36;import org.mapstruct.factory.Mappers;public class Example36 { public static void main(String[] args) { StudentMapper studentMapper = Mappers.getMapper(StudentMapper.class); PersonMapper personMapper = Mappers.getMapper(PersonMapper.class); Address studentAddress = new Address(); studentAddress.setAddressLine1("student address line 1"); studentAddress.setAddressLine2("student address line 2"); studentAddress.setState("VA"); studentAddress.setCountry("USA"); Student student = new Student(); student.setId(1); student.setName("John"); student.setAddress(studentAddress); Address personAddress = new Address(); personAddress.setAddressLine1("person address line 1"); personAddress.setAddressLine2("person address line 2"); personAddress.setState("WA"); personAddress.setCountry("USA"); Person person = new Person(); person.setId(1); person.setName("Troy"); person.setAddress(personAddress); PersonDTO personDTO = personMapper.getDTOFromModel(person); System.out.println(personDTO); StudentDTO studentDTO = studentMapper.getDTOFromModel(student); System.out.println(studentDTO); }}
Below is the output
Output
PersonDTO{id=1, name='Troy', addressDTO=AddressDTO{addressLine='person address line 1, person address line 2', state='WA', country='USA'}}StudentDTO{id=1, name='John', addressDTO=AddressDTO{addressLine='student address line 1, student address line 2', state='VA', country='USA'}}
In this way, we can call custom mapping method from another mapper interface code.