Spring Boot MapStruct Example
Hello. In this tutorial, we will explore the mapstruct in a spring boot application.
1. Introduction
1.1 Mapstruct
Mapstruct is an annotation-based code generator that simplifies the mapping implementations between the java beans. The code is generated via the plain method invocation and thus it is fast, type-safe, and easy to understand. It is often used in the multi-tiered application required to map between different object models (such as Entities and Data Transfer Objects (DTO’s)).
- It simplifies the mapping of different object models by automation it
- Gets plugged into the Java Compiler
- Provides support to command-line builds (such as Maven, Gradle, etc.)
- Provides custom support for implementing a special behavior
1.2 Lombok
- Lombok is nothing but a small library that reduces the amount of boilerplate Java code from the project
- Automatically generates the getters and setters for the object by using the Lombok annotations
- Hooks in via the Annotation processor API
- Raw source code is passed to Lombok for code generation before the Java Compiler continues. Thus, produces properly compiled Java code in conjunction with the Java Compiler
- Under the
target/classes
folder you can view the compiled class files - Can be used with Maven, Gradle IDE, etc.
2. Spring Boot MapStruct Endpoints
Let us dive into some practice stuff and I am hoping that you are aware of the spring boot basics.
2.1 Tools Used for Spring boot application and Project Structure
We are using Eclipse Kepler SR2, JDK 8, and Maven. In case you’re confused about where you should create the corresponding files or folder, let us review the project structure of the spring boot application.
Let us start building the application!
3. Creating a Spring Boot application
Below are the steps involved in developing the application.
3.1 Maven Dependency
In the pom.xml
file we will define the required dependencies such as Spring boot stater, h2 database, Lombok, and Mapstruct. We will also specify the plugin’s information required for the Mapstruct annotation processor to work alone and in conjugation with the Lombok.
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.2</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example.mapstruct</groupId> <artifactId>spring-mapstruct-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>spring-mapstruct-demo</name> <description>Springboot and mapstruct</description> <properties> <java.version>1.8</java.version> <org.mapstruct.version>1.4.2.Final</org.mapstruct.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>${org.mapstruct.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <!-- depending on your project --> <target>1.8</target> <!-- depending on your project --> <annotationProcessorPaths> <path> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>${org.mapstruct.version}</version> </path> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> </path> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok-mapstruct-binding</artifactId> <version>0.2.0</version> </path> <!-- other annotation processors --> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build> </project>
3.2 Application properties file
Create a properties file in the resources
folder and add the following content to it. The file will contain information about the database connectivity, spring jpa, and the h2-console.
application.properties
server.port=9090 spring.application.name=spring-mapstrut-demo # datasource settings spring.datasource.driver-class-name=org.h2.Driver spring.datasource.password= spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.username=sa # h2 settings spring.h2.console.enabled=true spring.h2.console.path=/h2-console # jpa settings spring.jpa.database-platform=org.hibernate.dialect.H2Dialect spring.jpa.hibernate.ddl-auto=create-drop spring.jpa.properties.hibernate.show_sql=true
3.3 Java Classes
Let us write the important java class(es) involved in this tutorial. The other non-important classes for this tutorial like the model, data transfer object (dto), service and repository can be downloaded from the Downloads section.
3.3.1 Implementation/Main class
Add the following code to the main class to bootstrap the application from the main method. Always remember, the entry point of the spring boot application is the class containing @SpringBootApplication
annotation and the static main method.
SpringMapstructDemoApplication.java
package com.jcg.mapstruct; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @Slf4j @SpringBootApplication public class SpringMapstructDemoApplication { public static void main(String[] args) { SpringApplication.run(SpringMapstructDemoApplication.class, args); log.info("spring boot and mapstruct application"); } }
3.3.2 Mapper class
Add the following code to the mapper class which will be responsible to map the entity (database) object to the data transfer object (dto) object and vice versa. Here the componentModel
attribute will help to inject the object of this interface as an Autowired dependency in other classes.
CommerceMapper.java
package com.jcg.mapstruct.mapper; import com.jcg.mapstruct.dto.CommerceDto; import com.jcg.mapstruct.model.Commerce; import org.mapstruct.InheritInverseConfiguration; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; import java.util.List; // @Mapper(componentModel = "spring", imports = UUID.class) @Mapper(componentModel = "spring") public interface CommerceMapper { CommerceMapper INSTANCE = Mappers.getMapper(CommerceMapper.class); @Mapping(source = "commerce.promotionCode", target = "code") // @Mapping(target = "refId", expression = "java(UUID.randomUUID().toString())") CommerceDto modelToDto(Commerce commerce); List<CommerceDto> modelsToDtos(List<Commerce> commerces); @InheritInverseConfiguration Commerce dtoToModel(CommerceDto commerceDto); }
3.3.3 Controller class
Add the following code to the controller class. The class will be responsible to handle the incoming HTTP requests, save or get the data from the database and map it to/from the data transfer object (dto) class.
CommerceController.java
package com.jcg.mapstruct.controller; import com.jcg.mapstruct.dto.CommerceDto; import com.jcg.mapstruct.mapper.CommerceMapper; import com.jcg.mapstruct.model.Commerce; import com.jcg.mapstruct.service.CommerceService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController @RequestMapping("/commerce") public class CommerceController { @Autowired CommerceService service; @Autowired CommerceMapper mapper; // http://localhost:9090/commerce/ /* Sample postman request - { "id": "{{$randomInt}}", "name": "{{$randomProduct}}", "price": "{{$randomPrice}}", "code": "{{$randomBankAccountBic}}", "refId": "{{$randomInt}}", "quantity": "{{$randomInt}}" } */ @PostMapping("/") @ResponseStatus(HttpStatus.CREATED) public void save(@RequestBody CommerceDto dto) { Commerce commerce = mapper.dtoToModel(dto); service.save(commerce); } // http://localhost:9090/commerce/ @GetMapping("/") @ResponseStatus(HttpStatus.OK) public List<CommerceDto> findAll() { return mapper.modelsToDtos(service.findAll()); } // http://localhost:9090/commerce/1 @GetMapping("/{id}") @ResponseStatus(HttpStatus.OK) public CommerceDto findOne(@PathVariable("id") int id) { return mapper.modelToDto(service.findOne(id)); } // other crud operations left for brevity. }
4. Run the Application
To execute the application, right-click on the SpringMapstructDemoApplication.java
class, Run As -> Java Application
.
5. Project Demo
To test the application endpoints we will use the postman tool. However, you’re free to use any tool of your choice for interacting with the application endpoints.
Application endpoints
// http://localhost:9090/commerce/ /* Sample postman request - { "id": "{{$randomInt}}", "name": "{{$randomProduct}}", "price": "{{$randomPrice}}", "code": "{{$randomBankAccountBic}}", "refId": "{{$randomInt}}", "quantity": "{{$randomInt}}" } */ // HTTP GET // Get products // http://localhost:9090/commerce/ // HTTP GET // Get product by id // http://localhost:9090/commerce/1
That is all for this tutorial and I hope the article served you whatever you were looking for. Happy Learning and do not forget to share!
6. Summary
In this tutorial, we learned the Mapstruct and Lombok theory along with a practical implementation of it in a spring application. You can download the sample application as an Eclipse project in the Downloads section.
7. Download the Project
This was an example of mapstruct implementation in a spring application.
You can download the full source code of this example here: Spring Boot MapStruct Example