DEV Community

Cover image for Replace a JPA entity with a DTO
Maddy
Maddy

Posted on • Originally published at techwithmaddy.com

Replace a JPA entity with a DTO

Have you ever come across a Sonar vulnerability issue such as:

Replace this persistence entity with a POJO or DTO object.

This happens when you pass a persistence entity into the @ResponseBody of a REST call, as opposed to a DTO object.

This article will show you how you can replace a persistence entity with a DTO object.

I wrote an article time ago on How To Create A Spring Boot Rest API.

You can clone the Github repository using this link.

We'll use this application as a reference.

Let's start.

#1. ADD MODEL MAPPER

The Model Mapper is an object mapping library. It makes it easy to convert one object model into another object model.

In the pom.xml, add the Model Mapper dependency:

 <dependency>
    <groupId>org.modelmapper</groupId>
    <artifactId>modelmapper</artifactId>
    <version>2.4.5</version>
</dependency>
Enter fullscreen mode Exit fullscreen mode

P.S.: if you ever get any problems after adding the above dependency, running the command mvn clean install usually helps.

#2. CREATE A DATA TRANSFER OBJECT

Martin Fowler introduced the Data Transfer Object pattern in his book "Patterns of Enterprise Application Architecture".

A Data Transfer Object is an object which carries data between processes.

This object doesn't contain any business logic.

In the src/main/java/com/techwithmaddy/CustomerAPI directory:

  1. Create a new package called dto (all lowercase).
  2. Create a class called CustomerDTO in the dto package.

This class has the following content:

package com.techwithmaddy.CustomerAPI.dto;

import lombok.Data;

@Data
public class CustomerDTO {

    private String firstName;
    private String lastName;
    private String email;
    private String phoneNumber;

}
Enter fullscreen mode Exit fullscreen mode

#2. CREATE A CUSTOMER CONVERTER CLASS

This converter class is responsible for converting an entity into DTO, and vice versa.

In the src/main/java/com/techwithmaddy/CustomerAPI directory:

  1. Create another package called converter (all lowercase).
  2. Create a class called CustomerConverter in the converter package.

This class has the following content:

package com.techwithmaddy.CustomerAPI.converter;

import com.techwithmaddy.CustomerAPI.dto.CustomerDTO;
import com.techwithmaddy.CustomerAPI.model.Customer;
import org.modelmapper.ModelMapper;
import org.springframework.stereotype.Component;

@Component
public class CustomerConverter {

    public CustomerDTO convertEntityToDto(Customer customer) {
        ModelMapper modelMapper = new ModelMapper();
        CustomerDTO customerDTO = modelMapper.map(customer, CustomerDTO.class);
        return customerDTO;
    }

    public Customer convertDtoToEntity(CustomerDTO customerDTO) {
        ModelMapper modelMapper = new ModelMapper();
        Customer customer = modelMapper.map(customerDTO, Customer.class);
        return customer;
    }
}
Enter fullscreen mode Exit fullscreen mode

#3. REFACTOR CUSTOMER SERVICE CLASS

We want to use the CustomerDTO, instead of the Customer entity database object.

We can refactor this class by importing the ModelMapper and the CustomerConverter, and auto wiring them.

    @Autowired
    ModelMapper modelMapper;

    @Autowired
    CustomerConverter customerConverter;
Enter fullscreen mode Exit fullscreen mode

The saveCustomer() method will now be like this:

    public CustomerDTO saveCustomer(CustomerDTO customerDTO) {
        Customer customer = customerConverter.convertDtoToEntity(customerDTO);
        customer = customerRepository.save(customer);
        return customerConverter.convertEntityToDto(customer);
    }
Enter fullscreen mode Exit fullscreen mode

#4. REFACTOR THE CUSTOMER CONTROLLER CLASS

Add this property to the Rest Controller:

    @Autowired
    private CustomerConverter customerConverter;
Enter fullscreen mode Exit fullscreen mode

And refactor this saveCustomer method to use the CustomerDTO, instead of the Entity class:

    @RequestMapping(method = {POST}, path = "/save", produces = MediaType.APPLICATION_JSON_VALUE)
    public CustomerDTO saveCustomer(@Valid @RequestBody CustomerDTO customerDTO){
        return customerService.saveCustomer(customerDTO);
    }
Enter fullscreen mode Exit fullscreen mode

#5. RUN THE APPLICATION

For the sake of this tutorial, we want to check if the above changes work.

Therefore, temporarily comment out:

  1. The GET, PUT, and PATCH requests in the Rest Controller.
  2. The entire CustomerServiceTest class.

Now you can run the application.

  • On Postman, create the following POST request and hit the SEND button:

maddy-save-post-request

  • On MySQL, you should see the new customer added to the table.

maddy-mysql-dto-saved

#6. WHY USE A DTO INSTEAD OF AN ENTITY?

Let's imagine the following scenario:

> A school wants to save data about its students. There is a database which stores student names, surnames, email, and other sensitive information. Teachers only have access to some of the data stored in the database (such as name, surname, and email). The rest of the information won't be accessible and visible to teachers. Teachers can only see the data they need.

Data Transfer Objects work this way: they store some of the data present in the database, with no business logic.

In the Spring Boot architecture, the client communicates with the controller layer.

If we didn't have Data Transfer Objects, we would have to use an Entity class in the controller class, creating a vulnerability risk in our application.

CONCLUSION

This article has shown you how to convert an entity into a DTO, and how you can use a DTO in the ResponseBody of a REST call.

I hope you've found this article helpful.

Do you know of any other approach? Please let me know in the comments.

Until next time! 🙋🏾‍♀️

ADDITIONAL RESOURCES

Discussion (2)

Collapse
pratikaambani profile image
Pratik Ambani • Edited on

Nice one, do you have any idea whether ModelMapper uses Reflections for conversion from Entity to PoJo?

If, we've already got BeanUtils.CopyProperties to parse from typeA to typeB

Collapse
maddy profile image
Maddy Author • Edited on

Hi there!

I had to Google your question and the answer seems to be "yes", it uses Reflections.

Here's the link:

groups.google.com/g/modelmapper/c/...

I hope this helps!