In all my previous post under MapStruct, whenever MapStruct has to create a target object it used constructor. What if the target class follows builder pattern instead of using a simple constructor.
In this post under MapStruct where object is mapped from source to destination class. I will show with example how to instruct MapStruct to use builder pattern when creating destination objects.
By default when creating target objects, MapStruct will first check whether the target class uses builder pattern to create itself, if not, then it calls the constructor.
Lets take “StudentDTO” as destination class. We need to modify this class in such a way that MapStruct uses builder pattern to create its objects instead of constructor.
To make the MapStruct use builder pattern to create destination object, we follow the below rules.
1) We need to create a static builder class which will build the destination object.
In our example, I created a static nested class “StudentDTOBuilder” within the destination class
2) The static builder class will have parameterless non-static “build” method which will create and return an instance of target class.
In our example, I will have “build” method in “StudentDTOBuilder” class.
3) We need to create a private constructor in the target class which will take instance of builder class as an argument.
In our example, I will have a private constructor for “StudentDTO” which will take an instance of “StudentDTOBuilder” as an constructor argument.
Below is the class structure for “StudentDTO” class with builder class inside it.
StudentDTO
package package21;
public class StudentDTO {
private int id;
private String name;
private StudentDTO(StudentDTOBuilder studentDTOBuilder) {
this.id = studentDTOBuilder.id;
this.name = studentDTOBuilder.name;
}
public static StudentDTOBuilder builder() {
return new StudentDTOBuilder();
}
public static class StudentDTOBuilder {
private int id;
private String name;
public StudentDTOBuilder id(int id) {
this.id = id;
return this;
}
public StudentDTOBuilder name(String name) {
this.name = name;
return this;
}
public StudentDTO build() {
return new StudentDTO(this);
}
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(this.id).append(":");
stringBuilder.append(this.name);
return stringBuilder.toString();
}
}
In this way we can instruct MapStruct to use builder pattern when creating instance of destination class.
Below is the class structure of source class “Student” for your reference
Student
package package21;
public class Student {
private int id;
private String name;
//Removed getter, setter, and toString for brevity
}
Below is the class structure of Mapper interface for your reference
Mapper interface
package package21;
import org.mapstruct.Mapper;
@Mapper
public interface StudentMapper {
StudentDTO getDTOFromModel(Student student);
}
Below is the main class for your reference
Main class
package package21;
import org.mapstruct.factory.Mappers;
public class Example21 {
public static void main(String[] args) {
StudentMapper studentMapper = Mappers.getMapper(StudentMapper.class);
Student student = new Student();
student.setId(1);
student.setName("John");
StudentDTO studentDTO = studentMapper.getDTOFromModel(student);
System.out.println(studentDTO);
}
}