IBM / JSONata4Java

Open Source Java version of JSONata
Apache License 2.0
88 stars 36 forks source link

$match does not match function signature occurs when passing arguments without chaining #291

Open lo-jason opened 7 months ago

lo-jason commented 7 months ago

Sample code showing error Running a simple code where a function is applied to the output of a $match expression

Expressions parse = Expressions.parse("$number($match($.a, /(\\d+)/).groups[0]))");
JsonNode inputNode = new ObjectMapper().readTree("{\"a\" : \"001\"}");

Results in an error from $match

com.api.jsonata4java.expressions.EvaluateException: Argument 1 of function $match does not match function signature
java.lang.RuntimeException: com.api.jsonata4java.expressions.EvaluateException: Argument 1 of function $match does not match function signature
    ...
Caused by: com.api.jsonata4java.expressions.EvaluateRuntimeException: Argument 1 of function $match does not match function signature
    at app//com.api.jsonata4java.expressions.functions.MatchFunction.invoke(MatchFunction.java:99)
    at app//com.api.jsonata4java.expressions.ExpressionsVisitor.visitFunction_call(ExpressionsVisitor.java:1823)
    at 

Native Jsonata Works The same input/output works just in Try Jsonata regardless of jsonata version https://try.jsonata.org/y5CkUaJVY

Issue code The inconsistency appears to be in FunctionUtils where the function is choosing to use the context despite it not being a valid input and having enough arguments already.

if (signature.indexOf("-") >= 0 && prc != null && prc instanceof PathContext) {
    return true;
}

Workaround Swapping around the code so the string is actually used as the context will work "$.a.$match(/(\\d+)/).groups[0] ~> $number()"

wnm3 commented 7 months ago

I spent some time looking into the situation. To resolve it will require adding parameter validation logic similar to the way the jsonata.org signature.js parseSignature method works. It is much more intelligent than the current logic to determine whether the context should be used to fill in missing/optional arguments. Addressing this is going to take significant time that I don't currently have at the moment. A quick and dirty hack would be to add a test of the typeof ctx.getChild(0) to determine if it doesn't match the expected string and undo the useContext to be false if it resolves to a function (the type of the 2nd parameter). I don't like this solution though.

I'm glad you found a workaround. I need to think more about a good way to solve this in our Java environment.