Backend Development 9 min read

Using MapStruct for Efficient Entity‑DTO Mapping in Java

This article introduces the open‑source MapStruct library for Java, showing how to configure Maven dependencies, define entity and DTO classes with Lombok, create mapper interfaces, and perform simple and advanced object conversions such as list mapping, multi‑object merging, and default value handling.

Java Captain
Java Captain
Java Captain
Using MapStruct for Efficient Entity‑DTO Mapping in Java

Developers often struggle with writing boilerplate code for converting between entities, especially when there are many fields. This guide presents MapStruct, an open‑source project that simplifies and elegantly handles such conversions.

First, add the required Maven configuration:

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <org.mapstruct.version>1.4.1.Final</org.mapstruct.version>
    <org.projectlombok.version>1.18.12</org.projectlombok.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>${org.mapstruct.version}</version>
    </dependency>
    <!-- Lombok should be provided, not on the classpath -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>${org.projectlombok.version}</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct-processor</artifactId>
        <version>${org.mapstruct.version}</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok</artifactId>
                        <version>${org.projectlombok.version}</version>
                    </path>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${org.mapstruct.version}</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>

Make sure to use Maven compiler plugin version 3.6.0 or higher and Lombok version 1.16.16 or higher; otherwise you may encounter compilation errors such as missing getters/setters.

Define your entity and DTO classes using Lombok annotations to reduce boilerplate:

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private String name;
    private int age;
    private GenderEnum gender;
    private Double height;
    private Date birthday;
}

public enum GenderEnum {
    Male("1", "男"),
    Female("0", "女");
    private String code;
    private String name;
    public String getCode() { return this.code; }
    public String getName() { return this.name; }
    GenderEnum(String code, String name) { this.code = code; this.name = name; }
}

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class StudentVO {
    private String name;
    private int age;
    private String gender;
    private Double height;
    private String birthday;
}

Create a mapper interface annotated with @Mapper . MapStruct will generate the implementation at compile time:

@Mapper
public interface StudentMapper {
    StudentMapper INSTANCE = Mappers.getMapper(StudentMapper.class);

    @Mapping(source = "gender.name", target = "gender")
    @Mapping(source = "birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss")
    StudentVO student2StudentVO(Student student);
}

Use the mapper in your code:

public class Test {
    public static void main(String[] args) {
        Student student = Student.builder()
            .name("小明")
            .age(6)
            .gender(GenderEnum.Male)
            .height(121.1)
            .birthday(new Date())
            .build();
        System.out.println(student);
        // Actual conversion
        StudentVO studentVO = StudentMapper.INSTANCE.student2StudentVO(student);
        System.out.println(studentVO);
    }
}

Advanced usages include list conversion, merging multiple source objects into one target, and specifying default values.

1. List Conversion

@Mapper
public interface StudentMapper {
    // existing mappings ...
    List
students2StudentVOs(List
studentList);
}

public class Test {
    public static void main(String[] args) {
        Student student = /* same as before */;
        List
list = new ArrayList<>();
        list.add(student);
        List
result = StudentMapper.INSTANCE.students2StudentVOs(list);
        System.out.println(result);
    }
}

2. Multiple Objects to One Object

@Mapper
public interface StudentMapper {
    @Mapping(source = "student.gender.name", target = "gender")
    @Mapping(source = "student.birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss")
    @Mapping(source = "course.courseName", target = "course")
    StudentVO studentAndCourse2StudentVO(Student student, Course course);
}

public class Test {
    public static void main(String[] args) {
        Student student = /* same as before */;
        Course course = Course.builder().id(1L).courseName("语文").build();
        StudentVO studentVO = StudentMapper.INSTANCE.studentAndCourse2StudentVO(student, course);
        System.out.println(studentVO);
    }
}

3. Default Values

@Mapper
public interface StudentMapper {
    @Mapping(source = "student.gender.name", target = "gender")
    @Mapping(source = "student.birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss")
    @Mapping(source = "course.courseName", target = "course")
    @Mapping(target = "name", source = "student.name", defaultValue = "张三")
    StudentVO studentAndCourse2StudentVO(Student student, Course course);
}

MapStruct thus provides a powerful, compile‑time solution for reducing manual mapping code, improving readability and maintainability of Java backend projects.

JavamavenMapStructLombokEntity Mapping
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.