When a user does not explicitly register a function on the Dialect selected a NullPointerException is thrown without much reason as to why. I would like to suggest handling this problem more gracefully to notify the user of the mistake.
Consider the following:
{code:title=Animal.java|borderStyle=solid} @Entity @Table( name = "ANIMAL" ) public class Animal { private Long id; private Animal mother; private Animal father; private String name; private Date born; } {code}
{code:title=JPA Criteria Query|borderStyle=solid} CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<HumanPojo> criteria = cb.createQuery( HumanPojo.class ); Root<Human> root = criteria.from( Human.class );
criteria.select( cb.construct( HumanPojo.class, root.get(Human_.id), root.get(Human_.name), cb.function( "convert", String.class, root.get(Human_.born), cb.literal(110)) ) );
em.createQuery( criteria ).getResultList(); {code}
In this scenario I am trying to utilize the CONVERT() function provided by SQL Server 2005+. When the query is executed I am presented with the following stack trace.
{code:title=Stack Trace|borderStyle=solid} java.lang.NullPointerException at org.hibernate.internal.util.ReflectHelper.getConstructor(ReflectHelper.java:309) at org.hibernate.hql.internal.ast.tree.ConstructorNode.resolveConstructor(ConstructorNode.java:174) at org.hibernate.hql.internal.ast.tree.ConstructorNode.prepare(ConstructorNode.java:144) at org.hibernate.hql.internal.ast.HqlSqlWalker.processConstructor(HqlSqlWalker.java:1163) at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectExpr(HqlSqlBaseWalker.java:2354) at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectExprList(HqlSqlBaseWalker.java:2220) at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectClause(HqlSqlBaseWalker.java:1495) at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:583) at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:311) at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:259) at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:262) at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:190) at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:142) at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:115) at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:76) at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:150) at org.hibernate.internal.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:302) at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:240) at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1907) at org.hibernate.jpa.spi.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:531) at org.hibernate.jpa.criteria.CriteriaQueryImpl$1.buildCompiledQuery(CriteriaQueryImpl.java:319) at org.hibernate.jpa.criteria.compile.CriteriaCompiler.compile(CriteriaCompiler.java:130) at org.hibernate.jpa.spi.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:699) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:344) at com.sun.proxy.$Proxy73.createQuery(Unknown Source) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:294) at com.sun.proxy.$Proxy73.createQuery(Unknown Source) {code}
The NPE is caused by an inability of the AST node produced for the select expression to determine a data type. See [SelectExpressionList.java|https://github.com/hibernate/hibernate-orm/blob/ec4f20a5fba79444dbd704f1305f961c339dd7d1/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/SelectExpressionList.java#L31]
Ultimately a null value is placed into the types array of the resolved constructor argument types and causes the NPE inside the ReflectHelper noted in the stack trace above. See [ConstructorNode.java|https://github.com/hibernate/hibernate-orm/blob/ec4f20a5fba79444dbd704f1305f961c339dd7d1/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/ConstructorNode.java#L156]
A couple of proposed solutions * 1) # Add a warning/error when a user attempts to invoke CriteriaBuilder.function() if the function is not defined. * 2) # Throw an exception/warning when a null data type for a constructor argument occurs within ConstructorNode. |
|