How to map Entity to DTO using ModelMapper?

By | February 27, 2023

The ModelMapper is a library that is used for converting/mapping two similar object models to each other in a simple and easy way. It is used when the two models have similar data, but their structures and use cases are different. ModelMapper allows us to convert one model to another without affecting the original object models.

Why we need ModelMapper?

In enterprise software applications generally, we have applications with three different layers Web Layer, Business Layer, and Database Layer. The object models in these layers may be different from each other. For example, objects in the database layer may have some fields that are not required by the web layer, such as auto-generated fields, encrypted password fields, etc.

In order to setup communication in these layers, we need to transfer objects from one layer to another, and to transfer objects from one layer to another, we need to convert or map one object to another, which can be easily achieved by the ModelMapper library.

In our previous article, How to create a REST API | User API, we developed our User API, in which we have written methods to convert dtoToEntity() and EntityToDto(), which are used to convert a DTO Object to an Entity and vice versa, respectively. In this article, we will use the ModelMapper library to map DTO objects to entities and vice versa.

Step By Step Implementation

Step 1- Add Dependendencies

In this step, we need to add model mapper dependencies. For this, we will be using the Central Maven Repository. We will add the following dependency.

XML
<dependencies>
	<dependency>
		<groupId>org.modelmapper</groupId>
		<artifactId>modelmapper</artifactId>
		<version>3.1.1</version>
	</dependency>
</dependencies>

Step 2- ModelMapper Bean Declaration

In this step, we need to declare the bean of the model mapper in the configuration class. i.e., the main class of a Spring Boot application (here, the BlogApplicationServicesApplication class).

Java
package com.paulsofts.blogapplicationservices;

import org.modelmapper.ModelMapper;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class BlogApplicationServicesApplication {

	public static void main(String[] args) {
		SpringApplication.run(BlogApplicationServicesApplication.class, args);
	}
	
	//Bean declaration for ModelMapper library
	@Bean
	public ModelMapper getModelMapper() {
		return new ModelMapper();
	}

}

Step 3- Use ModelMapper in Business Layer

In this step, we will use a model mapper to change our Entity to DTO. .i.e, User to UserDto and vice versa. First, we need to autowire the ModelMapper instance in our UserServiceImpl class and then use it to call the map (Object source, class destinationType) for mapping DTOs to entities and vice versa. The map(Object soruce, class destinationType) takes two arguments the source object which we want to convert/map to the class in which we want to map. Also, we will comment out our previous implementation.

Java
package com.paulsofts.blogapplicationservices.service;

import java.util.List;
import java.util.stream.Collectors;

import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.paulsofts.blogapplicationservices.dto.UserDto;
import com.paulsofts.blogapplicationservices.model.User;
import com.paulsofts.blogapplicationservices.repository.UserRepository;
import com.paulsofts.blogapplicationservices.utils.ResourceNotFoundException;

@Service
public class UserServiceImpl implements UserService {

	@Autowired
	private UserRepository userRepository;
	
	//autowire model mapper instance
	@Autowired
	private ModelMapper modelMapper;
	
	@Override
	public UserDto createUser(UserDto userDto) {
		//the data returned from data base is of User object,
		//we need to convert it into UserDto object as our method's return type is UserDto 
		
		//User user = this.dtoToUser(userDto);
		
		//we will be using map(Object source, class<T> destinationType) method to map UserDto to User
		User user = this.modelMapper.map(userDto, User.class);
		User userSavedToDB = this.userRepository.save(user);
		
		//return this.userToDto(userSavedToDB);
		
		return this.modelMapper.map(userSavedToDB, UserDto.class);
	}

	@Override
	public UserDto updateUser(UserDto userDto, int userId) {
		//here, we will be using findById() method and if user is not present then
		//we will be throwing our custom exception ResourceNotFoundException
		
		//findById() method uses java 8 feature .i.e., Optional Class
		
		User user = this.userRepository.findById(userId).orElseThrow(
				() -> new ResourceNotFoundException("User", "userId", userId));
		
		//if User is present we will update it
		
		user.setUserName(userDto.getUserName());
		user.setUserEmail(userDto.getUserEmail());
		user.setUserAbout(userDto.getUserAbout());
		User updatedUser = this.userRepository.save(user);
		
		//return this.userToDto(updatedUser);
		
		return this.modelMapper.map(updatedUser, UserDto.class);
	}

	@Override
	public UserDto getUserById(int userId) {
		User user = this.userRepository.findById(userId).orElseThrow(
				() -> new ResourceNotFoundException("User", "userId", userId));
		
		//return this.userToDto(user);
		
		return this.modelMapper.map(user, UserDto.class);
	}

	@Override
	public List<UserDto> getAllUser() {
		//the userList will contains all the list of users
		List<User> userList = this.userRepository.findAll();
		//we need to convert the userList to userDtoList
		
		//map() method is java 8 feature which is used to map(transform)
		//one object into another depending on the conditions passed to it
		
		//List<UserDto> userDtoList = userList.stream().map(user -> this.userToDto(user)).collect(Collectors.toList());
		
		List<UserDto> userDtoList = userList.stream().map(
				user -> this.modelMapper.map(user, UserDto.class)).collect(Collectors.toList());
		return userDtoList;
	}

	@Override
	public void deleteUser(int userId) {
		User user = this.userRepository.findById(userId).orElseThrow(
				() -> new ResourceNotFoundException("User", "userId", userId));
		this.userRepository.delete(user);
	}
	
	//this method will convert UserDto to User object .i.e., entity to DTO object
	/*
	 * public User dtoToUser(UserDto userDto) { User user = new User();
	 * user.setUserId(userDto.getUserId()); user.setUserName(userDto.getUserName());
	 * user.setUserEmail(userDto.getUserEmail());
	 * user.setUserPassword(userDto.getUserPassword());
	 * user.setUserAbout(userDto.getUserAbout()); return user; }
	 */
	
	//this method will convert User to UserDto object .i.e., DTO to entity object
	/*
	 * public UserDto userToDto(User user) { UserDto userDto = new UserDto();
	 * userDto.setUserId(user.getUserId()); userDto.setUserName(user.getUserName());
	 * userDto.setUserEmail(user.getUserEmail());
	 * userDto.setUserPassword(user.getUserPassword());
	 * userDto.setUserAbout(user.getUserAbout()); return userDto; }
	 */
}

In this way, using model mapper we can reduce the code base size which will be further improve the application performance.

Leave a Reply

Your email address will not be published. Required fields are marked *