Tencent/APIJSON · error · IllegalArgumentException

joinType + "/.../" + table + "/" + originKey + " 中字符 " + ori

Error message

joinType + "/.../" + table + "/" + originKey + " 中字符 " + originKey + " 不合法!join:'.../refKey'" + " 中 refKey 必须以 @ 结尾!

What it means

Join.setKeyAndType parses each key inside a @join table's field map. APIJSON join references must be of the form '.../refKey@' where the trailing '@' marks the value as a reference to the current table's field (e.g. "join":"/User/id@", User:{ "id@":"/Moment/userId" }). If originKey does not end with '@', APIJSON cannot tell which local field to bind — literal constant comparisons in join keys are deliberately unsupported (see the TODO in source), so it throws IllegalArgumentException.

Source

Thrown at APIJSONORM/src/main/java/apijson/orm/Join.java:275

			this.targetAlias = targetAlias;
		}
		public String getTargetAlias() {
			return targetAlias;
		}
		public String getTargetKey() {
			return targetKey;
		}
		public void setTargetKey(String targetKey) {
			this.targetKey = targetKey;
		}


		public void setKeyAndType(String joinType, String table, @NotNull String originKey) throws Exception { //id, id@, id{}@, contactIdList<>@ ...
			if (originKey.endsWith("@")) {
				originKey = originKey.substring(0, originKey.length() - 1);
			}
			else { //TODO 暂时只允许 User.id = Moment.userId 字段关联,不允许 User.id = 82001 这种
				throw new IllegalArgumentException(joinType + "/.../" + table + "/" + originKey + " 中字符 " + originKey + " 不合法!join:'.../refKey'" + " 中 refKey 必须以 @ 结尾!");
			}

			String k;

			if (originKey.endsWith("{}")) {
				setRelateType("{}");
				k = originKey.substring(0, originKey.length() - 2);
			}
			else if (originKey.endsWith("<>")) {
				setRelateType("<>");
				k = originKey.substring(0, originKey.length() - 2);
			}
			else if (originKey.endsWith("$")) {  // key%$:"a" -> key LIKE '%a%'; key?%$:"a" -> key LIKE 'a%'; key_?$:"a" -> key LIKE '_a'; key_%$:"a" -> key LIKE '_a%'
				k = originKey.substring(0, originKey.length() - 1);
				char c = k.isEmpty() ? 0 : k.charAt(k.length() - 1);

				String t = "$";
				if (c == '%' || c == '_' || c == '?') {

View on GitHub (pinned to 5284052872)

Solutions

  1. Append '@' and point the key at an existing field of the main table: "User":{"id@":"/Moment/userId"} — and ensure the referenced field exists in the outer object.
  2. Put constant conditions directly as normal where-clauses on the joined table's object (which supports literal values) instead of in the reference key.
  3. Check spelling of the refKey chain: format is 'alias/tableKey/field@' or per docs '.../refKey@'.

Example fix

// before
{"Moment":{...},"join":"/User/id","User":{"id":"/Moment/userId"}}
// after
{"Moment":{...},"join":"/User/id@","User":{"id@":"/Moment/userId"}}
Defensive patterns

Strategy: validation

Validate before calling

private static final Pattern JOIN_REF = Pattern.compile("^!?\\w+(\\{(\\}|\\[\\])|<>|\\$|~|\\*~|>=|<=|>|<)?@$");
void checkJoinKeys(JSONObject joinTableObj) {
  for (String k : joinTableObj.keySet())
    if (!JOIN_REF.matcher(k).matches() && !k.startsWith("@"))
      throw new IllegalArgumentException("join key '" + k + "' must end with @ (reference), e.g. 'id@'");
}

Type guard

function isJoinRefKey(k) { return /^!?[A-Za-z]\w*(@|\{\}@|<>@|\$@|~@|\*~@|>=@|<=@|>@|<@)$/.test(k); }

Prevention

When it happens

Trigger: A request specifies join config like "User":{"name":"/Moment/name"} or "join":"/User/id" — the key after stripping operators does not terminate with '@'. Only 'id@', 'id{}@', 'contactIdList<>@' style keys are accepted.

Common situations: Assuming join keys can bind literal values (User.id = 82001) — unsupported by design; forgetting the '@' suffix when hand-writing join objects; converting an older APIJSON 3.x request to 4.x join syntax; using '@combine'-style keys inside a join table map.

Related errors


AI-assisted analysis of Tencent/APIJSON@5284052872 (2026-08-14). Data as JSON: /api/errors/8efaa5b1ceb71ec2. Report an issue: GitHub.