Boot

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.

Spring boot Mapstruct - project structure
Fig. 1: Project structure

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.

Spring boot Mapstruct - run the app
Fig. 2: Run the 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.

Download
You can download the full source code of this example here: Spring Boot MapStruct Example

Yatin

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button