jpaspring-data-jpajpa-criteriahibernate-6.x

JPA CriteriaQuery MultiSelect failing on LEFT Join when using class based DTO. Is there someway to fix this?


With Reference to the Criteria Query API doc

CriteriaQuery multiselect(Selection<?>... selections)

If the type of the criteria query is CriteriaQuery for some user-defined class X (i.e., a criteria query object created by passing a X class argument to the createQuery method), the arguments to the multiselect method will be passed to the X constructor and an instance of type X will be returned for each row.

I have my statements some thing like below -

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Xcain4> query = cb.createQuery(ProductWrapper.class);
Root<TableA> root = query.from(TableA.class);
Join<TableA, TableB> TableBJoin = root.join("tabBList", JoinType.INNER);

Any my multiselect is -

query.multiselect(root.get("col11"), tableBJoin.get("col21"))

When I execute the query it working fine.. I am able to get list of ProductWrapper's.

But when I change the Join type to LEFT

Join<TableA, TableB> TableBJoin = root.join("tabBList", JoinType.LEFT);

I am facing below error -

2022-08-04 03:51:41.013 ERROR 31772 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.QueryException: could not instantiate class [com.exp.reports.dtos.ProductWrapper] from tuple; nested exception is java.lang.IllegalArgumentException: org.hibernate.QueryException: could not instantiate class [com.exp.reports.dtos.ProductWrapper from tuple] with root cause

I think, this is because few values for Col21 of TableB will be null when using LEFT Join. So for the ProductWrapper class I added a single args constructor -> public ProductWrapper(String col11) {...} ;. But this did not solve the issue.

I can switch to Tuple based return type which is working fine with Outer Join also, but I have to write the Tuple to DTO convertor. And as a preference, I want to use the class based approach over Tuple. Does anyone have any suggestion how to solve this without switching to tuple.

I am using SB & spring-boot-starter-data-jpa:2.7.0

I have gone through this reference, but the author has used Tuple in LEFT join case and like I have said, i tried with Tuple and it works. If any one has come across any reference where Class based DTO is used with LEFT/RIGHT joins, plz share.


Solution

  • The error message was not clear and hence it was not easy to find the cause.
    As left join will lead to having null's in some column values, hibernate was not able to map null value to the pojo. Reason being there were primitive in the pojo corresponding to the resultset null values.

    ProductWrapper {
    long filed1;
    }
    

    Changed it to -

    ProductWrapper {
    Long filed1;
    }
    

    And it's working blaze.