Can Fetch be used as parameter of treat() for downcasting?

Dear hibernate community,

I am trying to use Fetch instead of Join as parameter of treat(), to avoid the problem that the duplicate join is generated by hibernate (as mentioned in How can I do a JOIN FETCH in criteria api). I am using hibernate-core “5.4.5.Final” and Spring Boot “2.1.8.RELEASE”.

Say a fetch is: “Fetch<Object, Object> fetch = root.fetch(“friends”, JoinType.LEFT);”.

If call “criteriaBuilder.treat((SetJoin<?, ?>) fetch, (Class) SpecialDroid.class)”, below exception will be thrown:

java.lang.UnsupportedOperationException: null
at java.util.AbstractCollection.add( ~[na:1.8.0_211]
at org.hibernate.query.criteria.internal.CriteriaBuilderImpl.treat( ~[hibernate-core-5.4.5.Final.jar:5.4.5.Final]
at org.hibernate.query.criteria.internal.CriteriaBuilderImpl.treat( ~[hibernate-core-5.4.5.Final.jar:5.4.5.Final]
at com.open_care.template_app.ignite_h2.controller.JPAQueryController.getFieldPredicates( ~[main/:na]
at com.open_care.template_app.ignite_h2.controller.JPAQueryController.getAllEmployeesFromRepository( ~[main/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_211]
at sun.reflect.NativeMethodAccessorImpl.invoke( ~[na:1.8.0_211]
at sun.reflect.DelegatingMethodAccessorImpl.invoke( ~[na:1.8.0_211]
at java.lang.reflect.Method.invoke( ~[na:1.8.0_211]
at ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]

If call “criteriaBuilder.treat((Path) fetch, (Class) SpecialDroid.class)”, later entityManager.createQuery() will report error:

org.hibernate.hql.internal.ast.QuerySyntaxException: Invalid path: ‘generatedAlias1.secondaryFunction’ [select distinct human from com.open_care.template_app.ignite_h2.model.Human as human left join fetch human.friends as generatedAlias0 where treat(generatedAlias1 as com.open_care.template_app.ignite_h2.model.SpecialDroid).secondaryFunction like :param0]

Sounds that if hibernate can replace the ‘generatedAlias1’ in above query string with ‘generatedAlias0’, the problem can be solved.


I have the same problem and I did not find a solution in the Criteria API.

Looking at the source of the CriteriaBuilderImpl class, all “treat” methods for “Join” object go through a common method that add the “treat” object to the “Joins” set of the parent of the “Join” object :

final Set<Join<X, ?>> joins = join.getParent().getJoins();
final K treatAs = f.apply( join, type );
joins.add( treatAs );
return treatAs;

But the fetchs objects are stored in another set. So I do a similar processing for my fetch that need downcasting and that works !!!

JoinImplementor<X, T> join = (JoinImplementor<X, T>) fetch;
Set<Fetch<X, ?>> fetches = join.getParent().getFetches();
JoinImplementor<X, T> treatAs = join.treatAs(type);
fetches.add( treatAs );

I hope this can help…