Partner – JPA Buddy – NPI (tag=JPA/Hibernate)
announcement - icon

The right tools can and will save a lot of time. As long as you are using Hibernate and IntelliJ IDEA you can boost your coding speed and quality with JPA Buddy. It will help in a lot of the day-to-day work:

  • Creating JPA entities that follow best practices for efficient mapping
  • Creating DTOs from entities and MapStruct mappers using convenient visual tools
  • Generating entities from the existing database or Swagger-generated POJOs
  • Visually composing methods for Spring Data JPA repositories
  • Generating differential SQL to update your schema in accordance with your changes in entities
  • Autogenerating Flyway migrations and Liquibase changelogs comparing entities with the database or two databases
  • … and a lot more

Simply put, you'll learn and use the best practices of Hibernate and surrounding technology and become a lot more!

Definitely visit the JPA Buddy site to see its features in action closer.

Persistence top

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

>> CHECK OUT THE COURSE

1. Overview

In this article, we'll talk about how we can make an entity, collection or attribute Immutable in Hibernate.

By default, fields are mutable, which means we're able to perform operations on them that change their state.

2. Maven

To get our project up and running, we first need to add the necessary dependencies into our pom.xml. And as we're working with Hibernate, we are going to add the corresponding dependency:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.6.7.Final</version>
</dependency>

And, because we are working with HSQLDB, we also need:

<dependency>
    <groupId>org.hsqldb</groupId>
    <artifactId>hsqldb</artifactId>
    <version>2.3.4</version>
</dependency>

3. Annotation on Entities

First, let's define a simple entity class:

@Entity
@Immutable
@Table(name = "events_generated")
public class EventGeneratedId {

    @Id
    @Column(name = "event_generated_id")
    @GeneratedValue(generator = "increment")
    @GenericGenerator(name = "increment", strategy = "increment")
    private Long id;

    @Column(name = "name")
    private String name;
    @Column(name = "description")
    private String description;

    // standard setters and getters
}

As you have noticed we have added already the @Immutable annotation to our entity, so if we try and save an Event:

@Test
public void addEvent() {
    Event event = new Event();
    event.setId(2L);
    event.setTitle("Public Event");
    session.save(event);
    session.getTransaction().commit();
    session.close();
}

Then we should get the output:

Hibernate: insert into events (title, event_id) values (?, ?)

The output should be the same even if we remove the annotation, meaning there's no effect when we try to add an entity regardless of the annotation.

It's also important to note that in our EventGeneratedId entity, we added the GeneratedValue annotation, but this will only make a difference when we're creating an entity. That's because it specifies the generation strategy for the id – any other operations will not affect the Id field due to the Immutable annotation.

3.1. Updating the Entity

Now, we had no issue saving an entity, let's try to update it:

@Test
public void updateEvent() {
    Event event = (Event) session.createQuery(
      "FROM Event WHERE title='My Event'").list().get(0);
    event.setTitle("Public Event");
    session.saveOrUpdate(event);
    session.getTransaction().commit();
}

Hibernate will simply ignore the update operation without throwing an exception. However, if we remove the @Immutable annotation we get a different result:

Hibernate: select ... from events where title='My Event'
Hibernate: update events set title=? where event_id=?

What this tells us is that our object is now mutable (mutable is the default value if we don't include the annotation) and will allow the update to do its job.

3.2. Deleting an Entity

When it comes to deleting an entity:

@Test
public void deleteEvent() {
    Event event = (Event) session.createQuery(
      "FROM Event WHERE title='My Event'").list().get(0);
    session.delete(event);
    session.getTransaction().commit();
}

We'll be able to perform the delete regardless if it is mutable or not:

Hibernate: select ... from events where title='My Event'
Hibernate: delete from events where event_id=?

4. Annotation on Collections

So far we've seen what the annotation does to entities, but as we mentioned in the beginning, it can also be applied to collections.

First, let's add a collection to our Event class:

@Immutable
public Set<String> getGuestList() {
    return guestList;
}

Same as before, we've added the annotation beforehand, so if we go ahead and try to add an element to our collection:

org.hibernate.HibernateException: 
  changed an immutable collection instance: [com.baeldung.entities.Event.guestList#1]

This time we get an exception because with collections we are not allowed to add nor delete them.

4.1. Deleting Collections

The other scenario where a Collection by being immutable will throw an exception it's whenever we try to delete and we have set the @Cascade annotation.

So, whenever @Immutable is present and we attempt to delete:

@Test
public void deleteCascade() {
    Event event = (Event) session.createQuery(
      "FROM Event WHERE title='Public Event'").list().get(0);
    String guest = event.getGuestList().iterator().next();
    event.getGuestList().remove(guest);
    session.saveOrUpdate(event);
    session.getTransaction().commit();
}

Output:

org.hibernate.HibernateException: 
  changed an immutable collection instance:
  [com.baeldung.entities.Event.guestList#1]

5. XML Notes

Finally, the configuration can also be done using XML through the mutable=false attribute:

<hibernate-mapping>
    <class name="com.baeldung.entities.Event" mutable="false">
        <id name="id" column="event_id">
            <generator class="increment"/>
        </id>
        <property name="title"/>
    </class>
</hibernate-mapping>

However, since we basically implemented the examples using the annotation method, we will not get into details using XML.

6. Conclusion

In this quick article, we explore the useful @Immutable annotation out of Hibernate, and how that can help us define better semantics and constraints on our data.

As always, the implementation of all of these examples and snippets can be found in the GitHub project. This is a Maven-based project so it should be easy to import and run.

Persistence bottom

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

>> CHECK OUT THE COURSE
Persistence footer banner
Comments are closed on this article!