{"record":{"id":"9fb9880b228196f5","repo":"Tencent/APIJSON","slug":"method-function","errorCode":null,"errorMessage":"字符 \" + method + \" 不合法！函数的名称 function 不能为空且必须符合方法命名规范！总体必须为 function(key0,key1,...) 这种单函数格式！\\nfunction必须符合 \" + (isSQLFunction ? \"SQL 函数/SQL 存储过程\" : \"Java 函数\") + \" 命名，key 是用于在 request 内取值的键！","messagePattern":"字符 \" \\+ method \\+ \" 不合法！函数的名称 function 不能为空且必须符合方法命名规范！总体必须为 function\\(key0,key1,\\.\\.\\.\\) 这种单函数格式！\\\\nfunction必须符合 \" \\+ \\(isSQLFunction \\? \"SQL 函数/SQL 存储过程\" : \"Java 函数\"\\) \\+ \" 命名，key 是用于在 request 内取值的键！","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java","lineNumber":599,"sourceCode":"     * @param function\n     * @param request\n     * @param isSQLFunction\n     * @param containRaw\n     * @return\n     * @throws Exception\n     */\n\tpublic static FunctionBean parseFunction(@NotNull String function, @NotNull Map<String, Object> request, boolean isSQLFunction, boolean containRaw) throws Exception {\n\n\t\tint start = function.indexOf(\"(\");\n\t\tint end = function.lastIndexOf(\")\");\n\t\tString method = (start <= 0 || end != function.length() - 1) ? null : function.substring(0, start);\n\n        int dotInd = method == null ? -1 : method.indexOf(\".\");\n        String schema = dotInd < 0 ? null : method.substring(0, dotInd);\n        method = dotInd < 0 ? method : method.substring(dotInd + 1);\n\n        if (StringUtil.isName(method) == false) {\n\t\t\tthrow new IllegalArgumentException(\"字符 \" + method + \" 不合法！函数的名称 function 不能为空且必须符合方法命名规范！\"\n\t\t\t\t\t+ \"总体必须为 function(key0,key1,...) 这种单函数格式！\"\n\t\t\t\t\t+ \"\\nfunction必须符合 \" + (isSQLFunction ? \"SQL 函数/SQL 存储过程\" : \"Java 函数\") + \" 命名，key 是用于在 request 内取值的键！\");\n\t\t}\n        if (isSQLFunction != true && schema != null) { // StringUtil.isNotEmpty(schema, false)) {\n            throw new IllegalArgumentException(\"字符 \" + schema + \" 不合法！远程函数不允许指定类名！\"\n                    + \"且必须为 function(key0,key1,...) 这种单函数格式！\"\n                    + \"\\nfunction必须符合 \" + (isSQLFunction ? \"SQL 函数/SQL 存储过程\" : \"Java 函数\") + \" 命名，key 是用于在 request 内取值的键！\");\n        }\n        if (schema != null) { // StringUtil.isName(schema) == false) {\n\t\t\tschema = extractSchema(schema, null);\n        }\n\n\t\tString[] keys = StringUtil.split(function.substring(start + 1, end));\n\t\tint length = keys == null ? 0 : keys.length;\n\n\t\tClass<?>[] types;\n\t\tObject[] values;\n","sourceCodeStart":581,"sourceCodeEnd":617,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java#L581-L617","documentation":"parseFunction validates the grammar of a function expression: it must be a single call of the form function(key0,key1,...) where the method name (text before '(' and after an optional schema prefix) passes StringUtil.isName — Java-style identifier rules. If the parentheses are misplaced, the name is empty, or it contains illegal characters, IllegalArgumentException is thrown, with the message adapting to whether a SQL function or Java remote function was expected.","triggerScenarios":"Passing \"sum(id\" (missing ')'), \"(a,b)\" (empty name), \"my-func(a)\" or \"my func(a)\" (illegal characters), \"function() extra\", or a plain string \"abc\" without parentheses — note start<=0 also rejects bare names, since the '(' at index >0 is required and ')' must be last.","commonSituations":"Client builds function strings via concatenation and produces spaces or truncation; user-supplied input interpolated directly into @column/@having; switching a plain column name to a function call and forgetting the parentheses; schema prefix issues for SQL functions.","solutions":["Rewrite the expression as name(arg0,arg1,...) with a valid identifier name and no spaces.","Validate user-built expressions with StringUtil.isName on the name part and a parentheses check before sending.","For plain column references, drop the function syntax entirely (just \"id\").","For schema-qualified SQL functions use schema.func(key) and remember remote (Java) functions forbid schema prefixes."],"exampleFix":"// before\n{\"User\":{\"@column\":\"mask Phone(phone)\"}} // space in name\n\n// after\n{\"User\":{\"@column\":\"maskPhone(phone)\"}}","handlingStrategy":"validation","validationCode":"int start = function.indexOf('(');\nint end = function.lastIndexOf(')');\nString name = (start > 0 && end == function.length() - 1) ? function.substring(0, start) : null;\nint dot = name == null ? -1 : name.indexOf('.');\nif (dot >= 0) name = name.substring(dot + 1);\nboolean valid = name != null && StringUtil.isName(name) && !function.contains(\" \");","typeGuard":"public static boolean isValidFunctionExpr(String function) {\n    if (StringUtil.isEmpty(function, true)) return false;\n    int s = function.indexOf('('), e = function.lastIndexOf(')');\n    if (s <= 0 || e != function.length() - 1) return false;\n    String name = function.substring(0, s);\n    int d = name.indexOf('.');\n    if (d >= 0) name = name.substring(d + 1);\n    return StringUtil.isName(name) && !function.matches(\".*\\\\s.*\");\n}","tryCatchPattern":"try { parser.invoke(function, current); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"不合法\")) { /* reject/repair expression before retry */ } throw e; }","preventionTips":["Build function expressions from validated constants, never raw user input.","Reject any expression containing whitespace before sending.","Require the exact single-function form name(key0,key1,...); no nested or multiple calls."],"tags":["apijson","function-parsing","syntax","validation"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}