{"record":{"id":"1628e8c1fbc31ccd","repo":"Tencent/APIJSON","slug":"e-getkey-targettable-targetkey-targettab","errorCode":null,"errorMessage":"${e.getKey()}:'/targetTable/targetKey' 中 targetTable 值 ${targetTable} 不合法！必须满足大写字母开头的表对象英文单词 key 格式！","messagePattern":"(.+?):'/targetTable/targetKey' 中 targetTable 值 (.+?) 不合法！必须满足大写字母开头的表对象英文单词 key 格式！","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractParser.java","lineNumber":1830,"sourceCode":"\t\t\t\t\tthrow new IllegalArgumentException(e.getKey() + \":value 中 value 值 \" + targetPath + \" 不合法！必须为引用赋值的路径 '/targetTable/targetKey' ！\");\n\t\t\t\t}\n\n\t\t\t\t// 取出引用赋值路径 targetPath 对应的 Table 和 key\n\t\t\t\tindex = targetPath.lastIndexOf(\"/\");\n\t\t\t\tString targetKey = index < 0 ? null : targetPath.substring(index + 1);\n\t\t\t\tif (StringUtil.isName(targetKey) == false) {\n\t\t\t\t\tthrow new IllegalArgumentException(e.getKey() + \":'/targetTable/targetKey' 中 targetKey 值 \" + targetKey + \" 不合法！必须满足英文单词变量名格式！\");\n\t\t\t\t}\n\n\t\t\t\ttargetPath = targetPath.substring(0, index);\n\t\t\t\tindex = targetPath.lastIndexOf(\"/\");\n\t\t\t\tString targetTableKey = index < 0 ? targetPath : targetPath.substring(index + 1);\n\n\t\t\t\t// 主表允许别名\n\t\t\t\tapijson.orm.Entry<String, String> targetEntry = Pair.parseEntry(targetTableKey, true);\n\t\t\t\tString targetTable = targetEntry.getKey(); //User\n\t\t\t\tif (StringUtil.isName(targetTable) == false) {\n\t\t\t\t\tthrow new IllegalArgumentException(e.getKey() + \":'/targetTable/targetKey' 中 targetTable 值 \" + targetTable + \" 不合法！必须满足大写字母开头的表对象英文单词 key 格式！\");\n\t\t\t\t}\n\n\t\t\t\tString targetAlias = targetEntry.getValue(); //owner\n\t\t\t\tif (StringUtil.isNotEmpty(targetAlias, true) && StringUtil.isName(targetAlias) == false) {\n\t\t\t\t\tthrow new IllegalArgumentException(e.getKey() + \":'/targetTable:targetAlias/targetKey' 中 targetAlias 值 \" + targetAlias + \" 不合法！必须满足英文单词变量名格式！\");\n\t\t\t\t}\n\n\t\t\t\t//targetTable = targetTableKey;  // 主表允许别名\n\t\t\t\tif (StringUtil.isName(targetTable) == false) {\n\t\t\t\t\tthrow new IllegalArgumentException(e.getKey() + \":'/targetTable/targetKey' 中 targetTable 值 \" + targetTable + \" 不合法！必须满足大写字母开头的表对象英文单词 key 格式！\");\n\t\t\t\t}\n\n\t\t\t\t//对引用的JSONObject添加条件\n\t\t\t\tMap<String, Object> targetObj;\n\t\t\t\ttry {\n\t\t\t\t\ttargetObj = JSON.get(request, targetTableKey);\n\t\t\t\t}\n\t\t\t\tcatch (Exception e2) {","sourceCodeStart":1812,"sourceCodeEnd":1848,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java#L1812-L1848","documentation":"The table segment of a reference path ('/targetTable/targetKey', optionally 'Table:alias') is parsed with Pair.parseEntry and its table part must satisfy StringUtil.isName — an identifier starting with an uppercase letter, as APIJSON table object keys are conventionally uppercase ('User', 'Comment'). This IllegalArgumentException fires for lowercase or malformed table names.","triggerScenarios":"'userId@': '/user/id' (lowercase table), '/0User/id' (starts with digit), '/Us er/id' (space). Note: isName only checks identifier shape; conventionally the library expects uppercase-initial table keys, as the message states.","commonSituations":"Using the physical DB table name (often lowercase) instead of the JSON table-object key; auto-lowercasing keys with a serializer (e.g. Jackson/ Gson lower-case strategies); renaming table objects in the request but not the reference paths.","solutions":["Use the uppercase table object key exactly as it appears in the request: '/User/id' not '/user/id'","If a serializer rewrites keys, disable case transformation for APIJSON requests","Check for stray characters or digits at the start of the table segment"],"exampleFix":"// before\n{ 'join': '</Moment', 'Moment': { 'userId@': '/user/id' } }\n// after\n{ 'join': '</Moment', 'Moment': { 'userId@': '/User/id' } }","handlingStrategy":"validation","validationCode":"const TABLE_RE = /^[A-Z][A-Za-z0-9_]*$/;\nfunction checkRefTables(req) {\n  for (const tbl of Object.values(req)) {\n    if (tbl && typeof tbl === 'object') {\n      for (const [k, v] of Object.entries(tbl)) {\n        if (!k.endsWith('@') || typeof v !== 'string' || !v.startsWith('/')) continue;\n        const t = v.split('/')[1].split(':')[0];\n        if (!TABLE_RE.test(t)) return `${k}: targetTable '${t}' must be an uppercase-initial table key`;\n      }\n    }\n  }\n  return null;\n}","typeGuard":"const isValidTargetTable = (seg) => /^[A-Z][A-Za-z0-9_]*$/.test(seg);","tryCatchPattern":"Catch IllegalArgumentException containing 'targetTable 值'; correct the case of the table key to match the declared object.","preventionTips":["Reference paths use the JSON table-object key (uppercase-initial), not the physical lowercase DB name","Disable key case-munging in serializers used to build APIJSON requests"],"tags":["apijson","join","naming-convention","path-format"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}