Convert Entity To DTO In Spring REST API

Learn How to convert an Entity to a DTO and Convert DTO to an Entity in a Java Spring REST API, using a manual way and by using Model Mapper.

Overview

This article covers Converting an Entity to a DTO and Converting a DTO to an Entity manually or using the Model Mapper library. If you are looking for mapping Lists of different types using Model Mapper, read Mapping Lists of different element types using Model Mapper.

Entity Beans Vs Data Transfer Objects (DTOs)

Entities represent an application’s persistence model and are always internal to the application. On the other hand, DTOs (Data Transfer Objects) represent the models that an application exposes to the outside world.

We can have plain java beans representing various entities with an entity-based Object Relational Mapping framework (ORM). Thus, the entities and the DTOs may look similar.

However, we should not expose the internal persistence models of an application to the outside world. This means the controllers should always interact with the Data Transfer Objects (DTOs), while the repositories or the Data Access Objects (DAOs) should interact with the entities. One of the benefits of keeping the DTOs and Entities separate is that they can change independently.

Also, having a dedicated service layer keeps the Controllers and DAOs detached. However, if your controllers directly interact with repositories or DAOs, then either can take care of the Entity to DTO conversions.

Prepare an Entity Bean

Before we begin, let’s quickly create an Entity Bean for our application.
Entity Class

@Entity
@Data
public class Student {
  private String studentId;
  private String firstName;
  private String lastName;
  private int year;
}Code language: Java (java)

Prepare a Data Transfer Object (DTO)

The Data Transfer Object represents our REST service’s contract.
Data Transfer Object

@Data
public class StudentDto {
  private String studentId;
  private String firstName;
  private String lastName;
  private int year;
}Code language: Java (java)

Entity and DTO Conversion using a Constructor

A DTO class can have a constructor that instantiates itself using the provided Entity instance. Alternatively, an entity class can have a constructor that accepts a DTO instance as an argument.

Example of Entity and DTO mapping using a constructor.

@Data
public class StudentDto {
  private String studentId;
  private String firstName;
  private String lastName;
  private int year;

  public StudentDto(Student entity) {
    this.studentId = entity.getStudentId();
    this.firstName = entity.getFirstName();
    this.lastName = entity.getLastName();
    this.year = entity.getYear();
  }
}Code language: Java (java)

Having the constructor-based approach, we can convert an Entity to DTO like this.

Student student = repository.findAllById("123L");
StudentDto studentDto = new StudentDto(student);Code language: Java (java)

Entity and DTO Conversion using a Method

Also, an entity or a DTO can transform into the other types by providing a conversion method.

Example of Entity and DTO mapping using a dedicated method.

@Data
public class StudentDto {
  private String studentId;
  private String firstName;
  private String lastName;
  private int year;

  public Student toEntity() {
    Student entity = new Student();

    entity.setStudentId(this.studentId);
    entity.setFirstName(this.firstName);
    entity.setLastName(this.lastName);
    entity.setYear(this.year);
        
    return entity;
  }
}Code language: Java (java)

The conversion method can convert a DTO instance into an entity.

repository.save(studentDto.toEntity());Code language: Java (java)

Entity and DTO Conversion using a Dedicated Converter

The previous examples of using a constructor or a method for doing the Entity to DTO conversion are simple. However, the class defining such a constructor or method depends on the other and will change if the other class changes.

To keep both Entity and DTO classes independent and detached, we can create a dedicated converter class that handles the mapping between the Entity and the DTO fields.

Example of Entity and DTO Conversion using a Dedicated Mapper Class.

public class StudentMapper {

  public StudentDto toDto(Student entity) {
    StudentDto dto = new StudentDto();
    dto.setStudentId(entity.getStudentId());
    dto.setFirstName(entity.getFirstName());
    dto.setLastName(entity.getLastName());
    dto.setYear(entity.getYear());

    return dto;
  }

  public Student toEntity(StudentDto dto) {
    Student entity = new Student();
    entity.setStudentId(dto.getStudentId());
    entity.setFirstName(dto.getFirstName());
    entity.setLastName(dto.getLastName());
    entity.setYear(dto.getYear());

    return entity;
  }
}Code language: Java (java)

Let’s test this class. Next, test cases use the TestNG framework.

@Test
public void testToEntity() {
  StudentDto dto = new StudentDto("123", "Jon", "Snow", 2450);

  StudentMapper mapper = new StudentMapper();
  Student entity = mapper.toEntity(dto);

  assertEquals(entity.getStudentId(), dto.getStudentId());
  assertEquals(entity.getFirstName(), dto.getFirstName());
  assertEquals(entity.getLastName(), dto.getLastName());
  assertEquals(entity.getYear(), dto.getYear());
}

@Test
public void testToDto() {
  Student entity = new Student("123", "Jon", "Snow", 2450);

  StudentMapper mapper = new StudentMapper();
  StudentDto dto = mapper.toDto(entity);

  assertEquals(dto.getStudentId(), entity.getStudentId());
  assertEquals(dto.getFirstName(), entity.getFirstName());
  assertEquals(dto.getLastName(), entity.getLastName());
  assertEquals(dto.getYear(), entity.getYear());
}Code language: Java (java)

Entity and DTO Conversion using Model Mapper

The manual ways of conversions are suitable for small classes. However, the manual way is time-consuming and error-prone when we have large beans or many DTO and Entity pairs. To avoid that, we can use the ModelMapper library, which uses reflections to convert between classes having the same fields. Let’s create a ModelMapper implementation for an Entity to DTO Conversion.

First, we need to add the model mapper dependency.

<dependency>
  <groupId>org.modelmapper</groupId>
  <artifactId>modelmapper</artifactId>
  <version>{version}</version>
</dependency>Code language: HTML, XML (xml)

Next, we can create a @Bean factory method to create a ModelMapper instance. This way, the model mapper instance will be available for injection on the application level.

@Bean
public ModelMapper modelMapper(){
  return new ModelMapper();
}Code language: Java (java)

To do the Entity and DTO conversion, we can use its map() method that takes the source instance and the target type.

Example of using ModelMapper to convert an Entity to DTO.

StudentDto dto = modelMapper.map(entity, StudentDto.class);Code language: Java (java)

Similarly, we can use ModelMapper to convert a DTO to Entity.

Student entity = modelMapper.map(dto, Student.class);Code language: Java (java)

Let’s run Unit tests to verify if the conversions are correct.

public class StudentModelMapperTest {
  private ModelMapper modelMapper = new ModelMapper();

  @Test
  public void testModelMapperToEntity() {
    StudentDto dto = new StudentDto("123", "Jon", "Snow", 2450);

    Student entity = modelMapper.map(dto, Student.class);

    assertEquals(entity.getStudentId(), dto.getStudentId());
    assertEquals(entity.getFirstName(), dto.getFirstName());
    assertEquals(entity.getLastName(), dto.getLastName());
    assertEquals(entity.getYear(), dto.getYear());
  }

  @Test
  public void testModelMapperToDto() {
    Student entity = new Student("123", "Jon", "Snow", 2450);

    StudentDto dto = modelMapper.map(entity, StudentDto.class);

    assertEquals(dto.getStudentId(), entity.getStudentId());
    assertEquals(dto.getFirstName(), entity.getFirstName());
    assertEquals(dto.getLastName(), entity.getLastName());
    assertEquals(dto.getYear(), entity.getYear());
  }
}Code language: Java (java)

Summary

This tutorial explained several ways of Converting Entities to DTOs and Converting DTOs to Entities. We learned that an Entity bean or DTO could have a constructor or a dedicated conversion method to do the Entity and DTO conversion. Also, we can have a standalone mapper class that performs the mapping but keep the Entity and DTO detached.

In the last section, we learned that ModelMapper, an open-source library, provides an abstraction to map two entities with the same fields.

For more on Spring and Spring Boot, please visit Spring Tutorials.