eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

Partner – Diagrid – NPI EA (cat= Testing)
announcement - icon

In distributed systems, managing multi-step processes (e.g., validating a driver, calculating fares, notifying users) can be difficult. We need to manage state, scattered retry logic, and maintain context when services fail.

Dapr Workflows solves this via Durable Execution which includes automatic state persistence, replaying workflows after failures and built-in resilience through retries, timeouts and error handling.

In this tutorial, we'll see how to orchestrate a multi-step flow for a ride-hailing application by integrating Dapr Workflows and Spring Boot:

>> Dapr Workflows With PubSub

1. Introduction

In this tutorial, we’re going to review the Jimmer ORM framework. This ORM is relatively new at the time of this article, but it has some promising features. We’re going to review Jimmer’s philosophy, and then write some examples with it.

2. Overall Architecture

First things first, Jimmer is not a JPA implementation. That means that Jimmer does not implement every JPA feature. For instance, Jimmer does not have a dirty checking mechanism as such. However, it is worth mentioning that Jimmer, like Hibernate, has a lot of similar concepts. That is intentional in order to make the transition from Hibernate smoother. So, in general, the JPA knowledge would be helpful in understanding the Jimmer in general.

As an example, Jimmer has a concept of an entity, although its shape and design differ from Hibernate extensively. However, concepts like lazy loading or cascading are not present in Jimmer as such. The reason is that they don’t really make much sense in the Jimmer because of the way it is designed. We’ll see that shortly.

Final note for this section: Jimmer supports multiple databases, including MySQL, Oracle, PostgreSQL, SQL Server, SQLite, and H2.

3. Entity Sample

As mentioned, Jimmer has a lot of differences from Hibernate and many other ORM frameworks; it has several key design principles. The first one is that our entities serve a sole purpose – representing the schema of the underlying database. But, the important thing here is that we do not specify the way we intend to interact with it via annotations. Instead, Jimmer requires the developer to provide all the information necessary to derive the query to be executed on the call site.

So, what does that mean? To understand, let’s review the following Jimmer entity:

import org.babyfish.jimmer.client.TNullable;
import org.babyfish.jimmer.sql.Column;
import org.babyfish.jimmer.sql.Entity;
import org.babyfish.jimmer.sql.GeneratedValue;
import org.babyfish.jimmer.sql.GenerationType;
import org.babyfish.jimmer.sql.Id;
import org.babyfish.jimmer.sql.JoinColumn;
import org.babyfish.jimmer.sql.ManyToOne;
import org.babyfish.jimmer.sql.OneToMany;

@Entity
public interface Book {
    @Id
    @GeneratedValue(strategy = GenerationType.USER)
    long id();

    @Column(name = "title")
    String title();

    @Column(name = "created_at")
    Instant createdAt();

    @ManyToOne
    @JoinColumn(name = "author_id")
    Author author();

    @TNullable
    @Column(name = "rating")
    Long rating();

    @OneToMany(mappedBy = "book")
    List<Page> pages();

    // equals and hashcode implementation
}

As you can notice, it has annotations similar to JPA. But one thing is missing – we do not specify any cascading for the relations, such as pages in our case. Similar for fetch type (lazy or eager) – on the declaration side – it is not specified. We also cannot specify the insertable or updatable attributes of the @Column annotation as we probably would in JPA and so on.

We do not do that because Jimmer expects us to provide it explicitly when we try to execute the appropriate operation. We’ll see that in detail in the sections below.

4. DTO Language

Another thing that hits us instantly is that the Book is an interface, not a class. This is intentional, since in Jimmer, we’re not supposed to work with entities directly, that is to say, that we’re not supposed to instantiate them. Instead, the assumption is that we’re going to both read and write data via DTOs. And those DTOs should have the exact shape that we want to write or read from the database. Let’s look at an example (do not focus on the exact API calls that we make right now):

public void saveAdHocBookDraft(String title) {
    Book book = BookDraft.$.produce(bookDraft -> {
        bookDraft.setCreatedAt(Instant.now());
        bookDraft.setTitle(title);
        bookDraft.setAuthor(AuthorDraft.$.produce(authorDraft -> {
            authorDraft.setId(1L);
        }));
        bookDraft.setId(1L);
    });
    sqlClient.save(book);
}

In general, in most interactions, we need to use the SqlClient in order to interact with the database.

In the sample above, we’re creating an ad-hoc DTO via the BookDraft interface. Jimmer generated the BookDraft interface along with AuthorDraft for us, it is not handwritten code. The generation itself happens during compile time via the Java Annotation Processing Tool in case we’re using Java, or via Kotlin Symbol Processing in case we’re using Kotlin.

These two generated interfaces allow for the construction of a DTO object of an arbitrary shape, which Jimmer internally converts later to a Book entity. So, we’re indeed saving an entity, it is just that we’re not instantiating it ourselves, rather, Jimmer does it for us.

5. Null Handling

Also, Jimmer would only save the components that are present in the DTO. That is because Jimmer has a strict distinction between the property that was not set in the first place and the property that is explicitly set to null. In other words, if we do not want to include the given scalar property in the generated SQL, we simply create a DTO without explicitly setting it. By scalar, we mean fields that do not represent the relation property:

public void insertOnlyIdAndAuthorId() {
    Book book = BookDraft.$.produce(
        bookDraft -> {
            bookDraft.setAuthor(AuthorDraft.$.produce(authorDraft -> {
                authorDraft.setId(1L);
            }));
            bookDraft.setId(1L);
        });
    sqlClient.insert(book);
}

The generated INSERT for Book in the case above would look like this:

INSERT INTO BOOK(ID, author_id) VALUES(?, ?)

If we explicitly set a scalar property to null, then Jimmer would include this property in the underlying INSERT/UPDATE statement and assign a null value to it:

public void insertExplicitlySetRatingToNull() {
    Book book = BookDraft.$.produce(bookDraft -> {
        bookDraft.setAuthor(AuthorDraft.$.produce(authorDraft -> {
            authorDraft.setId(1L);
        }));
        bookDraft.setRating(null);
        bookDraft.setId(1L);
    });
    sqlClient.insert(book);
}

The generated INSERT statement would look like this:

INSERT INTO BOOK(ID, author_id, rating) VALUES(?, ?, ?)

Notice that INSERT includes the rating property. The bind value of this rating property would be set to null in the underlying JDBC Statement.

Last word, for properties that represent relations (non-scalar properties), the behavior is more complicated and deserves a separate article.

6. DTO Explosion Problem

Now, the experienced developers may notice a problem. Jimmer’s approach of working with the database would imply the creation of dozens of DTOs, each for some unique operation. The answer is – not quite. Although we would indeed need a lot of DTOs, we can significantly reduce the overhead of writing them manually. The reason for that is a dedicated DTO language that Jimmer has. Here is an example of it:

export com.baeldung.jimmer.models.Book
    -> package com.baeldung.jimmer.dto

BookView {
   #allScalars(Book)
   author {
     id
   }
   pages {
    #allScalars(Page)
   }
}

The above example represents a markup, written in Jimmer DTO language. The generation of POJOs out of this markup language happens during compilation time, as with the examples in the previous section.

In the markup above, for instance, we’ve asked Jimmer to include all the scalar fields in the generated DTO by using the #allScalars instruction. Apart from them, we’ve also mentioned that the DTO would only have the ID of the Author, not the Author itself. The collections of pages would be present in the DTO in their entirety (only scalar fields).

So, in general, with Jimmer, we indeed need a lot of DTOs in order to describe the desired behavior in every case. But we can either create the ad-hoc version or rely on the POJOs that the compiler plugin generates for us during the build.

7. Reading Path

Up until now, we’ve only talked about the ways of saving data into the database. Let’s review the reading path. In order to read the data, we also need to specify exactly what data we need to fetch via the DTO. The very shape of the DTO instructs the Jimmer of what exactly fields need to be fetched. If the field is not present in the DTO, it will not be fetched:

public List<BookView> findAllByTitleLike(String title) {
    List<BookView> values = sqlClient.createQuery(BookTable.$)
      .where(BookTable.$.title()
        .like(title))
      .select(BookTable.$.fetch(BookView.class))
      .execute();
        
    return values;
}

Here, we’re using the BookView DTO from the previous section. We can also specify the columns we need to read via Fetcher’s ad-hoc API. It is very similar to one that we used during writing to the database:

public List<BookView> findAllByTitleLikeProjection(String title) {
    List<Book> books = sqlClient.createQuery(BookTable.$)
      .where(BookTable.$.title()
        .like(title))
      .select(BookTable.$.fetch(Fetchers.BOOK_FETCHER.title()
        .createdAt()
        .author()))
      .execute();

    return books.stream()
      .map(BookView::new)
      .collect(Collectors.toList());
}

Here, we’re using the Object Fetcher API to construct the DTO that represents the shape of the structure we want to read. But we still signal the columns we want to read on the call site and not the declaration site. This approach is very similar to an ad-hoc creation of a DTO for saving.

7. Transaction Management

Finally, we’re going to quickly review the way Jimmer manages transactions. In general, Jimmer does not have a built-in transaction management mechanism on its own. Therefore, Jimmer relies on the Spring Framework’s transaction management infrastructure heavily. For instance, let’s review the local transaction management usage (not distributed), which is the most often scenario. In this case, Jimmer relies on the Spring’s TransactionSynchronizationManager capabilities and the transactional connection to be bound to the current thread.

To sum up the above, the traditional usage of Spring’s @Transactional is going to work for Jimmer. The imperative transaction management via Spring’s TransactionTemplate is also possible for Jimmer.

8. Conclusion

In this article, we’ve talked about Jimmer ORM. As we saw, Jimmer takes a unique approach in terms of data manipulation. While JPA and Hibernate, in particular, express the means of interactions with the database primarily via annotations, Jimmer requires developers to provide all the information dynamically at the call site. For this, Jimmer uses DTOs, which we typically would generate via Jimmer itself using its DTO language. However, we can also create them ad-hoc. In terms of transaction management, Jimmer relies on the Spring Framework’s infrastructure.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook Jackson – NPI EA – 3 (cat = Jackson)