{"record":{"id":"37efdef5b3b089fe","repo":"Tencent/APIJSON","slug":"list-join-join-onlist-0-getoriginkey","errorCode":null,"errorMessage":"服务器内部错误，List<Join> 中 Join.onList[0].getOriginKey() = null！","messagePattern":"服务器内部错误，List<Join> 中 Join\\.onList\\[0\\]\\.getOriginKey\\(\\) = null！","errorType":"exception","errorClass":"NullPointerException","httpStatus":500,"severity":"critical","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java","lineNumber":782,"sourceCode":"\t\t\t\t\tLog.i(TAG, \"executeAppJoin  for (Join j : joinList) >> j.isAppJoin() == false >>  continue;\");\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tSQLConfig<T, M, L> cc = join.getCacheConfig(); //这里用config改了getSQL后再还原很麻烦，所以提前给一个config2更好\r\n\t\t\t\tif (cc == null) {\r\n\t\t\t\t\tif (Log.DEBUG) {\r\n\t\t\t\t\t\tthrow new NullPointerException(\"服务器内部错误, executeAppJoin cc == null ! 导致不能缓存 @ APP JOIN 的副表数据！\");\r\n\t\t\t\t\t}\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tSQLConfig<T, M, L> jc = join.getJoinConfig();\r\n\r\n\t\t\t\tList<On> onList = join.getOnList();\r\n\t\t\t\tOn on = onList == null || onList.isEmpty() ? null : onList.get(0);  // APP JOIN 应该有且只有一个 ON 条件\r\n\t\t\t\tString originKey = on == null ? null : on.getOriginKey();\r\n\t\t\t\tif (originKey == null) {\r\n\t\t\t\t\tthrow new NullPointerException(\"服务器内部错误，List<Join> 中 Join.onList[0\" + (on == null ? \"] = null！\" : \".getOriginKey() = null！\"));\r\n\t\t\t\t}\r\n\t\t\t\tString key = on.getKey();\r\n\t\t\t\tif (key == null) {\r\n\t\t\t\t\tthrow new NullPointerException(\"服务器内部错误，List<Join> 中 Join.onList[0\" + (on == null ? \"] = null！\" : \".getKey() = null！\"));\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// 取出 \"id@\": \"@/User/userId\" 中所有 userId 的值\r\n\t\t\t\tList<Object> targetValueList = new ArrayList<>();\r\n\r\n\t\t\t\tfor (int i = 0; i < resultList.size(); i++) {\r\n\t\t\t\t\tM mainTable = resultList.get(i);\r\n\t\t\t\t\tObject targetValue = mainTable == null ? null : mainTable.get(on.getTargetKey());\r\n\r\n\t\t\t\t\tif (targetValue != null && targetValueList.contains(targetValue) == false) {\r\n\t\t\t\t\t\ttargetValueList.add(targetValue);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r","sourceCodeStart":764,"sourceCodeEnd":800,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java#L764-L800","documentation":"Internal NullPointerException from executeAppJoin: the first On of an APP JOIN exists but getOriginKey() returns null. originKey (the \"key@/Table/key\" string) is required to know which vice-table column maps to the main table; without it the APP JOIN data-caching step cannot proceed.","triggerScenarios":"An On object present in onList but constructed without originKey — typically programmatic Join/On creation or a parsing path that set key/targetTableKey but not originKey.","commonSituations":"Custom code extending APIJSON that builds On via setters and skips setOriginKey; migration between versions where the On model changed.","solutions":["Set originKey on the On used for APP JOIN (full \"key@/Target/key\" string).","Prefer letting APIJSON parse the joiner string rather than building On manually.","Align jar versions; report with the request body if input is standard."],"exampleFix":"// before\nOn on = new On(); on.setKey(\"userId\"); on.setTargetKey(\"id\");\n// after\nOn on = new On(); on.setKey(\"userId\"); on.setTargetKey(\"id\"); on.setOriginKey(\"userId@/User/id\");","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"catch (NullPointerException npe) { if (String(npe.getMessage()).contains(\"Join.onList[0].getOriginKey() = null\")) { // rebuild On with full originKey 'key@/Table/key' } }","preventionTips":["Set originKey whenever you set key/targetKey on an On.","Centralize On construction in one factory method that enforces all three fields."],"tags":["apijson","app-join","internal-error","null-pointer"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}