How to implement a custom basic type using Hibernate UserType

Imagine having a tool that can automatically detect JPA and Hibernate performance issues. Wouldn’t that be just awesome?

Well, Hypersistence Optimizer is that tool! And it works with Spring Boot, Spring Framework, Jakarta EE, Java EE, Quarkus, or Play Framework.

So, enjoy spending your time on the things you love rather than fixing performance issues in your production system on a Saturday night!

Introduction

In this article, we are going to see how we can implement a custom type using the Hibernate UserType interface.

If you wonder why you’d ever want to do this, then check out this question.

Our Hibernate user wants a resilient CharacterType that works with NULL or empty values. To make it even more interesting, we are going to make it work even if the underlying database column contains more than one character.

Custom type flavors

There are two ways to write a custom Hibernate type:

  • Using a SqlTypeDescriptor
  • Using the legacy UserType

While the former way is usually preferred, as demonstrated by this generic JSON type that works on both MySQL and PostgreSQL, I’m going to use the latter method to demonstrate how the UserTpe abstraction works.

For the current use case, we are going to use the NullableCharacterType from the Hypersistence Utils project.

First, you need to add the following dependency to your project:

<dependency>
    <groupId>io.hypersistence</groupId>
    <artifactId>hypersistence-utils-hibernate-55</artifactId>
    <version>${hypersistence-utils.version}</version>
</dependency>

For more info about which dependency to use based on the Hibernate version you are using, check out the Hypersistence Utils GitHub repository.

Testing time

Assuming we have an Event entity, for Hibernate 6, the mapping will look as follows:

@Entity(name = "Event")
@Table(name = "event")
public class Event {

    @Id
    @GeneratedValue
    private Long id;

    @Type(NullableCharacterType.class)
    @Column(name = "event_type")
    private Character type;
}

And for Hibernate 5, like this:

@Entity(name = "Event")
@Table(name = "event")
public class Event {

    @Id
    @GeneratedValue
    private Long id;

    @Type(type = "io.hypersistence.utils.hibernate.type.basic.NullableCharacterType")
    @Column(name = "event_type")
    private Character type;
}

And if we have the following entries in the database:

INSERT INTO event (id, event_type) VALUES (1, 'abc');    
INSERT INTO event (id, event_type) VALUES (2, '');
INSERT INTO event (id, event_type) VALUES (3, 'b');

When selecting and logging all event entries:

doInJPA(entityManager -> {
    List<Event> events = entityManager.createQuery(
        "select e from Event e", Event.class)
    .getResultList();
    for(Event event : events) {
        LOGGER.info("Event type: {}", event.getType());
    }
});

The following output is obtained:

Event type: a
Event type:  
Event type: b

Great!

I'm running an online workshop on the 20-21 and 23-24 of November about High-Performance Java Persistence.

If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.

Conclusion

Writing a custom type is very easy with the Hibernate UserType.

However, in this case here, you don’t even have to create the NullableCharacterType.You can just use the Hypersistence Utils project and get this type right out of the box.

Transactions and Concurrency Control eBook

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.