What are data transfer objects? Learn to use DTOs in your Java Spring -based projects

by SkillAiNest

High performance and privacy is at the center of the most successful software system. No one wants to use a software service that takes ridiculous time to load – and no company wants their users’ data to be in minor risk. This is why DTOs are an important topic for understanding software engineers.

Using DTOS is helpful when building applications that hold sensitive data such as financial or health records. When used properly, DTOS can prevent sensitive fields from being exposed by the client. In critical systems, they can further tighten security and reduce failure conditions, ensuring that only the right and desired sectors are accepted.

In this article, you will learn what the DTOs are, why they are important, and the best ways to make them make them make them from spring -based applications.

Provisions

It is slightly more modern tutorial. So you should better understand this, you should have the right knowledge of Java’s concepts such as items, gaators and seatters, and spring/spring boots. You should also have solid understanding about how the software usually works.

The table of content

What is DTO?

DTOs stand for data transfer items. It is a software design sample that ensures the transfer of a smooth data object made between different layers of the software system.

Showing DTO's Life Cycle in the software system

Picture Source | Fabio Ribero

Data transfer with DTOs in different layers of software is two -dimensional. DTOs are either used to carry data in an inside direction from an external client/user to software or to carry data in the outbound direction from software.

The DTOS contains only field data, constructors, and essential gaters and setters methods. So they are simple old javas items.

You can see the two -dimensional flow in the bottom syllable:

In a software system sheds the DTO's two -dimensional flow in the image, the controller to the database and the database back in the controller

Picture Source | Fabio Ribero

Why use DTOs?

1. Data Privacy

In the spring boot, companies act as a blueprint to make the data object. These institutions are interpreted with classes @Entity And map the database table. An example of the entity class represents a database row or record, while the entity represents a field database column in the class.

When enrolling for a software service or product, the user may be asked to provide both the sensitive sensitive and insensitive data for the appropriate work of the application. These figures are kept as fields through the entity class and eventually maps and remains up to the database.

When we need to expose the data from the database and expose through an API closing point based on the inquiry provided-an inquiry to retrieve the user’s record or entity, Jackson (serializer dependent (Spring-based applications are commonly used by the user). I do not want to show that the user’s entity is being serialized when the user’s entity is being serialized.

Through the DTOS, you can recover a complete entity (containing sensitive and non -serious data) from the database, creating a custom class (says UserDTO.java) In which only holds insensitive fields that make you feel safe to expose, and eventually, map the database -recovered entity map on a safe -to -use object. In this way, the user DTO is the one that is serialized and exposed through the closing point of the API and not the full entity – keeping sensitive data confidential.

2. Software performance was improved

DTOS can improve your software application performance by reducing the number of API calls for data recovery. Through the DTOS, you can only return serialized data from multiple entity in an API call.

Let’s say that in your Spring Boat application, there are user and follower companies, and you want to return the user’s data as well as their followers. Generally, Jackson can only serialize an entity at a time, either the user or the follower. But through a DTO, you can connect these two entities into one and eventually served and returned all data in the same application, instead of building two closing locations to return the user and follower data.

In the next section, I will show you different ways to create a DTOS for your Spring Boat Project with the implementation of the code.

How to make DTO for Spring -based application

There are two main points for making DTOs in Spring/Spring Boat:

1. Making custom items and manually handling map

For this approach you need to handle your current entity maping/change in the Customs Object (DTO) – that is, to say, you write the code that creates the DTO and sets the DTO fields to the current entity. This is common for developers who prefer fine grain control, but it can be painful for large -scale projects.

Follow the steps below to create the user from the user’s entity:

Step 1: Create a DTO class

Create a new file that has a name USERDTO.JAVA And write down the code below:

public class UserDTO {
    private Long id;
    private String firstName;
    private String lastName;
    private String email;


    
    public UserDTO() {}

    
    public UserDTO(Long id, String firstName, String lastName, String email) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
    }


    
    public Long getId() {
        return id;
    }


    public void setId(Long id) {
        this.id = id;
    }


    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }


    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

}

Explanated User Class can only hold four (4) fields: idFor, for, for,. firstNameFor, for, for,. lastNameAnd email. It is not able to expose or receive more than this field of fields. The class also includes gutter and seat ways to recover and assign data to fields.

Step 2: Create mapper methods within utility class

Create a new file that has a name Usermapper.java And put this piece of this code into it:

public class UserMapper {

    

    public static UserDTO toDTO(UserEntity user) {

        if (user == null) return null;

        UserDTO dto = new UserDTO();
        dto.setId(user.getId());
        dto.setFirstName(user.getFirstName());
        dto.setLastName(user.getLastName());
        dto.setEmail(user.getEmail());
        return dto;
    }


    

    public static UserEntity toEntity(UserDTO dto) {

        if (dto == null) return null;
       UserEntity user = new UserEntity(); 
        user.setFirstName(dto.getFirstName());
        user.setLastName(dto.getLastName());
        user.setEmail(dto.getEmail());

        return user;
    }

User -on -Class is an utility class that makes the user a map of the DTO and DTO. This is the place where I talked about the transfer of two -dimensional data. First of all, retrieving the full record from the database in the usual-DTO direction and serializing it by the client through an API closing point and turning it into a smooth item (invalid with unnecessary information) before bringing them to front.

In the direction of the DTO consumer, the client involves taking the object as input into the system, but this time, limiting the client in terms of the number of data fields in which they can transfer the system. This object was received, mapped with an entity, and is preserved in the system. This is important when you do not want the client to have access to some important fields (which will weaken your request). That is why software engineers always say, “Don’t trust the user”.

I see you to peek that looks like our consumer:

import jakarta.persistence.*;

import java.time.LocalDate;


@Entity

@Table(name = "users")

public class UserEntity {


    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)

    private Long id;
    private String firstName;
    private String lastName;

    @Column(unique = true)
    private String email;
    private String password;
    private String phoneNumber;
    private String gender;
    private LocalDate dateOfBirth;
    private String address;
    private String city;
    private String state;
    private String country;
    private String profilePictureUrl;
    private boolean isVerified;
    private LocalDate createdAt;
    private LocalDate updatedAt;

    
    public UserEntity() {}

    
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public LocalDate getDateOfBirth() {
        return dateOfBirth;
    }

    public void setDateOfBirth(LocalDate dateOfBirth) {
        this.dateOfBirth = dateOfBirth;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getCountry() {
       return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public String getProfilePictureUrl() {
        return profilePictureUrl;
    }

    public void setProfilePictureUrl(String profilePictureUrl) {
        this.profilePictureUrl = profilePictureUrl;
    }

    public boolean isVerified() {
        return isVerified;
    }

    public void setVerified(boolean verified) {
        isVerified = verified;
    }

    public LocalDate getCreatedAt() {
        return createdAt;
    }

    public void setCreatedAt(LocalDate createdAt) {
        this.createdAt = createdAt;
    }

    public LocalDate getUpdatedAt() {
        return updatedAt;
    }

    public void setUpdatedAt(LocalDate updatedAt) {
        this.updatedAt = updatedAt;
    }

}

In pieces of the code mentioned, you can see that the users have only four (4) fields, which are insensitive and safe to expose serialization. These fields are ID, first name, last name, and email – unlike consumerism, which contains both sensitive and insensitive fields. Therefore, the maps of the non -protected user are not protected from the map of the consumer. With this, the user DTO Object can be serialized and returned through an closing point. Now you can see why DTOs help us prevent us from exposing confidential information.

2. Creating customs and handling mapping through an external library

The use of an outer library means adding a layer of abstraction to the mapping process. The library handles the job pressure parts for you, and it is often the preferred choice for large -scale projects. In this article, we are using Map Stranger Because it is popular and easy to use. Maun will be our blood toll.

Step 1: Add dependent to your project

Since you are using Maon as your Blood Tool, open your POM.XML file and add this code:

<dependencies>
    
    <dependency>
        <groupId>org.mapstructgroupId>
        <artifactId>mapstructartifactId>
        <version>1.5.5.Finalversion>
    dependency>
dependencies>
<build>
    <plugins>
        
        <plugin>
            <groupId>org.apache.maven.pluginsgroupId>
            <artifactId>maven-compiler-pluginartifactId>
            <version>3.10.1version>
            <configuration>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstructgroupId>
                        <artifactId>mapstruct-processorartifactId>
                        <version>1.5.5.Finalversion>
                    path>
                annotationProcessorPaths>
            configuration>
        plugin>
    plugins>
build>

This will help download dependence on the project.

Step 2: Explain your DTO

Use UserDTO.java File given in Step 1 of the first approach.

Step 3: Create Maps Strakt Maiper Interface

Create a file and its name usermapper.java, and add the code below to:

import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

@Mapper(componentModel = "spring")
public interface UserMapper {
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
    UserDTO toDTO(UserEntity user);
    UserEntity toEntity(UserDTO userDTO);
}

The user interface contains the example field and two methods, namely toodo and tentity, which takes the type of consumer and user items respectively as arguments. The implementation of these methods is summarized and handled by the library for us.

Now you can use mapper methods (todo and tentity) in your service or controller.

How to make DTOS from two or more items

This is one of the most important methods of using DTOs: making more than one entity to create DTOS and connect them as one, so that they can be returned to an API call or application.

There are many ways you can implement this technique and create complex reaction DTO based on your project requirements. The form or structure of your API Response Object may not be equal to the example given in this tutorial – but the same principle applies, which only produces individual DTOS and is connecting them to a DTO, which eventually acts as a DTO.

The example below is not extremely complicated, but it is enough to help you understand how it works so you can take advantage of technique to create more complex API response items. This example will combine the doctor’s DTOs and his appointments.

Step 1: Create a DTO class

Create a file that has a name DOCTORDTO.JAVA And add this code to it:


public class DoctorProfileDTO {
    private String doctorId;
    private String fullName;
    private String email;
    private String specialization;

   
   public DoctorProfileDTO(){
    }

    
    public String getDoctorId() {
        return doctorId;
    }

    public void setDoctorId(String doctorId) {
        this.doctorId = doctorId;
    }

    
    public String getFullName() {
        return fullName;
    }

    public void setFullName(String fullName) {
        this.fullName = fullName;
    }

    
    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    
    public String getSpecialization() {
        return specialization;
    }

    public void setSpecialization(String specialization) {
        this.specialization = specialization;
    }
}

Make another one that says Appointment dto.java And add this code:

public class AppointmentDTO {
    private String appointmentId;
    private String appointmentDate;
    private String status;
    private String patientName;
    private String patientEmail;

   
   public AppointmentDTO(){
    }

    
    public String getAppointmentId() {
        return appointmentId;
    }

    public void setAppointmentId(String appointmentId) {
        this.appointmentId = appointmentId;
    }

    
    public String getAppointmentDate() {
        return appointmentDate;
    }

    public void setAppointmentDate(String appointmentDate) {
        this.appointmentDate = appointmentDate;
    }

    
    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    
    public String getPatientName() {
        return patientName;
    }

    public void setPatientName(String patientName) {
        this.patientName = patientName;
    }

    
    public String getPatientEmail() {
        return patientEmail;
    }

    public void setPatientEmail(String patientEmail) {
        this.patientEmail = patientEmail;
    }
}

Step 2: Create a comprehensive DTO by combining both entities

Create a file that has a name Dr. Vietnth Dippentammintoto.Ajawa:

import java.util.List;

public class DoctorWithAppointmentsDTO {
    private DoctorProfileDTO doctorProfile;
    private List appointments;

    
    public DoctorWithAppointmentsDTO() {
    }

    
    public DoctorProfileDTO getDoctorProfile() {
        return doctorProfile;
    }

    public void setDoctorProfile(DoctorProfileDTO doctorProfile) {
        this.doctorProfile = doctorProfile;
    }

    
    public List getAppointments() {
        return appointments;
    }

    public void setAppointments(List appointments) {
        this.appointments = appointments;
    }
}

Step 3: Create a mapper class

Create a mapper class DOCTORMAppper.java Containing logic to make a map Dr. Vietnth DippententDoato Class:

public class MapperClass {

    public DoctorWithAppointmentsDTO toDTO(Doctor doctor, List appointments) {

        DoctorProfileDTO doctorProfile = new DoctorProfileDTO();
        doctorProfile.setDoctorId(doctor.getId());
        doctorProfile.setFullName(doctor.getFullName());
        doctorProfile.setEmail(doctor.getEmail());
        doctorProfile.setSpecialization(doctor.getSpecialization());

        List appointmentDTOs = appointments.stream().map(appt -> {
            AppointmentDTO dto = new AppointmentDTO();
            dto.setAppointmentId(appt.getId());
            dto.setAppointmentDate(appt.getDate().toString()); 
            dto.setStatus(appt.getStatus().name());
            dto.setPatientName(appt.getPatient().getName());
            dto.setPatientEmail(appt.getPatient().getEmail());
            return dto;
        }).toList();

        DoctorWithAppointmentsDTO doctorWithAppointment = new DoctorWithAppointmentsDTO();
        doctorWithAppointment.setDoctorProfile(doctorProfile);
        doctorWithAppointment.setAppointments(appointmentDTOs);

        return doctorWithAppointment;
    }
}

From the aforementioned example, you can see that two separate DTOs (for appointment and Dr. Pro Fields) were formed before the Comprehensive DTO, Dr. Vietnamese Dupixems was formed. The Comprehensive DTO Classes (Dr. Vietnam Dappernatoato) contain fields that examples of appointment and examples of Dr. Profile DTOs. The Mapper Class takes the list of doctors and appointments as arguments, making them a map for Dr. Properto, respectively. Finally, the fields of the Comprehensive DTO Class are set up using the DTO Objects marked from the institutions.

Dr. Vietnth Dipperintests, When the serialized and closing point is returned, you should be outpitted like this:

{
  "doctorProfile": {
    "doctorId": "abc123",
    "fullName": "Dr. Susan Emeka",
    "email": "suzan.emeka@example.com",
    "specialisation": "Cardiology"
  },
  "appointments": (
    {
      "appointmentId": "appt001",
      "appointmentDate": "2025-07-10T09:00:00",
      "status": "CONFIRMED",
      "patientName": "James Agaji",
      "patientEmail": "james.agaji@example.com"
    },
 {
      "appointmentId": "appt002",
      "appointmentDate": "2025-08-12T07:05:08",
      "status": "CONFIRMED",
      "patientName": "Jane Augustine",
      "patientEmail": "jane.augustine@example.com"
    }
  )
}

Conclusion

If you are a software engineer that is related to privacy and performance, it is important to use DTOs in your applications.

In this article, you have learned what the DTOs are, as well as important perspectives for making and using them. Take the time to go through pieces of code given in this article and practice with them until you implement them yourself. Thanks for reading.

You may also like

Leave a Comment

At Skillainest, we believe the future belongs to those who embrace AI, upgrade their skills, and stay ahead of the curve.

Get latest news

Subscribe my Newsletter for new blog posts, tips & new photos. Let's stay updated!

@2025 Skillainest.Designed and Developed by Pro