How to map a PostgreSQL HStore entity property with JPA and Hibernate

(Last Updated On: January 18, 2019)
Imagine having a tool that can automatically detect if you are using JPA and Hibernate properly. Hypersistence Optimizer is that tool!

Introduction

The open-source hibernate-types project allows you to map a great variety of database types that are not supported natively by Hibernate ORM (e.g. JSON, ARRAY, YearMonth, Month, INET addresses).

In this article, we are going to see how you can map a PostgreSQL HStore type, which allows you to store key/value pairs, to a Java Map entity property when using JPA and Hibernate.

Maven dependency

First of all, you need to set up the following Maven dependency in your project pom.xml configuration file:

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

If you’re using older versions of Hibernate (e.g. 5.1 or 4.3), check out the hibernate-types GitHub repository for more info about the matching dependency for your current Hibernate version.

Domain Model

First of all, we need to make sure we have the hstore extension installed in our database:

CREATE EXTENSION IF NOT EXISTS hstore;

Our application needs to store Book entities in the following database table:

PostgreSQL HStore Book database table

Notice that the properties column type is hstore which is not supported by Hibernate ORM.

To map the PostgreSQL hstore column types to a Java Map, you need a custom Hibernate type since the built-in types don’t support persisting database-specific types. Luckily, thanks to the hibernate-types library you can easily map the book table to the following Book entity:

@Entity(name = "Book")
@Table(name = "book")
@TypeDef(name = "hstore", typeClass = PostgreSQLHStoreType.class)
public static class Book {

    @Id
    @GeneratedValue
    private Long id;

    @NaturalId
    @Column(length = 15)
    private String isbn;

    @Type(type = "hstore")
    @Column(columnDefinition = "hstore")
    private Map<String, String> properties = new HashMap<>();

    //Getters and setters omitted for brevity
}

The @TypeDef annotation is used to register the PostgreSQLHStoreType custom Hibernate Type with the hstore name. Afterward, the properties entity attribute uses the @Type annotation to specify that the hstore Hibernate Type should be used to handle this entity attribute.

Testing Time

Now, when storing the following Book entity:

Book book = new Book();

book.setIsbn("978-9730228236");
book.getProperties().put("title", "High-Performance Java Persistence");
book.getProperties().put("author", "Vlad Mihalcea");
book.getProperties().put("publisher", "Amazon");
book.getProperties().put("price", "$44.95");

entityManager.persist(book);

Hibernate executes the following SQL INSERT statement:

INSERT INTO book (isbn, properties, id)
VALUES (
    '978-9730228236', 
    '"author"=>"Vlad Mihalcea", 
     "price"=>"$44.95", "publisher"=>"Amazon", 
     "title"=>"High-Performance Java Persistence"', 
    1
)

And, when we fetch the Book entity, we can see that all properties are fetched properly.

Book book = entityManager
.unwrap(Session.class)
.bySimpleNaturalId(Book.class)
.load("978-9730228236");

assertEquals(
    "High-Performance Java Persistence", 
    book.getProperties().get("title")
);
assertEquals(
    "Vlad Mihalcea", 
    book.getProperties().get("author")
);

Awesome, right?

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

Conclusion

The hibernate-types project supports more than hstore PostgreSQL type. You can map PostgreSQL-specific Enums, nullable Character, JSON, or even provide your own immutable Hibernate custom Types.

For more details about the hibernate-types project, check out this article.

Download free ebook sample

Newsletter logo
10 000 readers have found this blog worth following!

If you subscribe to my newsletter, you'll get:
  • A free sample of my Video Course about running Integration tests at warp-speed using Docker and tmpfs
  • 3 chapters from my book, High-Performance Java Persistence,
  • a 10% discount coupon for my book.

2 Comments on “How to map a PostgreSQL HStore entity property with JPA and Hibernate

  1. I want to write the custom user type for PostgreSQL datatype Citext. Can you please help me how we do that?

    • You need to fork my hibernate-types GitHub repository and create the new type. Use the existing type to get a better idea of what you need to do. Once you created the user type and the test case that proves its working, send me a Pull Request and I’ll check it out to see if I can integrate it.

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.

Want to run your data access layer at warp speed?