Foojay Today

Alternatives to DTO

March 07, 2022

More than a decade ago, I wrote about the DTO:

"A data transfer object is an object that carries data between processes. The motivation for its use is that communication between processes is usually done resorting to remote interfaces, where each call is an expensive operation. Because the majority of the cost of each call is related to the round-trip time between the client and the server, one way of reducing the number of calls is to use an object (the DTO) that aggregates the data that would have been transferred by the several calls, but that is served by one call only." -- Wikipedia

I believed (and still do) that it should be a thing of the past. Yet, it seems its usage is still widespread.

I do not deny there are some valid reasons to transform data. However, there are alternatives to the traditional DTO process:

  1. Return a business object from the service layer. In projects I've worked on previously, we directly mapped the BO to the entity read from the database.
  2. Transform the BO to a DTO in the presentation layer.
  3. Return the DTO from the presentation layer.

Return the entity itself

When the entity's properties are a superset of the properties that need to be displayed, aggregating additional properties is not required. Transforming the entity to a DTO is not only overkill. It hinders performance.

In that case, the best approach is to return the entity itself.

JPA projection

We make requests for specific data in a particular context. Thus, when the call reaches the data access layer, the scope of the required data is fully known: it makes sense to execute a SQL query that is tailor-fitted to this scope.

For that, JPA offers projections. In essence, a projection in a query allows selecting precisely the data one wants. Here's an example; given a Person entity class and a PersonDetails regular class:

CriteriaQuery<PersonDetails> q = cb.createQuery(PersonDetails.class);
Root<Person> c = q.from(Person.class);,

Jackson converter

Regarding JSON specifically, we can delegate the process of providing the correct data to the serializer framework, e.g. Jackson. The idea behind it is the following: the main code processes the entity as usual, and at the edge, a Jackson converter converts it to the required JSON structure.

If less data is necessary, it's child's play. If more, then the converter needs additional dependencies to get data where it is. Of course, if this data comes from the same datastore, this is not great, and the alternative above is more relevant. If not, it's an option.


Last but not least, one could return the full-blown entities and let the client decide what data makes sense in its context.

GraphQL is built around this idea: Facebook created it, and it is now fully Open Source. Its main advantage is to offer a specification and a lot of language-specific implementations on top of it.



When a gap exists between the business and presentation models, it's easy to get back to age-old "patterns" such as the DTO. However, any of the alternatives above are probably more relevant.

To go further:

Originally published at A Java Geek on March 6th, 2022


Related Articles

View All
  • Create a CRUD UI in Pure Java

    Many developers struggle writing Web UI, but it gets to be a super fun job if we could do it using pure java, let’s find out how we can do it using Vaadin.

    Read More
    Feb 02, 2022
  • Get Your JDK As Easily As Possible!

    Have you ever been in the situation where you’ve been looking for a specific JDK version of a specific distribution?

    Sometimes that was easy… sometimes it was hard… but it never was fun.

    After creating the Disco API (“Universal OpenJDK Discovery API”, in full) which serves up JDK distributions as a service, I had the idea to create plugins for IDEs to enable people to download the JDK of their choice more easily.

    Read More
    Jul 20, 2021
  • BlockHound: How It Works

    BlockHound will transparently instrument the JVM classes and intercept blocking calls (e.g., IO) if they are performed from threads marked as “non-blocking operations only” (ie. threads implementing Reactor’s NonBlocking marker interface, like those started by Schedulers.parallel()).

    If and when this happens (but remember, this should never happen!), an error will be thrown.

    Read More
    Jun 22, 2021


  • Nicolas Frankel

    Nicolas is a developer advocate with 15+ years experience consulting for many different customers, in a wide range of contexts (such as telecoms, banking, insurances, large retail and public sector). ... Learn more

Comments (0)

Your email address will not be published.



Subscribe to foojay updates:
Copied to the clipboard