The best way to use the Hibernate TupleTransformer
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, I’m going to explain how the Hibernate TupleTransformer works and how to use it to replace the deprecated ResultTransformer.
The deprecated ResultTransformer
Prior to using Hibernate 6, the ResultTransformer
was the default option for transforming a query result set.
However, since 5.2, the setResultTransformer
method of the Hibernate Query
interface was deprecated even if no alternative was provided at the time. The reason why this method and its associated ResultTransformer
interface were deprecated was that the ResultTransformer
interface was not a functional interface.
A functional interface provides a single abstract method and can be used when defining a lambda expression. For this reason, the legacy ResultTransformer
interface was split into two interfaces TupleTransformer
and ResultListTransformer
, as illustrated in the following diagram:
Hibernate TupleTransformer
The TupleTransformer
defines the transformTuple
method, as follows:
@Incubating @FunctionalInterface public interface TupleTransformer<T> { /** * Tuples are the elements making up each "row" of the query result. * The contract here is to transform these elements into the final * row shape. * * @param tuple The result elements * @param aliases The result aliases ("parallel" array to tuple) * * @return The transformed row. */ T transformTuple(Object[] tuple, String[] aliases); }
The transformTuple
method allows you to transform the default Object[]
array projection resulting from the JDBC ResultSet
after consuming a given record.
How to use the Hibernate TupleTransformer
For instance, let’s say we have the following Post
entity:
@Entity(name = "Post") @Table(name = "post") public class Post { @Id private Long id; private String title; @Column(name = "created_on") private LocalDateTime createdOn; @Column(name = "created_by") private String createdBy; @Column(name = "updated_on") private LocalDateTime updatedOn; @Column(name = "updated_by") private String updatedBy; @Version private Integer version; }
And we want to execute the following JPQL query, which fetches a custom projection:
select p.id, p.title, p.createdOn, p.createdBy, p.updatedOn, p.updatedBy from Post p order by p.id
By default, when executing the JPQL query above, the project records are going to be wrapped in an Object[]
array:
List<Object[]> postRecords = entityManager.createQuery(""" select p.id, p.title, p.createdOn, p.createdBy, p.updatedOn, p.updatedBy from Post p order by p.id """) .getResultList();
However, operating with Object[]
array projections is not developer-friendly, so we want to map the query result on the following Java Record hierarchy:
For this purpose, we are going to use a TupleTransformer
that allows us to map the default Object[]
array projection to the PostRecord
object, like this:
List<PostRecord> postRecords = entityManager.createQuery(""" select p.id, p.title, p.createdOn, p.createdBy, p.updatedOn, p.updatedBy from Post p order by p.id """) .unwrap(org.hibernate.query.Query.class) .setTupleTransformer( (tuple, aliases) -> { int i =0; return new PostRecord( longValue(tuple[i++]), stringValue(tuple[i++]), new AuditRecord( localDateTimeValue(tuple[i++]), stringValue(tuple[i++]), localDateTimeValue(tuple[i++]), stringValue(tuple[i++]) ) ); } ) .getResultList();
Cool, right?
If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.
Conclusion
Hibernate 6 provides a lot of new features, like SQM (Semantic Query Model) or support for Window Functions.
The new Hibernate TupleTransformer
should be used to replace the legacy ResultTransformer
usages, as the deprecated ResultTransformer
will surely be removed in a future version of Hibernate.
