{"record":{"id":"58d92d02a9bf76f0","repo":"Tencent/APIJSON","slug":"value-value-string","errorCode":null,"errorMessage":"{}/{}:value 中 value 必须为函数String！","messagePattern":"(.+?)/(.+?):value 中 value 必须为函数String！","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java","lineNumber":540,"sourceCode":"//\t\t\t\t\t\tLog.d(TAG, \"onParse  isTable(table) == false >> return true;\");\n//\t\t\t\t\t\treturn true;//舍去，对Table无影响\n//\t\t\t\t\t}\n//\t\t\t\t}\n\n\t\t\t\t// 直接替换原来的 key@: path 为 key: target\n\t\t\t\tLog.i(TAG, \"onParse    >>  key = replaceKey; value = target;\");\n\t\t\t\tkey = replaceKey;\n\t\t\t\tvalue = target;\n\t\t\t\tLog.d(TAG, \"onParse key = \" + key + \"; value = \" + value);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new IllegalArgumentException(path + \"/\" + key + \":value 中 value 必须为 依赖路径String 或 SQL子查询JSONObject ！\");\n\t\t\t}\n\t\t}\n\n\t\tif (key.endsWith(\"()\")) {\n\t\t\tif (value instanceof String == false) {\n\t\t\t\tthrow new IllegalArgumentException(path + \"/\" + key + \":value 中 value 必须为函数String！\");\n\t\t\t}\n\n\t\t\tString k = key.substring(0, key.length() - 2);\n\n\t\t\tString type; //远程函数比较少用，一般一个Table:{}内用到也就一两个，所以这里用 \"-\",\"0\",\"+\" 更直观，转用 -1,0,1 对性能提升不大。\n\t\t\tboolean isMinus = k.endsWith(\"-\");\n            boolean isPlus = isMinus == false && k.endsWith(\"+\");\n\t\t\tif (isMinus) { //不能封装到functionMap后批量执行，否则会导致非Table内的 key-():function() 在onChildParse后执行！\n\t\t\t\ttype = \"-\";\n\t\t\t\tk = k.substring(0, k.length() - 1);\n\t\t\t}\n\t\t\telse if (isPlus) {\n\t\t\t\ttype = \"+\";\n\t\t\t\tk = k.substring(0, k.length() - 1);\n\t\t\t}\n\t\t\telse {\n\t\t\t\ttype = \"0\";\n\t\t\t}","sourceCodeStart":522,"sourceCodeEnd":558,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java#L522-L558","documentation":"Any key ending in '()' designates a remote function call and its value must be a String in the form function(key0,key1,...). This IllegalArgumentException fires when the value is not a String — e.g. a JSONObject, JSONArray, number or boolean.","triggerScenarios":"\"name()\": { \"fun\": \"arg\" } or \"name()\": 123. Any 'key()' entry whose value fails instanceof String, including 'key-()' / 'key+()' variants since the check runs after the suffix marker is stripped.","commonSituations":"Client builds the function call as structured JSON instead of a string; copy-paste replaces the quotes; confusion between 'key@' object form and 'key()' string form.","solutions":["Provide the value as a String: \"key()\": \"functionName(argKey)\".","Keep arguments as request keys referenced inside the parentheses, not as nested JSON."],"exampleFix":"// before\n\"tagList()\": { \"getTags\": \"id\" }\n// after\n\"tagList()\": \"getTags(id)\"","handlingStrategy":"type-guard","validationCode":"for (String k : request.keySet()) {\n  String base = k.endsWith(\"()\") ? k : (k.endsWith(\"-()\") || k.endsWith(\"+()\")) ? k.substring(0, k.length() - 3) + \"()\" : null;\n  if (base != null && !(request.get(k) instanceof String)) throw new IllegalArgumentException(k + \" must map to a function String\");\n}","typeGuard":"function isFunctionStringValue(key: string, v: unknown): boolean {\n  return !/^(.*[-+])?\\(\\)$/.test(key) || typeof v === 'string';\n}","tryCatchPattern":null,"preventionTips":["Always write 'key()': \"fn(argKey)\" — value is a String.","Don't build function calls as nested JSON objects.","Remember 'key-()' / 'key+()' variants carry the same String requirement."],"tags":["apijson","remote-function","key-function","validation","request-syntax"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}