How to map a PostgreSQL HStore entity property with JPA and Hibernate
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
The Hypersistence Utils open-source 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.
How to map a PostgreSQL HStore entity property with JPA and #Hibernate . @vlad_mihalcea https://t.co/360MtHSYmw pic.twitter.com/KcXP3PD6lO
— Java (@java) January 5, 2019
Maven dependency
First of all, you need to set up the following Maven dependency in your project pom.xml
configuration file:
<dependency> <groupId>io.hypersistence</groupId> <artifactId>hypersistence-utils-hibernate-55</artifactId> <version>${hypersistence-utils.version}</version> </dependency>
If you’re using older versions of Hibernate (e.g., 5.4, 5.3, or 5.2), check out the Hypersistence Utils 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:
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 Hypersistence Utils library you can easily map the book
table to the following Book
entity.
For Hibernate 6, the mapping will look as follows:
@Entity(name = "Book") @Table(name = "book") public class Book { @Id @GeneratedValue private Long id; @NaturalId @Column(length = 15) private String isbn; @Type(PostgreSQLHStoreType.class) @Column(columnDefinition = "hstore") private Map<String, String> properties = new HashMap<>(); }
And for Hibernate 5, like this:
@Entity(name = "Book") @Table(name = "book") @TypeDef(name = "hstore", typeClass = PostgreSQLHStoreType.class) public 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<>(); }
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?
I'm running an online workshop on the 11th of October about High-Performance SQL.If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.
Conclusion
The Hypersistence Utils 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
.
