{"record":{"id":"0c784f44a2519042","repo":"Tencent/APIJSON","slug":"join-e-getkey-tablekey-value-value","errorCode":null,"errorMessage":"join:'${e.getKey()}' 对应的 ${tableKey}:value 中 value 类型不合法！必须是 {} 这种 Map<String, Object> 格式！${e2.getMessage()}","messagePattern":"join:'(.+?)' 对应的 (.+?):value 中 value 类型不合法！必须是 (.+?) 这种 Map<String, Object> 格式！(.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractParser.java","lineNumber":1662,"sourceCode":"\t\t\tString alias = entry.getValue(); // owner\n\t\t\tif (StringUtil.isNotEmpty(alias, true) && StringUtil.isName(alias) == false) {\n\t\t\t\tthrow new IllegalArgumentException(apijson.JSONRequest.KEY_JOIN + \":value 中 value 的 alias 值 \" + alias + \" 不合法！\"\n\t\t\t\t\t\t+ \"必须为 &/Table0,</Table1/key1,@/Table1:alias2/key2,... 或 { '&/Table0':{}, '</Table1/key1':{},... } 这种格式！\"\n\t\t\t\t\t\t+ \"且 Table:alias 的 alias 必须满足英文单词变量名格式！\");\n\t\t\t}\n\n\t\t\t// 取出Table对应的JSONObject，及内部引用赋值 key:value\n\t\t\tM tableObj;\n\t\t\tM parentPathObj;\t// 保留\n\t\t\ttry {\n\t\t\t\tparentPathObj = arrKey == null ? request : JSON.get(request, arrKey);\t// 保留\n\t\t\t\ttableObj = parentPathObj == null ? null : JSON.get(parentPathObj, tableKey);\n\t\t\t\tif (tableObj == null) {\n\t\t\t\t\tthrow new NullPointerException(\"tableObj == null\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Exception e2) {\n\t\t\t\tthrow new IllegalArgumentException(apijson.JSONRequest.KEY_JOIN + \":'\" + e.getKey() + \"' 对应的 \" + tableKey + \":value 中 value 类型不合法！\" +\n          \t\t\t\"必须是 {} 这种 Map<String, Object> 格式！\" + e2.getMessage());\n\t\t\t}\n\n\t\t\tif (arrKey != null) {\n\t\t\t\tif (parentPathObj.get(apijson.JSONRequest.KEY_JOIN) != null) {\n\t\t\t\t\tthrow new IllegalArgumentException(apijson.JSONRequest.KEY_JOIN + \":'\" + e.getKey() + \"' 对应的 \" + arrKey + \":{ join: value } 中 value 不合法！\" +\n\t\t\t\t\t\t\t\"@ APP JOIN 最多允许跨 1 层，只能是子数组，且数组对象中不能有 join: value 键值对！\");\n\t\t\t\t}\n\n\t\t\t\tInteger subPage = getInteger(parentPathObj, apijson.JSONRequest.KEY_PAGE);\n\t\t\t\tif (subPage != null && subPage != 0) {\n\t\t\t\t\tthrow new IllegalArgumentException(apijson.JSONRequest.KEY_JOIN + \":'\" + e.getKey() + \"' 对应的 \" + arrKey + \":{ page: value } 中 value 不合法！\" +\n\t\t\t\t\t\t\t\"@ APP JOIN 最多允许跨 1 层，只能是子数组，且数组对象中 page 值只能为 null 或 0 ！\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tboolean isAppJoin = \"@\".equals(joinType);\n","sourceCodeStart":1644,"sourceCodeEnd":1680,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java#L1644-L1680","documentation":"After validating path grammar, the parser fetches the joined table's object from the request (optionally through arrKey) and requires it to be a Map. Lookup failure (missing object) or wrong type is caught and rethrown as IllegalArgumentException including the inner exception message — typically 'tableObj == null' when the referenced table object is absent from the request.","triggerScenarios":"\"@join\":\"&/User/id\" in a request that contains no \"User\":{...} object at that location; or \"User\": [...] / string instead of an object; or arrKey points to an array object that does not contain tableKey.","commonSituations":"Typos between join path and the table key; the table object nested at a different level than the path says; reusing a join clause from another request template; sending conditions for the joined table as a query string instead of an object.","solutions":["Add the matching table object at the exact path the join references: {\"@join\":\"&/User/id\", \"User\":{...}}","Ensure the value for that table key is a JSON object {}","Verify arrKey matches: for '@/list[]/User' the request must have list[] containing User:{}","Copy join paths and table keys from one source of truth to avoid drift"],"exampleFix":"// before\n{\"@join\":\"&/User/id\",\"Moment\":{}}\n// after\n{\"@join\":\"&/User/id\",\"User\":{},\"Moment\":{}}","handlingStrategy":"validation","validationCode":"for (String p : joinPaths) {\n  String tableKey = tableSegmentOf(p);\n  if (!(resolve(requestRoot, p) instanceof Map)) throw new IllegalStateException(\"join target object missing: \" + p);\n}","typeGuard":"boolean joinTargetObjectExists(Map<String,Object> root, String arrKey, String tableKey) {\n  Map<?,?> parent = arrKey == null ? root : (Map<?,?>) root.get(arrKey);\n  return parent != null && parent.get(tableKey) instanceof Map;\n}","tryCatchPattern":null,"preventionTips":["Derive join paths and table keys from the same builder constants","Assert every join path resolves to an object in the payload before send","Keep table objects at the exact level the path declares"],"tags":["apijson","join","missing-table","request-format"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}