DTO or not to DTO?

Giorgi Tsiklauri
Javarevisited

--

Disclaimer: This article does not take existence of the Java records into consideration, and it merely speaks about DTOs, in their classical understanding.

Shall I use DTOs or not?

This is a long-time popular, to some extent debatable, and sometimes, even inclining to so-called “holly war” question, very short answer to which, is

— It depends.

— What is DTO, anyways?

— It is a Data Transfer Object, i.e. the data aggregate object, sole purpose of which is to facilitate conveying data from the point A (the source) to the point B (destination).

There are plenty of people, who, in plenty of cases, would prefer one approach (using DTOs) over another (using bare model classes / entities), and vice versa; however, there is no the single source of truth on which is better to use.

It very much depends on the requirements, software design, architectural approach you decide to stick with, other (project-related) specific details, and even on personal preference.

Some even claim that the DTO is an anti-pattern; some love using them; some think, that data refinement/adjustment should happen on the consumer/client side (for various reasons, out of which, one can be No Policy for API changes).

That being said, YES, you can simply return the model class (in Hibernate, it’s @Entity) instance (or list of instances) right from your controller and there is no problem with this approach. I would even say, that this does not even violate anything from SOLID or Clean Code principles.

But again..

it depends on what do you use response for; what representation of data do you need; what should be the capacity and purpose of the object in question, and etc..

DTO is generally a good practice in the following scenarios:

  1. When you want to aggregate the data for your object from different [re]sources, i.e. you want to put some object transformation logic between the Persistence Layer and the Business(or Web) Layer:
    Imagine you’re using ORM and you have a Java code abstraction for your database. Now imagine, you fetch from your database an Employee instance; however, from another 3rd party web service (or just any other source), you also receive some complementary-to-employee data for that employee object. Say, it’s — EmployeeContact.
    Now, you want to send some data from the employee object (let’s say it’s ID, Firstname, Lastname fields) and some data from the employeeConcat object (let’s say it’s City, District, Address and PostalCode fields) to the client, which expects the data, modeling employee and its address, but you do not wish to send these two instances separately (you, especially, will not want to send all the instances separately, if they are more than two).
    Instead of sending two instances and delegating assembling responsibility to the client, what you might find as a better and convenient alternative, is to use DTO.
    Using DTO would look like creating the corresponding DTO class (let’s say — EmployeeAddressDTO), that aggregates two (or more) model classes and per each instance of such a class, you will have a model aggregating desired data, which, in the above case , is data from the employee and employeeContact objects. By the way, during this aggregation, you might also want to do some other things, like data alteration, adjustment, modification, calculation, or etc.
    The point is that you want to combine the data from different [re]sources and represent that combination as a one, unified object.
    This makes a good case to use DTO pattern. DTO is reusable, it conforms to Single-Responsibility Principle, and it is well segregated from other layers. Note, that since ;
  2. When you don’t necessarily combine data received from different sources, but you want to modify and customize the model instance, which you will be returning:
    Imagine you have a very big Entity (with a lot of fields), and the client, which calls the corresponding endpoint (Front-End application, Mobile, or any client), has no need of receiving this huge entity (or list of entities). If you, despite the client’s requirement, will still be sending the original/unchanged entity, you will end up consuming network bandwidth/load inefficiently (more than enough), performance will be weaker, and generally, you will be just wasting computing resources for no good reason. In this case, you might want to transform your original Entity to the DTO object, which the client needs (only with required fields). Here, you might even want to implement different DTO classes, for one entity, for different consumers/clients, as you might want to customise data representation per each client.

Note, that you may have a situation, when your requirements involve both 1st (aggregation) and 2nd (modification/customisation) points mentioned above.

However, if you are sure, that your table/relation representations (instances of @Entity classes) are exactly what the client needs, there is no necessity of introducing DTOs.

Supporting further the idea, that @Entity can be returned to the presentation layer without DTO

  1. Java Persistence with Hibernate, Second Edition, in §3.3.2, even motivates it explicitly, that:

You can reuse persistent classes outside the context of persistence, in unit tests or in the presentation layer, for example. You can create instances in any runtime environment with the regular Java new operator, preserving testability and reusability;

2. Hibernate entities do not need to be explicitly Serializable.

Other Hibernate and JPA articles you may like

--

--

Giorgi Tsiklauri
Javarevisited

Software engineer, architect, lecturer; long while w/ computers and music; interested in software design, computer networks, composition, security and privacy.