{"record":{"id":"226147a5a267ae64","repo":"Tencent/APIJSON","slug":"function-getfunction-fb-get","errorCode":null,"errorMessage":"字符 \" + function + \" 对应的远程函数 \" + getFunction(fb.getMethod(), fb.getKeys()) + \" 不在后端 \" + parser.getClass().getName() + \" 内，也不在父类中！如果需要则先新增对应方法！\\n请检查函数名和参数数量是否与已定义的函数一致！\\n且必须为 function(key0,key1,...) 这种单函数格式！\\nfunction 必须符合 Java 函数命名，key 是用于在 curObj 内取值的键！\\n调用时不要有空格！\" + (Log.DEBUG ? e.getMessage() : \"\")","messagePattern":"字符 \" \\+ function \\+ \" 对应的远程函数 \" \\+ getFunction\\(fb\\.getMethod\\(\\), fb\\.getKeys\\(\\)\\) \\+ \" 不在后端 \" \\+ parser\\.getClass\\(\\)\\.getName\\(\\) \\+ \" 内，也不在父类中！如果需要则先新增对应方法！\\\\n请检查函数名和参数数量是否与已定义的函数一致！\\\\n且必须为 function\\(key0,key1,\\.\\.\\.\\) 这种单函数格式！\\\\nfunction 必须符合 Java 函数命名，key 是用于在 curObj 内取值的键！\\\\n调用时不要有空格！\" \\+ \\(Log\\.DEBUG \\? e\\.getMessage\\(\\) : \"\"\\)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java","lineNumber":446,"sourceCode":"\t\tif (parser.getVersion() < version) {\n\t\t\tthrow new UnsupportedOperationException(\"不允许 version = \" + parser.getVersion() + \" 的请求调用远程函数 \" + fb.getMethod() + \" ! 必须满足 version >= \" + version + \" !\");\n\t\t}\n\t\tString tag = (String) row.get(\"tag\");  // TODO 改为 tags，类似 methods 支持多个 tag。或者干脆不要？因为目前非开放请求全都只能后端指定\n\t\tif (tag != null && tag.equals(parser.getTag()) == false) {\n\t\t\tthrow new UnsupportedOperationException(\"不允许 tag = \" + parser.getTag() + \" 的请求调用远程函数 \" + fb.getMethod() + \" ! 必须满足 tag = \" + tag + \" !\");\n\t\t}\n\t\tString[] methods = StringUtil.split((String) row.get(\"methods\"));\n\t\tList<String> ml = methods == null || methods.length <= 0 ? null : Arrays.asList(methods);\n\t\tif (ml != null && ml.contains(parser.getMethod().toString()) == false) {\n\t\t\tthrow new UnsupportedOperationException(\"不允许 method = \" + parser.getMethod() + \" 的请求调用远程函数 \" + fb.getMethod() + \" ! 必须满足 method 在 \" + Arrays.toString(methods) + \"内 !\");\n\t\t}\n\n\t\ttry {\n            return invoke(parser, fb.getMethod(), fb.getTypes(), fb.getValues(), (String) row.get(\"returnType\"), current, SCRIPT_EXECUTOR_MAP.get(lang));\n\t\t}\n        catch (Exception e) {\n\t\t\tif (e instanceof NoSuchMethodException) {\n\t\t\t\tthrow new IllegalArgumentException(\"字符 \" + function + \" 对应的远程函数 \" + getFunction(fb.getMethod(), fb.getKeys())\n                        + \" 不在后端 \" + parser.getClass().getName() + \" 内，也不在父类中！如果需要则先新增对应方法！\"\n\t\t\t\t\t\t+ \"\\n请检查函数名和参数数量是否与已定义的函数一致！\"\n\t\t\t\t\t\t+ \"\\n且必须为 function(key0,key1,...) 这种单函数格式！\"\n\t\t\t\t\t\t+ \"\\nfunction 必须符合 Java 函数命名，key 是用于在 curObj 内取值的键！\"\n\t\t\t\t\t\t+ \"\\n调用时不要有空格！\" + (Log.DEBUG ? e.getMessage() : \"\"));\n\t\t\t}\n\t\t\tif (e instanceof InvocationTargetException) {\n\t\t\t\tThrowable te = ((InvocationTargetException) e).getTargetException();\n\t\t\t\tif (StringUtil.isEmpty(te.getMessage(), true) == false) { //到处把函数声明throws Exception改成throws Throwable挺麻烦\n\t\t\t\t\tthrow te instanceof Exception ? (Exception) te : new Exception(te.getMessage());\n\t\t\t\t}\n\t\t\t\tthrow new IllegalArgumentException(\"字符 \" + function + \" 对应的远程函数传参类型错误！\"\n\t\t\t\t\t\t+ \"\\n请检查 key:value 中value的类型是否满足已定义的函数 \" + getFunction(fb.getMethod(), fb.getKeys()) + \" 的要求！\"\n\t\t\t\t\t\t+ (Log.DEBUG ? e.getMessage() : \"\"));\n\t\t\t}\n\t\t\tthrow e;\n\t\t}\n","sourceCodeStart":428,"sourceCodeEnd":464,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java#L428-L464","documentation":"All Function-table gates passed, so the parser reflectively invokes the method on the parser object (your APIJSONFunctionParser subclass), but java.lang.reflect reports NoSuchMethodException: no method with that name and parameter count/types exists on the parser class or its superclasses. The message embeds the expected signature and reminder that arguments must be key references in function(key0,key1,...) form.","triggerScenarios":"Function table registers 'maskPhone' but the backend APIJSONFunctionParser defines maskPhone(Long) while the request calls maskPhone(phone) where phone resolves to a String; or the method simply is not implemented yet; or parameter count differs.","commonSituations":"Frontend adds a function call before the backend method exists; refactor renamed a Java method without updating the Function table; argument-count mismatch between the call expression and the Java signature.","solutions":["Implement (or fix) the public method in your APIJSONFunctionParser subclass with exactly the name and parameter types the calls pass.","Match parameter count: function(key0,key1) must map to a two-argument method.","If the method exists in another class, move it into the parser class hierarchy or add a delegating method.","Enable Log.DEBUG temporarily to append the underlying NoSuchMethodException detail to the message."],"exampleFix":"// before: request uses maskPhone(phone) but parser lacks it\n\n// after\nclass APIJSONFunctionParser extends AbstractFunctionParser<Long> {\n    public Object maskPhone(String phone) { return phone.replaceAll(\"(\\\\d{3})\\\\d{4}(\\\\d{4})\", \"$1****$2\"); }\n}","handlingStrategy":"try-catch","validationCode":"Method m = null;\nfor (Method c : parser.getClass().getMethods()) {\n    if (c.getName().equals(fb.getMethod()) && c.getParameterCount() == fb.getKeys().length) { m = c; break; }\n}\nif (m == null) { /* method missing: implement it before deploying the client change */ }","typeGuard":null,"tryCatchPattern":"try { return parser.invoke(fn, current); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"不在后端\")) { throw new UnsupportedOperationException(\"Remote function not implemented backend-side: \" + fn, e); } throw e; }","preventionTips":["Deploy backend function implementations before releasing clients that call them.","Keep Function-table rows and Java methods in one PR/review unit.","Add unit tests that reflectively assert every registered Function row has a matching method on the parser class."],"tags":["apijson","remote-function","reflection","nosuchmethod"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}