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.

Partner – Microsoft – NPI EA (cat = Baeldung)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, visit the documentation page.

You can also ask questions and leave feedback on the Azure Container Apps GitHub page.

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

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, you can get started over on the documentation page.

And, you can also ask questions and leave feedback on the Azure Container Apps GitHub page.

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

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag=Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

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 – All Access – NPI EA (cat= Spring)
announcement - icon

All Access is finally out, with all of my Spring courses. Learn JUnit is out as well, and Learn Maven is coming fast. And, of course, quite a bit more affordable. Finally.

>> GET THE COURSE
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 – LambdaTest – NPI EA (cat=Testing)
announcement - icon

End-to-end testing is a very useful method to make sure that your application works as intended. This highlights issues in the overall functionality of the software, that the unit and integration test stages may miss.

Playwright is an easy-to-use, but powerful tool that automates end-to-end testing, and supports all modern browsers and platforms.

When coupled with LambdaTest (an AI-powered cloud-based test execution platform) it can be further scaled to run the Playwright scripts in parallel across 3000+ browser and device combinations:

>> Automated End-to-End Testing With Playwright

Course – Spring Sale 2025 – NPI EA (cat= Baeldung)
announcement - icon

Yes, we're now running our Spring Sale. All Courses are 25% off until 26th May, 2025:

>> EXPLORE ACCESS NOW

Course – Spring Sale 2025 – NPI (cat=Baeldung)
announcement - icon

Yes, we're now running our Spring Sale. All Courses are 25% off until 26th May, 2025:

>> EXPLORE ACCESS NOW

1. Overview

Identifiers in Hibernate represent the primary key of an entity. This implies the values are unique so they can identify a specific entity, that isn’t null and won’t be modified.

Hibernate provides several different ways to define identifiers. In this article, we’ll review each method of mapping entity IDs.

2. Simple Identifiers

The most straightforward way to define an identifier is by using the @Id annotation.

Simple IDs are mapped using @Id to a single property of Java primitive and primitive wrapper types, along with String, Date, BigDecimal, and BigInteger.

Let’s see a quick example of defining an entity with a primary key of type long:

@Entity
public class TennisPlayer {

    @Id
    private long playerId;
    private String name;

    public TennisPlayer(String name) {
        this.name = name;
    }
    // getters, setters
}

Next, let’s create a TennisPlayer and persist it:

@Test
public void whenSavingTennisPlayerWithoutAnId_thenSavingEntityOk() {
    TennisPlayer tennisPlayer = new TennisPlayer("Tom");
    session.save(tennisPlayer);
    assertThat(tennisPlayer.getPlayerId()).isEqualTo(0L);
}

As we can see, although we forgot to set tennisPlayer.playerId, the entity persisted successfully. This is because zero is the default value for primitive numbers, such as int and long.

It’s worth mentioning that this might not be the desired result. We usually want to set the value of an identifier explicitly rather than rely on the default of zero.

Next, let’s create another entity using Long as the @Id type:

@Entity
public class BaseballPlayer {

    @Id
    private Long playerId; // Long instead of long
    private String name;
 
    public BaseballPlayer(String name) {
        this.name = name;
    }
    // getters, setters
}

BaseballPlayer is pretty similar to TennisPlayer except that the @Id type is a primitive wrapper type, Long. Next, let’s persist a new BaseballPlayer entity:

@Test
public void whenSavingBaseballPlayerWithoutAnId_thenSavingEntityFails() {
    BaseballPlayer baseballPlayer = new BaseballPlayer("Jerry");
    assertThatThrownBy(() -> session.save(baseballPlayer))
      .isInstanceOf(IdentifierGenerationException.class)
      .hasMessageContaining("ids for this class must be manually assigned before calling save()");
}

This time, when we persist baseballPlayer without setting its @Id field, Hibernate throws IdentifierGenerationExceptionThis is because Hibernate cannot determine the primary key value when the @Id field is null.

The exception’s error message gives us the tip to fix the issue — manually set an @Id value before saving:

@Test
public void whenSavingBaseballPlayerWithAManualId_thenSavingEntityOK() {
    BaseballPlayer baseballPlayer = new BaseballPlayer("Jerry");
    baseballPlayer.setPlayerId(42L);
    session.save(baseballPlayer);
}

As we can see, simple identifiers are straightforward. However, if it isn’t primitive, we must assign the @Id value manually. This can help encourage us to remember to set the value of an identifier before persisting.

Next, let’s see if we can somehow generate the @Id value automatically.

3. Generated Identifiers

If we want to automatically generate the primary key value, we can add the @GeneratedValue annotation.

This can use four generation types: AUTO, IDENTITY, SEQUENCE, and TABLE.

If we don’t explicitly specify a value, the generation type defaults to AUTO.

3.1. AUTO Generation

If we’re using the default generation type, the persistence provider will determine values based on the type of the primary key attribute. This type can be numerical or UUID.

For numeric values, the generation is based on a sequence or table generator, while UUID values will use the UUIDGenerator.

Let’s first map an entity’s primary key using the AUTO generation strategy:

@Entity
public class Student {

    @Id
    @GeneratedValue
    private long studentId;

    // ...
}

In this case, the primary key values will be unique at the database level.

Now we’ll look at the UUIDGenerator, which was introduced in Hibernate 5.

To use this feature, we just need to declare an id of type UUID with @GeneratedValue annotation:

@Entity
public class Course {

    @Id
    @GeneratedValue
    private UUID courseId;

    // ...
}

Hibernate will generate an id of the form “8dd5f315-9788-4d00-87bb-10eed9eff566”.

3.2. IDENTITY Generation

This type of generation relies on the IdentityGenerator, which expects values generated by an identity column in the database. This means they are auto-incremented.

To use this generation type, we only need to set the strategy parameter:

@Entity
public class Student {

    @Id
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    private long studentId;

    // ...
}

One thing to note is that IDENTITY generation disables batch updates.

3.3. SEQUENCE Generation

To use a sequence-based ID, Hibernate provides the SequenceStyleGenerator class.

This generator uses sequences if our database supports them. It switches to table generation if they aren’t supported.

To customize the sequence name, we can use the @GenericGenerator annotation with SequenceStyleGenerator strategy:

@Entity
public class User {
    @Id
    @GeneratedValue(generator = "sequence-generator")
    @GenericGenerator(
      name = "sequence-generator",
      strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
      parameters = {
        @Parameter(name = "sequence_name", value = "user_sequence"),
        @Parameter(name = "initial_value", value = "4"),
        @Parameter(name = "increment_size", value = "1")
        }
    )
    private long userId;
    
    // ...
}

In this example, we’ve also set an initial value for the sequence, which means the primary key generation will start at 4.

SEQUENCE is the generation type recommended by the Hibernate documentation.

The generated values are unique per sequence. If we don’t specify a sequence name, Hibernate will reuse the same hibernate_sequence for different types.

3.4. TABLE Generation

The TableGenerator uses an underlying database table that holds segments of identifier generation values.

Let’s customize the table name using the @TableGenerator annotation:

@Entity
public class Department {
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, 
      generator = "table-generator")
    @TableGenerator(name = "table-generator", 
      table = "dep_ids", 
      pkColumnName = "seq_id", 
      valueColumnName = "seq_value")
    private long depId;

    // ...
}

In this example, we can see that we can also customize other attributes such as the pkColumnName and valueColumnName.

However, the disadvantage of this method is that it doesn’t scale well and can negatively affect performance.

To sum up, these four generation types will result in similar values being generated but use different database mechanisms.

3.5. Custom Generator

Let’s say we don’t want to use any of the out-of-the-box strategies. In order to do that, we can define our custom generator by implementing the IdentifierGenerator interface.

We’ll create a generator that builds identifiers containing a String prefix and a number:

public class MyGenerator 
  implements IdentifierGenerator, Configurable {

    private String prefix;

    @Override
    public Serializable generate(
      SharedSessionContractImplementor session, Object obj) 
      throws HibernateException {

        String query = String.format("select %s from %s", 
            session.getEntityPersister(obj.getClass().getName(), obj)
              .getIdentifierPropertyName(),
            obj.getClass().getSimpleName());

        Stream ids = session.createQuery(query).stream();

        Long max = ids.map(o -> o.replace(prefix + "-", ""))
          .mapToLong(Long::parseLong)
          .max()
          .orElse(0L);

        return prefix + "-" + (max + 1);
    }

    @Override
    public void configure(Type type, Properties properties, 
      ServiceRegistry serviceRegistry) throws MappingException {
        prefix = properties.getProperty("prefix");
    }
}

In this example, we override the generate() method from the IdentifierGenerator interface.

First, we want to find the highest number from the existing primary keys of the form prefix-XX. Then we add 1 to the maximum number found and append the prefix property to get the newly generated id value.

Our class also implements the Configurable interface so that we can set the prefix property value in the configure() method.

Next, let’s add this custom generator to an entity.

For this, we can use the @GenericGenerator annotation with a strategy parameter that contains the full class name of our generator class:

@Entity
public class Product {

    @Id
    @GeneratedValue(generator = "prod-generator")
    @GenericGenerator(name = "prod-generator", 
      parameters = @Parameter(name = "prefix", value = "prod"), 
      strategy = "com.baeldung.hibernate.pojo.generator.MyGenerator")
    private String prodId;

    // ...
}

Also, notice we’ve set the prefix parameter to “prod”.

Let’s see a quick JUnit test for a clearer understanding of the id values generated:

@Test
public void whenSaveCustomGeneratedId_thenOk() {
    Product product = new Product();
    session.save(product);
    Product product2 = new Product();
    session.save(product2);

    assertThat(product2.getProdId()).isEqualTo("prod-2");
}

Here the first value generated using the “prod” prefix was “prod-1”, followed by “prod-2”.

3.6. Custom @IdGeneratorType With Manually Assigned Identifier

If we want more control over ID generation and prefer not to rely on built-in strategies, we can create a custom ID generator using Hibernate’s @IdGeneratorType annotation.

This allows manual ID assignment while still giving Hibernate the option to generate IDs automatically when needed. The allowAssignedIdentifiers() method, introduced in Hibernate 6.5, lets us control whether manually assigned IDs are accepted.

Let’s look at the custom MovieIdGenerator:

public class MovieIdGenerator extends SequenceStyleGenerator {
    @Override
    public Object generate(SharedSessionContractImplementor session, Object owner) throws HibernateException {
        final Long id;
        if (this.allowAssignedIdentifiers() && owner instanceof Movie) {
            id = ((Movie) owner).getId();
        } else {
            id = null;
        }
        return id != null ? id : super.generate(session, owner);
    }

    @Override
    public boolean allowAssignedIdentifiers() {
        return true;
    }
}

In this case, we override generate() to either use a manually assigned ID or let Hibernate generate one automatically.

We’ll add the custom annotation @MovieGeneratedId:

@IdGeneratorType(MovieIdGenerator.class)
@Target({ FIELD })
@Retention(RetentionPolicy.RUNTIME)
@interface MovieGeneratedId {
}

Let’s say we want to define a custom strategy for generating IDs in our Movie entity:

@Entity
public class Movie {
    @Id
    @MovieGeneratedId
    private Long id;

    private String title;
    private String director;
}

Let’s dive into how our MovieRepository manages both auto-generated and manually assigned IDs.

Here, we create a Movie object without setting an ID. Upon saving, MovieRepository automatically generates a unique ID:

@Test
void givenMovie_whenCreatingAndRetrievingMovie_thenCorrectMovieIsRetrieved() {
    Movie movie = new Movie("3 Idiots", "Rajkumar Hirani");
    Movie savedMovie = movieRepository.save(movie);
    assertNotNull(savedMovie.getId());
    assertEquals("3 Idiots", savedMovie.getTitle());
    assertEquals("Rajkumar Hirani", savedMovie.getDirector());
}

When a Movie object is created with a manually assigned ID, MovieRepository keeps this specified ID instead of generating a new one when saving:

@Test
void givenManualId_whenCreatingAndRetrievingMovie_thenCorrectMovieIsRetrieved() {
    Movie movie = new Movie(10L, "Inception", "Christopher Nolan");
    Movie savedMovie = movieRepository.save(movie);
    assertEquals(10L, savedMovie.getId());
    assertEquals("Inception", savedMovie.getTitle());
    assertEquals("Christopher Nolan", savedMovie.getDirector());
}

4. Composite Identifiers

Besides the simple identifiers we’ve seen so far, Hibernate also allows us to define composite identifiers.

A composite id is represented by a primary key class with one or more persistent attributes.

The primary key class must fulfill several conditions:

  • It should be defined using @EmbeddedId or @IdClass annotations.
  • It should be public, serializable and have a public no-arg constructor.
  • Finally, it should implement equals() and hashCode() methods.

The class’s attributes can be basic, composite or ManyToOne, while avoiding collections and OneToOne attributes.

4.1. @EmbeddedId

Now let’s look at how to define an id using @EmbeddedId.

First, we need a primary key class annotated with @Embeddable:

@Embeddable
public class OrderEntryPK implements Serializable {

    private long orderId;
    private long productId;

    // standard constructor, getters, setters
    // equals() and hashCode() 
}

Next, we can add an id of type OrderEntryPK to an entity using @EmbeddedId:

@Entity
public class OrderEntry {

    @EmbeddedId
    private OrderEntryPK entryId;

    // ...
}

Let’s see how we can use this type of composite id to set the primary key for an entity:

@Test
public void whenSaveCompositeIdEntity_thenOk() {
    OrderEntryPK entryPK = new OrderEntryPK();
    entryPK.setOrderId(1L);
    entryPK.setProductId(30L);
        
    OrderEntry entry = new OrderEntry();
    entry.setEntryId(entryPK);
    session.save(entry);

    assertThat(entry.getEntryId().getOrderId()).isEqualTo(1L);
}

Here the OrderEntry object has an OrderEntryPK primary id formed of two attributes: orderId and productId.

4.2. @IdClass

The @IdClass annotation is similar to the @EmbeddedId. The difference with @IdClass is that the attributes are defined in the main entity class using @Id for each one. The primary key class will look the same as before.

Let’s rewrite the OrderEntry example with an @IdClass:

@Entity
@IdClass(OrderEntryPK.class)
public class OrderEntry {
    @Id
    private long orderId;
    @Id
    private long productId;
    
    // ...
}

Then we can set the id values directly on the OrderEntry object:

@Test
public void whenSaveIdClassEntity_thenOk() {        
    OrderEntry entry = new OrderEntry();
    entry.setOrderId(1L);
    entry.setProductId(30L);
    session.save(entry);

    assertThat(entry.getOrderId()).isEqualTo(1L);
}

Note that for both types of composite ids, the primary key class can also contain @ManyToOne attributes:

@Embeddable
public class OrderEntryPK implements Serializable {

    private long orderId;
    private long productId;
    @ManyToOne
    private User user;

    // ...
}
@Entity
@IdClass(OrderEntryPK.class)
public class OrderEntryIdClass {
    @Id
    private long orderId;
    @Id
    private long productId;
    @ManyToOne
    private User user;

    // ...
}

Hibernate also allows defining primary keys made up of @ManyToOne associations combined with @Id annotation. In this case, the entity class should also fulfil the conditions of a primary key class.

However, the disadvantage of this method is that there’s no separation between the entity object and the identifier.

5. Derived Identifiers

Derived identifiers are obtained from an entity’s association using the @MapsId annotation.

First, let’s create a UserProfile entity that derives its id from a one-to-one association with the User entity:

@Entity
public class UserProfile {

    @Id
    private long profileId;
    
    @OneToOne
    @MapsId
    private User user;

    // ...
}

Next, let’s verify that a UserProfile instance has the same id as its associated User instance:

@Test
public void whenSaveDerivedIdEntity_thenOk() {        
    User user = new User();
    session.save(user);
       
    UserProfile profile = new UserProfile();
    profile.setUser(user);
    session.save(profile);

    assertThat(profile.getProfileId()).isEqualTo(user.getUserId());
}

6. Conclusion

In this tutorial, we’ve seen the multiple ways we can define identifiers in Hibernate.

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.

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

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, visit the documentation page.

You can also ask questions and leave feedback on the Azure Container Apps GitHub page.

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

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag = Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

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

Course – Spring Sale 2025 – NPI EA (cat= Baeldung)
announcement - icon

Yes, we're now running our Spring Sale. All Courses are 25% off until 26th May, 2025:

>> EXPLORE ACCESS NOW

Course – Spring Sale 2025 – NPI (All)
announcement - icon

Yes, we're now running our Spring Sale. All Courses are 25% off until 26th May, 2025:

>> EXPLORE ACCESS NOW

Course – LSD – NPI (cat=JPA)
announcement - icon

Get started with Spring Data JPA through the reference Learn Spring Data JPA:

>> CHECK OUT THE COURSE

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