{"record":{"id":"4a3ba045b9cbbd3f","repo":"Tencent/APIJSON","slug":"version-parser-getversion","errorCode":null,"errorMessage":"不允许 version = \" + parser.getVersion() + \" 的请求调用远程函数 \" + fb.getMethod() + \" ! 必须满足 version >= \" + version + \" !","messagePattern":"不允许 version = \" \\+ parser\\.getVersion\\(\\) \\+ \" 的请求调用远程函数 \" \\+ fb\\.getMethod\\(\\) \\+ \" ! 必须满足 version >= \" \\+ version \\+ \" !","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java","lineNumber":429,"sourceCode":"\t\tif (row == null) {\n\t\t\tthrow new UnsupportedOperationException(\"不允许调用远程函数 \" + fb.getMethod() + \" !\");\n\t\t}\n\n        String language = (String) row.get(\"language\");\n        String lang = \"java\".equalsIgnoreCase(language) ? null : language;\n\n        if (ENABLE_SCRIPT_FUNCTION == false && lang != null) {\n            throw new UnsupportedOperationException(\"language = \" + language + \" 不合法！AbstractFunctionParser.ENABLE_SCRIPT_FUNCTION\" +\n                    \" == false 时不支持远程函数中的脚本形式！如需支持则设置 AbstractFunctionParser.ENABLE_SCRIPT_FUNCTION = true ！\");\n        }\n\n\t\tif (lang != null && SCRIPT_EXECUTOR_MAP.get(lang) == null) {\n\t\t\tthrow new ClassNotFoundException(\"找不到脚本语言 \" + lang + \" 对应的执行引擎！请先依赖相关库并在后端 APIJSONFunctionParser<T, M, L> 中注册！\");\n\t\t}\n\n\t\tint version = row.get(\"version\") != null ? Integer.parseInt(row.get(\"version\").toString()) : 0;\n\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() + \" 内，也不在父类中！如果需要则先新增对应方法！\"","sourceCodeStart":411,"sourceCodeEnd":447,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java#L411-L447","documentation":"Function rows carry a minimum-version field; the parser compares parser.getVersion() (usually derived from the request's @version or parser default) against it and throws UnsupportedOperationException when the request version is lower. This lets operators stage breaking function changes behind a version gate.","triggerScenarios":"Function table row sets version=3 while the request/parser runs with version < 3 (e.g. request lacks @version so the parser default, often 1 or 0, applies).","commonSituations":"A function was upgraded and its row's version bumped, but existing clients still send the old default version; new environment imported Function rows with version values but clients never set @version.","solutions":["Send a higher version in the request (e.g. add \"@version\": 3) or set the parser's default version accordingly.","Or lower/reset the version column of that Function row if all clients should use it.","Keep client @version in sync with the Function table's minimum versions as part of release notes."],"exampleFix":"// before\n{\"User\":{\"@column\":\"maskPhone(phone)\"}} // parser version < row version\n\n// after\n{\"@version\":3, \"User\":{\"@column\":\"maskPhone(phone)\"}}","handlingStrategy":"validation","validationCode":"int rowMinVersion = row.get(\"version\") != null ? Integer.parseInt(row.get(\"version\").toString()) : 0;\nif (parser.getVersion() < rowMinVersion) {\n    // bump request @version or lower the row's version requirement\n}","typeGuard":null,"tryCatchPattern":"try { parser.invoke(fn, current); } catch (UnsupportedOperationException e) { if (e.getMessage().contains(\"version\")) { /* retry with raised @version */ } throw e; }","preventionTips":["Always send an explicit @version in requests that use functions.","Track Function-table minimum versions in client release notes.","When bumping a row's version, announce the required client version."],"tags":["apijson","remote-function","versioning","configuration"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}