Vladimir Sitnikov created CALCITE-7853:
------------------------------------------
Summary: Lambda with no parameters throws NullPointerException
when called through FunctionExpression.getFunction()
Key: CALCITE-7853
URL: https://issues.apache.org/jira/browse/CALCITE-7853
Project: Calcite
Issue Type: Bug
Components: linq4j
Affects Versions: 1.42.0
Reporter: Vladimir Sitnikov
I build a linq4j lambda that takes no parameters, ask for its function with
{{getFunction()}}, and call {{apply()}}. The call throws
{{NullPointerException}} instead of returning the lambda's value. A lambda with
parameters works through the same path (see {{ExpressionTest.testCompile}}).
h3. Reproduction
{code:java}
import org.apache.calcite.linq4j.function.Function0;
import org.apache.calcite.linq4j.tree.Expressions;
String x =
Expressions.<Function0<String>>lambda(Expressions.constant("abc"))
.getFunction()
.apply();
{code}
h3. Expected
{{apply()}} returns {{"abc"}}, the value of the lambda body.
h3. Actual
{noformat}
java.lang.NullPointerException: Cannot read the array length because "args" is
null
at
org.apache.calcite.linq4j.tree.FunctionExpression.lambda$compile$0(FunctionExpression.java:88)
at
org.apache.calcite.linq4j.tree.FunctionExpression.lambda$getFunction$0(FunctionExpression.java:107)
at jdk.proxy3/jdk.proxy3.$Proxy13.apply(Unknown Source)
at
org.apache.calcite.linq4j.test.ExpressionTest.testLambdaWithoutParametersViaGetFunction(ExpressionTest.java:1191)
{noformat}
Reproduced on main at commit 8f27e24a02 with Amazon Corretto 21.0.9. The same
{{getFunction()}} code is in calcite-1.42.0; I did not run the reproduction on
that release.
h3. Analysis
The symptom and reproduction above stand without this section.
{{getFunction()}} wraps the compiled lambda in a {{java.lang.reflect.Proxy}}
whose handler calls {{Invokable.dynamicInvoke(args)}}. The
[InvocationHandler.invoke|https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/reflect/InvocationHandler.html#invoke(java.lang.Object,java.lang.reflect.Method,java.lang.Object%5B%5D)]
contract says {{args}} is {{null}} if the interface method takes no arguments,
and the invokable built by {{compile()}} reads {{args.length}}. Passing an
empty array when {{args}} is {{null}} fixes it.
Found while reviewing CALCITE-7736 ([PR
#5213|https://github.com/apache/calcite/pull/5213]), which carries the same fix
inside the nullness migration; this issue extracts it so it can land on its own.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)