agrestio / agrest

Server-side Java REST Framework for easy access to data graphs from various backends
https://agrest.io
Apache License 2.0
80 stars 34 forks source link

NPE in CayenneExpParser for a combination of null and positional parameter #648

Closed andrus closed 11 months ago

andrus commented 11 months ago

This very specific expression throws an NPE. No error occurs if I change any of the clauses, or repace positional parameter with a constant.

CayenneExpParser parser = ..

Exp agExp = Exp.parse("a = null or a.b = $b").positionalParams("B");
Expression e = parser.parse(agExp);
java.lang.NullPointerException: Cannot invoke "io.agrest.exp.parser.Node.jjtAccept(io.agrest.exp.parser.AgExpressionParserVisitor, Object)" 
because the return value of "io.agrest.exp.parser.SimpleNode.jjtGetChild(int)" is null

    at io.agrest.cayenne.exp.CayenneExpressionVisitor.process(CayenneExpressionVisitor.java:296)
    at io.agrest.cayenne.exp.CayenneExpressionVisitor.visit(CayenneExpressionVisitor.java:48)
    at io.agrest.cayenne.exp.CayenneExpressionVisitor.visit(CayenneExpressionVisitor.java:14)
    at io.agrest.exp.parser.ExpEqual.jjtAccept(ExpEqual.java:25)
    at io.agrest.cayenne.exp.CayenneExpressionVisitor.process(CayenneExpressionVisitor.java:296)
    at io.agrest.cayenne.exp.CayenneExpressionVisitor.visit(CayenneExpressionVisitor.java:23)
    at io.agrest.cayenne.exp.CayenneExpressionVisitor.visit(CayenneExpressionVisitor.java:14)
    at io.agrest.exp.parser.ExpOr.jjtAccept(ExpOr.java:28)
    at io.agrest.exp.parser.Node.accept(Node.java:44)
    at io.agrest.cayenne.exp.CayenneExpParser.parse(CayenneExpParser.java:18)
andrus commented 11 months ago

The difference seems to be that for a = null clause, Exp.parse() produces second expression child of "null", while Exp.positionalParams produces ExpScalar of "null". We need to unify the expression semantics, but also address the NPE itself.