Last updated on December 2nd, 2024
The MapStruct library provides us with the qualifiedByName attribute feature in the @Mapping annotation where we can specify the name mentioned in the @Name(“—“) annotation of the custom method of the Mapper interface. To use qualifiedByName in MapStruct first, we must create a MapStruct Mapper interface and then make a custom method annotated with @Name(“—–”) annotation after we must use @Mapping annotation with qualifiedByName attribute in the mapper method. In this topic, we will learn how to use qualifiedByName in MapStruct using the Spring Boot application.
Use QualifiedByName in MapStruct
We need to follow some steps to use qualifiedByName in MapStruct. These are the following steps are:
1. Create MapStruct Mapper Interface
We need to create an interface which is annotated with @Mapper annotation.
Example
@Mapper
public interface WebSeriesMapper {
}
2. Create a Custom Method
We need to create a custom method with @Name annotation in the Mapper interface.
Example
@Mapper
public interface WebSeriesMapper {
@Named("intToString")
default String intToString(int status) {
return status == 1 ? "yes" : "no";
}
}
3. Use @Mapping
We need to create a mapper method annotated with @Mapping annotation its qualifiedByName attribute in the Mapper interface.
Example
@Mapper
public interface WebSeriesMapper {
@Named("intToString")
default String intToString(int status) {
return status == 1 ? "yes" : "no";
}
@Mapping(source = "status", target = "status", qualifiedByName = "stringToInt")
WebSeries dtoToEntity(WebSeriesDTO dto);
}
Step-by-step Guide to Use QualifiedByName in MapStruct
Let’s create a Spring Boot Application step-by-step guide using qualifiedByName in MapStruct. We will create an example of WebSeries saving and retrieving by mapping DTO to Entity and vice versa with different field types by using custom conversion logic with the help of qualifiedByName in MapStruct using API endpoints.
These are the following steps:
- Create a Spring Boot Project
- Setup in the IDE
- Add MapStruct Dependencies
- Configure H2 Database
- Create a JPA Entity
- Create a DTO class
- Create a Repository Interface
- Create a MapStruct Mapper Interface
- Create a Service Interface
- Implement the Service Interface
- Create a Controller
- Run the Spring Boot Application
1. Create a Spring Boot Project
We are creating a Spring Boot Project from the web tool Spring Initializr. By Providing details for the project and select the following Maven dependencies:
- Spring Web
- Spring Data JPA
- H2 Database
- Lombok
2. Setup in the IDE
We use Eclipse IDE to set up and configure the created Spring Boot Project. You can use other IDE to set up and configure the Spring Boot project.
Project Structure of Spring Boot
This image shows the project structure of Spring Boot in Eclipse IDE.
3. Add MapStruct Dependencies
We need to add MapStruct dependencies in the project pom.xml file.
<!-- MapStruct dependency -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.6.2</version>
</dependency>
<!-- For MapStruct processor-->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.6.2</version>
<scope>provided</scope>
</dependency>
Maven Dependency
This is the complete Maven dependencies for this application which will implement mapping between DTO and Entity using MapStruct’s qualifiedByName feature in Spring Boot.
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>3.3.0</version>
<relativePath />
<!-- lookup parent from repository -->
</parent>
<groupId>com.springjava</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.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.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- MapStruct dependency -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.6.2</version>
</dependency>
<!-- For MapStruct processor-->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.6.2</version>
<scope>provided</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>
</plugins>
</build>
</project>
4. Configure H2 Database
We are going to configure the H2 database connection in the application.properties file.
application.properties
#H2 Database Configuration
spring.datasource.url=jdbc:h2:mem:test
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update
spring.h2.console.enabled=true
5. Create a JPA Entity
Let’s create a JPA Entity class. For example, consider a WebSeries entity and use Lombok for generating setter and getter methods, a constructor, etc.
WebSeries.java
package com.springjava.entity;
import java.time.LocalDate;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Data;
@Data
@Entity
public class WebSeries {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private LocalDate release;
private int status;
}
6. Create a DTO class
We are creating a DTO class WebSeriesDTO with the same fields, different field names and field types.
WebSeriesDTO.java
package com.springjava.dto;
import lombok.Data;
@Data
public class WebSeriesDTO {
private Long id;
private String name;
private String releaseDate;
private String status;
}
7. Create a Repository Interface
Create a repository interface for the WebSeries JPA Entity class that interface extends the JpaRepository interface to perform persistence operations on the web_series database table.
WebSeriesRepo.java
package com.springjava.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.springjava.entity.WebSeries;
public interface WebSeriesRepo extends JpaRepository<WebSeries, Long> {
}
8. Create a MapStruct Mapper Interface
We are creating a Mapper Interface WebSeriesMapper for mapping DTO to Entity and vice versa with different field names and field types using MapStruct.
WebSeriesMapper.java
package com.springjava.utility;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Named;
import org.mapstruct.factory.Mappers;
import com.springjava.dto.WebSeriesDTO;
import com.springjava.entity.WebSeries;
@Mapper
public interface WebSeriesMapper {
WebSeriesMapper INSTANCE = Mappers.getMapper(WebSeriesMapper.class);
//Method to map status as Integer to String
@Named("intToString")
default String intToString(int status) {
return status == 1 ? "yes" : "no";
}
//Method to map status as String to Integer
@Named("stringToInt")
default Integer stringToInt(String status) {
return status.equals("yes") ? 1 : 0;
}
//Mapping DTO to Entity with different field type(String to LocalDate)
@Mapping(source = "releaseDate", target = "release", dateFormat = "d-MM-yyyy")
@Mapping(source = "status", target = "status", qualifiedByName = "stringToInt")
WebSeries dtoToEntity(WebSeriesDTO dto);
//Mapping Entity to DTO with different field type(LocalDate to String)
@Mapping(source = "release", target = "releaseDate", dateFormat = "d-MM-yyyy")
@Mapping(source = "status", target = "status", qualifiedByName = "intToString")
WebSeriesDTO entityToDto(WebSeries entity);
}
9. Create a Service Interface
Create a Service interface WebSeriessService with some method declaration.
WebSeriesService.java
package com.springjava.service;
import java.util.List;
import com.springjava.dto.WebSeriesDTO;
public interface WebSeriesService {
void saveAll(List<WebSeriesDTO> dtoList);
List<WebSeriesDTO> getAll();
}
10. Implement the Service Interface
Implement the WebSeriesService interface in the WebSeriesServiceImpl class. This class is annotated with @Service annotation, where we inject WebSeriesRepo to call all its methods(saveAll() and findAll()).
WebSeriesServiceImpl.java
package com.springjava.service;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.springjava.dto.WebSeriesDTO;
import com.springjava.entity.WebSeries;
import com.springjava.repository.WebSeriesRepo;
import com.springjava.utility.WebSeriesMapper;
@Service
public class WebSeriesServiceImpl implements WebSeriesService {
@Autowired
private WebSeriesRepo webSeriesRepo;
@Override
public void saveAll(List<WebSeriesDTO> dtoList) {
List<WebSeries> webSeriesList = new ArrayList<>();
for (WebSeriesDTO dto : dtoList) {
//Use MapStruct for converting DTO to Entity with different data type
WebSeries webSeries = WebSeriesMapper.INSTANCE.dtoToEntity(dto);
webSeriesList.add(webSeries);
}
webSeriesRepo.saveAll(webSeriesList);
}
@Override
public List<WebSeriesDTO> getAll() {
List<WebSeriesDTO> dtoList = new ArrayList<>();
for(WebSeries webSeries: webSeriesRepo.findAll()) {
//Use MapStruct for converting Entity to DTO with different data type
WebSeriesDTO dto = WebSeriesMapper.INSTANCE.entityToDto(webSeries);
dtoList.add(dto);
}
return dtoList;
}
}
- In the above, we have called methods to map DTO to Entity and Entity to DTO.
11. Create a Controller
Create a controller class WebSeriesController. This is annotated with @RestController to make this class a RestController.
WebSeriesController.java
package com.springjava.controller;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.springjava.dto.WebSeriesDTO;
import com.springjava.service.WebSeriesService;
@RestController
@RequestMapping("/api/webseries")
public class WebSeriesController {
@Autowired
private WebSeriesService webSeriesService;
@PostMapping("/save-all")
public ResponseEntity<?> save(@RequestBody List<WebSeriesDTO> dtoList) {
Map<String, Object> respWeb = new LinkedHashMap<String, Object>();
webSeriesService.saveAll(dtoList);
respOrder.put("status", 1);
respOrder.put("message", "Record is Saved Successfully!");
return new ResponseEntity<>(respWeb , HttpStatus.CREATED);
}
@GetMapping("/list")
public ResponseEntity<?> getAll() {
Map<String, Object> respWeb = new LinkedHashMap<String, Object>();
List<WebSeriesDTO> dtoList = webSeriesService.getAll();
if (!dtoList.isEmpty()) {
respOrder.put("status", 1);
respOrder.put("data", dtoList);
return new ResponseEntity<>(respWeb , HttpStatus.OK);
} else {
respOrder.clear();
respOrder.put("status", 0);
respOrder.put("message", "Data is not found");
return new ResponseEntity<>(respWeb , HttpStatus.NOT_FOUND);
}
}
}
12. Run the Spring Boot Application
Right-click this Spring Boot application on the DemoApplication.java, then click Run As and select Java Application.
H2 Database Console
To check the H2 database console use the URL http://localhost:[server_port]/h2-console.
JSON Array
We are creating a sample JSON Array to test the API http://localhost:8080/api/order/save-all.
[
{
"name": "Demo",
"releaseDate": "04-11-2024",
"status":"yes"
},
{
"name": "Abc",
"releaseDate": "04-11-2024",
"status":"no"
}
]
Test the APIs on the Postman Tool
POST: http://localhost:8080/api/webseries/save-all
GET: http://localhost:8080/api/webseries/list
Conclusion
In this topic, we learned how to use qualifiedByName in MapStruct using the Spring Boot application.