magic npe in hibernate

2019-07-04 19:30发布

问题:

When I write

Session session = sessionFactory.getCurrentSession();
List<Candidate> candidates = (List<Candidate>) session.createQuery(
        "select Candidate from Candidate as candidate  left outer join"
        + " candidate.skills as skill    where skill.id =" + 1).list();

I have npe at second line

if I write

Session session = sessionFactory.getCurrentSession();
List<Candidate> candidates = (List<Candidate>) session.createSQLQuery(
        "select candidate.* from candidate inner join candidate_skill"
        + " on candidate.id = candidate_skill.candidate_id"
        + " inner join skill on candidate_skill.skill_id = skill.id"
        + " where skill.id = 1").list();

I have good result

why I have NPE in first example?

SEVERE: Servlet.service() for servlet [appServlet] in context with path [/ui] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause java.lang.NullPointerException at org.hibernate.dialect.function.SQLFunctionRegistry.findSQLFunction(SQLFunctionRegistry.java:41)

回答1:

Remove select Candidate from first query (do you have a field Candidate in Candidate entity)? HQL syntax for full entity select is from <mapped entity>....


About your question:

How magic NPE happens: (...After a bit of debugging or HQL parser)
HQL parser - during AST building - look for a property-reference called Candidate and doesn't find it so try to resolve as a ClassName or a function (look in org.hibernate.hql.internal.ast.util.LiteralProcessor.processConstant() function); Candidate IS a classname and parser threat it as a discriminator value (for entity subclassing) returning null.
After that parser, during translation of select's explicit list find Candidate with value null and try to resolve as a function because null is not a valid dataType (entity, primitive or other valid datatatype) so try to resolve them as a function; value null us used as parameter for function SQLFunctionRegistry.findSQLFunction() which as this body:

public SQLFunction findSQLFunction(String functionName) {
        return sfi.getSqlFunctionRegistry().findSQLFunction( functionName.toLowerCase() );
    }

and functionName.toLowerCase() cause the NPE.