Tencent/APIJSON · critical · NullPointerException
服务器内部错误,List<Join> 中 Join.onList[0] = null!
Error message
服务器内部错误,List<Join> 中 Join.onList[0] = null!
What it means
Internal NullPointerException from executeAppJoin: for an @ APP JOIN the executor requires exactly one ON condition, but onList is null/empty (or its first element is null), so on == null and originKey cannot be read. APP JOIN cannot fetch and cache vice-table rows without the ON relation.
Source
Thrown at APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java:782
Log.i(TAG, "executeAppJoin for (Join j : joinList) >> j.isAppJoin() == false >> continue;");
continue;
}
SQLConfig<T, M, L> cc = join.getCacheConfig(); //这里用config改了getSQL后再还原很麻烦,所以提前给一个config2更好
if (cc == null) {
if (Log.DEBUG) {
throw new NullPointerException("服务器内部错误, executeAppJoin cc == null ! 导致不能缓存 @ APP JOIN 的副表数据!");
}
continue;
}
SQLConfig<T, M, L> jc = join.getJoinConfig();
List<On> onList = join.getOnList();
On on = onList == null || onList.isEmpty() ? null : onList.get(0); // APP JOIN 应该有且只有一个 ON 条件
String originKey = on == null ? null : on.getOriginKey();
if (originKey == null) {
throw new NullPointerException("服务器内部错误,List<Join> 中 Join.onList[0" + (on == null ? "] = null!" : ".getOriginKey() = null!"));
}
String key = on.getKey();
if (key == null) {
throw new NullPointerException("服务器内部错误,List<Join> 中 Join.onList[0" + (on == null ? "] = null!" : ".getKey() = null!"));
}
// 取出 "id@": "@/User/userId" 中所有 userId 的值
List<Object> targetValueList = new ArrayList<>();
for (int i = 0; i < resultList.size(); i++) {
M mainTable = resultList.get(i);
Object targetValue = mainTable == null ? null : mainTable.get(on.getTargetKey());
if (targetValue != null && targetValueList.contains(targetValue) == false) {
targetValueList.add(targetValue);
}
}
View on GitHub (pinned to 5284052872)
Solutions
- Give the APP JOIN a complete relation: "Comment/userId@/User/id": "@ APP" style joiner with the /key@/Table/key mapping.
- When building Join programmatically, always attach a non-empty onList with a valid first On.
- If the joiner string is correct, check for version mismatch and report upstream.
Example fix
// before
"join": {"Comment@": "@ APP"}
// after
"join": {"Comment/userId@/User/id": "@ APP"} Defensive patterns
Strategy: validation
Validate before calling
// validate APP JOIN entry has a full relation before sending
const JOINER = /^[\w$]+\/[^/@]+@\/?[\w$]+\/[^/@]+$/;
for (const jk of Object.keys(body['@join'] || {})) {
if (!JOINER.test(jk)) throw new Error('malformed join key: ' + jk);
} Try / catch
try { executor.execute(config); } catch (npe) { if (npe instanceof NullPointerException && /Join\.onList\[0\] = null/.test(String(npe.getMessage()))) { log.error('APP JOIN missing ON condition'); throw new BadRequestException('join needs /key@/Table/key'); } throw npe; } Prevention
- Always write APP JOIN as 'Table/localKey@/Target/targetKey'.
- Test every join entry with a minimal request before shipping.
When it happens
Trigger: A "@ APP" type join entry whose onList was never populated — e.g. joiner string missing the key@ mapping segment, or a Join built in code without On conditions.
Common situations: Malformed join key like "Comment@ User" (no /userId@/User/id part); partial deserialization of join config; custom Join construction for APP JOIN without ON.
Related errors
- 服务器内部错误,List<Join> 中 Join.onList[0].getOriginKey() = null!
- 服务器内部错误,List<Join> 中 Join.onList[0].getKey() = null!
- 服务器内部错误,List<Join> 中 Join.onList[{}] = null!
- 服务器内部错误,List<Join> 中 Join.onList[{}].getOriginKey() = null!
- AbstractSQLExecutor.executeAppJoin StringUtil.isEmpty(sql,
AI-assisted analysis of Tencent/APIJSON@5284052872 (2026-08-14).
Data as JSON: /api/errors/20e99f88291535c5.
Report an issue: GitHub.