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

StackOverflow is a gold mine! Check out this question I bumped into this morning. Basically, 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 an 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 Hibernate Types project.

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

<dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-55</artifactId>
    <version>${hibernate-types.version}</version>
</dependency>

For more info about which dependency to use based on the Hibernate version you are using, check out the Hibernate Types project GitHub page.

Testing time

Assuming we have the following entity:

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

    @Id
    @GeneratedValue
    private Long id;

    @Type(type = "com.vladmihalcea.hibernate.type.basic.NullableCharacterType")
    @Column(name = "event_type")
    private Character type;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Character getType() {
        return type;
    }

    public void setType(Character type) {
        this.type = type;
    }
}

And 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!

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 Hibernate. Although the UserType does the trick, usually, the the SqlTypeDescriptor approach is to be preferred.

However, it’s even easier if you use the Hibernate Types project and just get an implementation that’s tested by millions of developers on a per monthly basis instead of having to write it yourself.

Transactions and Concurrency Control eBook

Leave a Reply

Your email address will not be published.

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