The best way to use the Hibernate TupleTransformer
Are you struggling with performance issues in your Spring, Jakarta EE, or Java EE application?
Imagine having a tool that could automatically detect performance issues in your JPA and Hibernate data access layer long before pushing a problematic change into production!
With the widespread adoption of AI agents generating code in a heartbeat, having such a tool that can watch your back and prevent performance issues during development, long before they affect production systems, can save your company a lot of money and make you a hero!
Hypersistence Optimizer is that tool, and it works with Spring Boot, Spring Framework, Jakarta EE, Java EE, Quarkus, Micronaut, or Play Framework.
So, rather than allowing performance issues to annoy your customers, you are better off preventing those issues using Hypersistence Optimizer and enjoying spending your time on the things that you love!
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.







