Understanding MapStruct in Spring Boot for Java Bean Mapping

Introduction

Mapping between Java Beans is a common task in application development, especially in Spring Boot applications. Typically, you need to convert data between different layers, such as converting DTOs (Data Transfer Objects) to entities and vice versa. Manually writing mapping code can be tedious and error-prone. This is where MapStruct comes in handy. MapStruct is a code generator that greatly simplifies the process of mapping Java Beans by generating the mapping code at compile time.

What is MapStruct?

MapStruct is a Java-based code generation library that simplifies the mapping process between different Java Bean types. It uses annotations to define the mapping, and during compilation, it generates the implementation code for the mappers. This ensures type safety, reduces boilerplate code, and improves maintainability.

Key Features of MapStruct

  1. Type-Safe: MapStruct ensures that all mappings are checked at compile time, reducing runtime errors.
  2. Fast: Since MapStruct generates plain Java code, the performance of the mappings is very high.
  3. No Reflection: MapStruct does not use reflection, making it more performant compared to other mapping frameworks.

Setting Up MapStruct in a Spring Boot Project
 

1. Create a Spring Boot Project

Create a new Spring Boot project using Spring Initializr or manually set up a Maven project.

2. Add Dependencies

Add the necessary dependencies for MapStruct in your pom.xml.

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>1.5.2.Final</version>
    </dependency>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct-processor</artifactId>
        <version>1.5.2.Final</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.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>1.5.2.Final</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>

3. Define Entities and DTOs

Create a simple User entity and its corresponding UserDTO.

User.java

package com.example.demo.entity;
public class User {
    private Long id;
    private String name;
    private String email;

    // Getters and Setters
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

UserDTO.java

package com.example.demo.dto;
public class UserDTO {
    private Long id;
    private String name;

    // Getters and Setters
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

4. Define the Mapper Interface

Create a mapper interface for mapping between User and UserDTO.

UserMapper.java

package com.example.demo.mapper;
import com.example.demo.dto.UserDTO;
import com.example.demo.entity.User;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

@Mapper
public interface UserMapper {

    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);

    UserDTO userToUserDTO(User user);

    User userDTOToUser(UserDTO userDTO);
}

5. Create the Service Layer

Create a service class to use the mapper.

UserService.java

package com.example.demo.service;
import com.example.demo.dto.UserDTO;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import org.springframework.stereotype.Service;
@Service
public class UserService {

    public UserDTO getUserDTO(User user) {
        return UserMapper.INSTANCE.userToUserDTO(user);
    }

    public User getUser(UserDTO userDTO) {
        return UserMapper.INSTANCE.userDTOToUser(userDTO);
    }
}

6. Create the Controller

Create a controller to expose endpoints for testing the mapping.

UserController.java

package com.example.demo.controller;
import com.example.demo.dto.UserDTO;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/user")
    public UserDTO getUserDTO(@RequestParam Long id, @RequestParam String name, @RequestParam String email) {
        User user = new User();
        user.setId(id);
        user.setName(name);
        user.setEmail(email);
        return userService.getUserDTO(user);
    }

    @GetMapping("/userDTO")
    public User getUser(@RequestParam Long id, @RequestParam String name) {
        UserDTO userDTO = new UserDTO();
        userDTO.setId(id);
        userDTO.setName(name);
        return userService.getUser(userDTO);
    }
}

Running the Application

Run your Spring Boot application. You can test the endpoints by accessing them.

GET http://localhost:8080/user?id=1&name=John&[email protected]
GET http://localhost:8080/userDTO?id=1&name=John

These endpoints will demonstrate the mapping between User and UserDTO using MapStruct.

Conclusion

MapStruct is a powerful and efficient tool for mapping between Java Beans in a Spring Boot application. It reduces boilerplate code, ensures type safety, and improves maintainability. By following this guide, you can set up and use MapStruct in your Spring Boot applications to handle Java Bean mappings effortlessly.