Why you should use the Hibernate ResultTransformer to customize result set mappings

(Last Updated On: January 4, 2018)


JPA queries allow you to fetch either entities or DTO projections. However, sometimes you want a combined result set as illustrated in this Hibernate forum question.

Domain Model

Assuming you have the following entities:

The relationship between the two entities is not materialized in a @ManyToOne association. However, both entities share a locale attribute which we can use to form a join between the two.

Returning an entity in a DTO projection

As I explained before, DTO projections are suitable for read-only transactions and fetching data that is not meant to be modified.

However, there might be use cases when you want to select an entity inside your DTO projection. Therefore, considering we have the following DTO projection:

public class PersonAndCountryDTO{

    private final Person person;

    private final String country;

    public PersonAndCountryDTO(
        Person person, 
        String country) {
        this.person = person;
        this.country = country;

    public Person getPerson() {
        return person;

    public String getCountry() {
        return country;

When you execute a JPQL query like this one:

List<PersonAndCountryDTO> personAndAddressDTOs = entityManager.createQuery(
    "select new " +
    "   com.vladmihalcea.book.hpjp.hibernate.query.dto.PersonAndCountryDTO(" +
    "       p, " +
    "       c.name" +
    "   ) " +
    "from Person p " +
    "join Country c on p.locale = c.locale " +
    "order by p.id", PersonAndCountryDTO.class)

Hibernate generates the following SQL queries:

SELECT p.id AS col_0_0_,
       c.name AS col_1_0_
FROM   Person p
       Country c 
       ( p.locale = c.locale )

SELECT p.id AS id1_1_0_,
       p.locale AS locale2_1_0_,
       p.name AS name3_1_0_
FROM   Person p
WHERE  p.id = 3

SELECT p.id AS id1_1_0_,
       p.locale AS locale2_1_0_,
       p.name AS name3_1_0_
FROM   Person p
WHERE  p.id = 4

The Hibernate 5.2 implementation of the DTO projection cannot materialize the DTO projection from the ResultSet without executing a secondary query. However, this is very bad to performance since it can lead to N+1 query issues.

This HQL limitation has been discussed, and Hibernate 6.0 new SQM parser might address this issue, so stay tuned!


However, you are not limited to using JPA alone. Hibernate offers many enhancements that have no direct equivalent in the standard. One of these enhancements is the ResultTransformer mechanism which allows you to customize the ResultSet any way you like.

List<PersonAndCountryDTO> personAndAddressDTOs = entityManager
    "select p, c.name " +
    "from Person p " +
    "join Country c on p.locale = c.locale " +
    "order by p.id")
.unwrap( org.hibernate.query.Query.class )
    new ResultTransformer() {
        public Object transformTuple(
            Object[] tuple, 
            String[] aliases) {
            return new PersonAndCountryDTO(
                (Person) tuple[0],
                (String) tuple[1]

        public List transformList(List collection) {
            return collection;

There are two things to consider for this query:

  1. The unwrap method is used to cast the JPA javax.persistence.Query to the Hibernate-specific org.hibernate.query.Query so that we gain access to the setResultTransformer method.
  2. The ResultTransformer comes with a legacy definition which is not following the Functional Interface syntax. Hence, we cannot use a lambda in this example. Hibernate 6.0 aims to overcome this issue, so that’s why the Hibernate ORM 5.2 ResultTransformer is deprecated. Nevertheless, an alternative will be provided, so the concept we are discussing in this article is going to stand still even in Hibernate 6.

When running the aforementioned Hibernate ResultTransformer query, Hibernate generates the following output:

SELECT p.id AS col_0_0_,
       c.name AS col_1_0_,
       p.id AS id1_1_,
       p.locale AS locale2_1_,
       p.name AS name3_1_
FROM   Person p
       Country c 
       ( p.locale = c.locale )

Way much better!

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


While the JPA NEW select clause is fine for trivial DTO projections, the ResultTransformer it allows you to customize the result set any way you like. In the particular use case we tested in this article, the ResultTransformer is also much more efficient as well, generating a single SQL query instead of N+1 ones.

Subscribe to our Newsletter

* indicates required
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. 
Get the most out of your persistence layer!


13 thoughts on “Why you should use the Hibernate ResultTransformer to customize result set mappings

  1. If the person has a list of countries, like “private List countries;”, how do you suggest to get the result?

    I know that an approach could be: In the @Overridden method “transformTuple(…)” for every row, doing a second query to get all countries. Do you know a better approach?

      1. Sorry Vlad but I couldn’t extract how I could map a list/collection field without another query from your answer. Could you provide an example or explain how one could proceed to query for a resultList of PersonAndCountry if country is a List instead of single String ?

      2. I don’t understand your question. More, this is better asked on StackOverflow while providing more context.

      3. Radu asked how would you proceed if Person had a list of countries. I have this scenario today and can’t find how to perform a query to retrieve (lets assume a person and its list of countries) inside a DTO to transform into a JSON…

        Something like “select p.name as personName, c as countries from Person join p.countries c where p.age >= 18” where Person is a huge entity with lots of attributes and Person.countries is a List of Country.

        There is a way to direct tranform this result set into a list of PersonAndCountryDTO with String personName and List countries with ResultTransformer?

        Sorry for not going to SO but you reply so fast here and there is already a context to go from…

      4. Thank you so much Vlad… found your github, I’m looking for the example as I need to solve my problem as soon as possible. Just added your book to amazon cart too, I’ll buy as soon as I can, love to read books (not digital ones) and yours seems to be awesome…

  2. Thank you! Indeed, the container that I’m using has “Hibernate 5.0.10 Final” and I tried to use “Hibernate 5.2.10 Final” with provided scope. Because of that worked on compile using org.hibernate.query.Query but on runtime does not worked; With “Hibernate 5.0.10” works but there does not exists the method “org.hibernate.Query.getResultList()”; instead could be used “org.hibernate.Query.list()”;

  3. Is very strange but for section with ResultTransformer I get the following error: “Caused by: javax.ejb.EJBTransactionRolledbackException: org.hibernate.internal.QueryImpl cannot be cast to org.hibernate.query.Query”;

    I’ve already verified if there is any mvn dependency conflict.

    1. That’s because you’re using an older version of Hibernate. In 5.2, org.hibernate.Query is deprecated in favor of org.hibernate.query.Query. Try with org.hibernate.Query for older versions.

Leave a Reply

Your email address will not be published. Required fields are marked *