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
Feb 6, 2026
Backend Developer Roadmap 2026: What You Need to Know

Backend complexity keeps growing, and frameworks can't keep up. In 2026, knowing React or Django isn't enough. You need fundamentals that hold up when systems break, traffic spikes, or your architecture gets rewritten for the third time.I've been building production systems for 15 years. This roadmap covers three areas that separate people who know frameworks from people who can actually architect backend systems: data, architecture, and infrastructure. This is about how to think, not what tools to install.

Videos
card image
Jan 29, 2026
JDBC Connection Pools in Microservices. Why They Break Down (and What to Do Instead)

In this livestream, Catherine is joined by Rogerio Robetti, the founder of Open J Proxy, to discuss why traditional JDBC connection pools break down when teams migrate to microservices, and what is a more efficient and reliable approach to organizing database access with microservice architecture.

Further watching

Videos
card image
Feb 27, 2026
Spring Developer Roadmap 2026: What You Need to Know

Spring Boot is powerful. But knowing the framework isn’t the same as understanding backend engineering. In this video, I walk through the roadmap I believe matters for a Spring developer in 2026. We start with data. That means real SQL — CTEs, window functions, normalization trade-offs — and understanding what ACID and BASE actually imply for system guarantees. Spring Data JPA is useful, but you still need to know what happens underneath. Then architecture: microservices vs modular monolith, serverless, CQRS, and when HTTP, gRPC, Kafka, or WebSockets make sense. Not as buzzwords — but as design choices with trade-offs. Security and infrastructure follow: OWASP Top 10, AuthN vs AuthZ, encryption in transit and at rest, Docker, Kubernetes, Infrastructure as Code, and observability with Micrometer, OpenTelemetry, and Grafana. This roadmap isn’t about mastering every tool. It’s about knowing what affects reliability in production.

Videos
card image
Feb 18, 2026
Build Typed AI Agents in Java with Embabel

Most Java AI demos stop at prompt loops. That doesn't scale in production. In this video, we integrate Embabel into an existing Spring Boot application and build a multi-step, goal-driven agent for incident triage. Instead of manually orchestrating prompt → tool → prompt cycles, we define typed actions and let the agent plan across deterministic and LLM-powered steps. We parse structured input with Ollama, query MongoDB deterministically, classify risk using explicit thresholds, rank affected implants, generate a constrained root cause hypothesis, and produce a bounded containment plan. LLM handles reasoning. Java enforces rules. This is about controlled AI workflows on the JVM — not prompt glue code.

Videos
card image
Feb 12, 2026
Spring Data MongoDB: From Repositories to Aggregations

Spring Data MongoDB breaks down fast once CRUD meets production—real queries, actual data volumes, analytics. What looks simple at first quickly turns into unreadable repository methods, overfetching, and slow queries. In this video, I walk through building a production-style Spring Boot application using Spring Data MongoDB — starting with basic setup and repositories, then moving into indexing, projections, custom queries, and aggregation pipelines. You'll see how MongoDB's document model changes data design compared to SQL, when embedding helps, and when it becomes a liability. We cover where repository method naming stops scaling, how to use @Query safely, when to switch to MongoTemplate, and how to reduce payload size with projections and DTOs. Finally, we implement real MongoDB aggregations to calculate analytics directly in the database and test everything against a real MongoDB instance using Testcontainers. This is not another MongoDB overview. It's a practical guide to actually using Spring Data MongoDB in production without fighting the database.