Stop Using DTOs – A Cleaner Way for Your Java APIs

 

Transcript:

You don't need details before I close the video. Hear me out. Maybe just maybe you or your neighbor or you colleague need them, but chances are you are doing it wrong. What I mean, probably you know how to use DTO's. Probably you test them, but do know that you actually usually can avoid using them.

What is the history of using? Actually they originate from somewhere like 2005 when the whole idea of returning entities was very scary because when you returns an entity, you have to serialize it right wrong. JsonView, JsonIgnore and other useful notations can help you avoid it. And today we'll talk about them. Hi, you are on CyberJAR I'm Pasha. I'm developer advocated BellSoft, and I'm more than 15 years in software development in JVM. And every time I hear about Detailss, it makes me think, is everything going right here? Let's discuss.

If you follow our channel, then you just saw a video by my colleague Kat. About how to use DTO with Spring Boot and in Spring Boot applications. She describes a lot of useful applications of DTO, validations and custom beans and so on, but think about the amount of machinery, additional machinery we should use. Just to use this approach, we have to create a lot of DTO classes, potentially a lot because for one entity we can have almost infinite amount of projections, and all these projections will have the same names of fields as our entity. Most probably there are exceptions. Surely. Also, we have to rely on co-generation. I personally love co generation. But do I really want to map everything with generated code, which is simple, but it's still a tone of code and it's not like I really control it, right? When I control my code generation, I'm totally fine with it, but when someone else does it, it come out of hands very quickly. Is it fine by you? Do you like it? I think that I know a better approach. Let's start from a simple example. I have a very basic entity here on your screen. It's just a user with username and password, and it's so simple to imagine a situation when there are a little bit more fields and we want to return them all, but password. And many of you probably reflectively created DTO for it, like user without password DTO, and then you'll map a user entity to user without password DTO with MapStruct or tool like that, or just manually and return it just to be on the safe side. But it is quite a boilerplate to be honest. We know that we certainly never want to return passages, right?

Maybe we can just put json ignore annotation on this field. It reduces the amount of code we have to write dramatically. It's one line of code, actually it's meta code. It's just an notation. And I would argue this code is actually more maintainable than the version of DTO's. It, we have only one entity for everything and it doesn't leak unnecessary information to our users. So we are safe and our code is shorter and easier to read. I hear your voices and that too loud. Pasha. This example is oversimplified. Okay. Okay. You are right. Let's get back for a second. Let's imagine that there is one more field in our entity. It's email and we do not want to return email to regular users of our API or front end, but we want to return email to administrators or say internal personal of our company. Surely. You know how to do it with dts, you will just create two more dts. One of them is use a DTO without email and without password and use a DTO without password with email. Two more. Okay, that's fine. No it's not. You could just use JsonView annotation. Let's see how it works. Look at this class views. It only contains two class inside of it, public and internal extends public. All the fields elevated with json View public should be available to our general audience. All the fields annotated with JsonView internal as well as all the field sanitation JSON view public should be available to our administrators or internal personnel. Now let's update our entity a little bit. We'll add JSON view public to our IT and username. They could be available to anyone. We'll update email to be JSON View internal, and we'll leave password as is json Ignore. Now let's update our controller. Because it is the place actually responsible for realization with json Ignore it's symbol. When Jackson sees a json ignore field, it'll just ignore it. But views, we have to actually update our controllers. Here is how we do it. We just add json, view annotation on methods of our controls, like fixed. What are this voices again? Pasha, I don't use JPA. Oh, you use JUG Actually, I'm on board with you. I don't like JPA either. JUG gives me much more control over my SQL and I love it. But there is an issue, right? JUG generates code. We can't just put annotations on generated code. Do we actually need them? Is devoid, do we need to use ju generated DTO? Actually, we don't. To address the hq, Jackson uses an approach very popular in say, scatter world, but almost unknown in Java world and it's mixings.

Let's look at the mixing exam. Mixin is just an interface and it only contains getters of our fields. And this getters can be annotated by Jackson notations like JsonView or JsonIgnore. For example. Here we see two ghettos annotated with JsonView public and one ghetto annotated with JSON. No. When we create such mixing, the only thing we left to do is to register this mixing in Jackson. Here's how we do it. Obviously, you are not obligated to apply Mixings only to records. If you want, you can apply them to JPA entities or any other classes you don't control. It's totally in your power. The beautiful thing here, your class shouldn't implement the interface of mixing. The mixing is just a interface known only to Jackson Register only for Jackson, which controls the serialization behavior. What is the sound again? I'm hearing. I'm hearing, I'm hearing your question. Pasha, our objects are not as simple as you show. We have complex data structures and they are in JPE entities. They depend on each other, and when I have a comment, this comment has a user. Our users do not exist in vacuum. They're bound to something real amazing news for you.

If your person has a list of comments or if your comment has a link to user. You can annotate fields in all of them with your views and the whole structure will be visible only to a degree that is allowed by JsonView annotation, like here an example. Now I know there is a couple more questions. First, validation. Beautiful. You can put validation annotations. On your entities too, and if you need to validate it, you will. And also, Hibernate Validator supports validation types of validation classes, so you are not obligated to validate all the fields. You can validate some of them, depending on your context, on your situation. The second, many of you think, or many of you will say that dts are more explicit than annotations? Well, kinda, but not. Annotations are also explicit and what's more important, they are reusable. They do not care about how many projections you have.

You will always have what you need without excessive amount of classes. And when one day you'll have to move field from one view to another, you will just do it and it won't break any API. Sure you'll have to fix your test, but this is what we have tests for, right? So, so what do we take out from this video? I hope that now you at least have another view. On the question, do I need a DTO? If you need it, please use it. Just know that there is an alternative. If you wanna know more about dts, please check out Kat's video. If you like the video, like the video. If you don't like the video, please leave a comment. Tell us what you think, and maybe I'll fix it. Who knows? And with this patches out, see you next time.

Summary

In this video, the idea of whether DTOs are always necessary in Spring Boot applications is challenged. Instead of generating multiple DTO classes and mappings, it shows how Jackson annotations such as @JsonIgnore and @JsonView, or Mixins, can manage serialization and control which fields are exposed. This reduces boilerplate, keeps entities simpler, and improves maintainability. The takeaway is that while DTOs have their place, in many cases they can be avoided with these alternatives.

Social Media

Videos
card image
Jul 15, 2025
Java Downgrade Challenge: From JDK 8 to 1.1 (Part 2)

In Part 2 of the Java Downgrade Challenge, we continue our journey — now from Java 8 all the way to Java 1.1. No streams, no lambdas, no generics, no collections — and at one point, we even boot up Windows 98. If you thought Part 1 was painful, this one unwinds Java history line by line. By the end, the familiar Java from today will be almost gone.

Videos
card image
Jun 27, 2025
5x Smaller Java Docker Images — 2025 Optimization Guide

In this video, I’ll show you how to make your Java Docker images 5 TIMES SMALLER. You’ll see the full process, from a heavy 587MB container to a lean 116MB image, ready for production.

Further watching

Videos
card image
Aug 27, 2025
Buildpacks for Spring Boot

Buildpacks for Spring Boot: no Dockerfiles, no hassle — just production-ready container images in one command. Tired of maintaining Dockerfiles? In this tutorial, you’ll learn how to use buildpacks to create optimized Spring Boot containers — fast, secure, and cloud-ready — with just one command. We’ll show what happens under the hood: automatic dependency detection, layered image creation, memory tuning, SBOM generation, and how to tweak builds with just a few plugin options. Need faster startup, smaller image size, or JFR monitoring? Buildpacks can handle it — and we’ll show you how.

Videos
card image
Aug 20, 2025
Flyway in Spring Boot: Step-by-Step tutorial with Maven

Learn how to use Flyway in Spring Boot with Maven for smooth and reliable database migrations. In this hands-on tutorial, we cover everything from setting up PostgreSQL in Docker, configuring Flyway in your application, writing versioned and repeatable migrations, to using Flyway in CI/CD pipelines with GitHub Actions. Whether you’re new to Flyway or want to master schema version control in Spring Boot, this video will guide you step by step.

Videos
card image
Aug 6, 2025
GraalVM for Java Developers: The Ultimate Beginner’s Guide

What is GraalVM and how can it improve your Java applications? In just 10 minutes, this video explains the three main components of GraalVM — the JIT compiler, Native Image, and Polyglot API. Learn how to boost performance, reduce startup time, and combine multiple languages in one app. Whether you’re building microservices, serverless apps, or just exploring modern JVM tooling, this is your quick-start guide to GraalVM.