{"record":{"id":"b90d3bd71666e686","repo":"Tencent/APIJSON","slug":"combine","errorCode":null,"errorMessage":"{}:{ @combine:'{}' } 中字符 '{}' 不合法！逻辑连接符 & 右边缺少一个空格 ！逻辑连接符 & | 左右必须各一个相邻空格！空格不能多也不能少！不允许首尾有空格，也不允许连续空格！左括号 ( 的右边 和 右括号 ) 的左边 都不允许有相邻空格！","messagePattern":"(.+?):(.+?)' \\} 中字符 '(.+?)' 不合法！逻辑连接符 & 右边缺少一个空格 ！逻辑连接符 & \\| 左右必须各一个相邻空格！空格不能多也不能少！不允许首尾有空格，也不允许连续空格！左括号 \\( 的右边 和 右括号 \\) 的左边 都不允许有相邻空格！","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java","lineNumber":3549,"sourceCode":"\t\t\t\t\t\tresult += \"( \" + gainCondition(isNot, wi) + \" )\";\n\t\t\t\t\t\tisNot = false;\n\t\t\t\t\t\tfirst = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tkey = \"\";\n\t\t\t\t\tlastLogic = 0;\n\n\t\t\t\t\tif (isOver) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (c == ' ') {\n\t\t\t\t}\n\t\t\t\telse if (c == '&') {\n\t\t\t\t\tif (last == ' ') {\n\t\t\t\t\t\tif (i >= n - 1 || s.charAt(i + 1) != ' ') {\n\t\t\t\t\t\t\tthrow new IllegalArgumentException(errPrefix + \" 中字符 '\" + (i >= n - 1 ? s : s.substring(0, i + 1))\n\t\t\t\t\t\t\t\t\t+ \"' 不合法！逻辑连接符 & 右边缺少一个空格 ！逻辑连接符 & | 左右必须各一个相邻空格！空格不能多也不能少！\"\n\t\t\t\t\t\t\t\t\t+ \"不允许首尾有空格，也不允许连续空格！左括号 ( 的右边 和 右括号 ) 的左边 都不允许有相邻空格！\");\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tresult += SQL.AND;\n\t\t\t\t\t\tlastLogic = c;\n\t\t\t\t\t\ti ++;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tkey += c;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (c == '|') {\n\t\t\t\t\tif (last == ' ') {\n\t\t\t\t\t\tif (i >= n - 1 || s.charAt(i + 1) != ' ') {\n\t\t\t\t\t\t\tthrow new IllegalArgumentException(table + \":{ @combine: '\" + combine\n\t\t\t\t\t\t\t\t\t+ \"' } 中字符 '\" + (i >= n - 1 ? s : s.substring(0, i + 1))\n\t\t\t\t\t\t\t\t\t+ \"' 不合法！逻辑连接符 | 右边缺少一个空格 ！逻辑连接符 & | 左右必须各一个相邻空格！空格不能多也不能少！\"","sourceCodeStart":3531,"sourceCodeEnd":3567,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java#L3531-L3567","documentation":"In @combine parsing, '&' is only treated as a logic operator when the previous char was a space (last == ' '); the operator form additionally requires the next char to be a space. If '&' follows its leading space but is not followed by exactly one space (end of string or non-space next), this error is thrown — the '&' operator must have one adjacent space on BOTH sides.","triggerScenarios":"@combine:\"id &name\", \"id &\", or \"id &  name\" variants where after '&' comes end-of-string or a non-space char. (The double-space case is separately caught as an empty-key error.) Trigger point: line 3549, when s.charAt(i+1) != ' ' or i >= n-1.","commonSituations":"Hand-typing expressions with one space around the operator; concatenating \"a \" + \"& \" + \"b\" incorrectly (yielding \"a & b\" vs \"a &b\"); minifying JSON and stripping spaces inside the @combine string value by accident.","solutions":["Format every operator as ' & ' — exactly one space before and after: \"id & name\".","Build expressions with a helper that always joins with ' & ' / ' | ' (see validation code).","Run a grammar pre-check before sending (see validation code)."],"exampleFix":"// before\n{\"@combine\":\"id &name\"}\n// after\n{\"@combine\":\"id & name\"}","handlingStrategy":"validation","validationCode":"if (!combine.matches(\"(\\\\S+|\\\\([^()]*\\\\))(\\\\s[&|]\\\\s(\\\\S+|\\\\([^()]*\\\\)))*\"))\n    throw new IllegalArgumentException(\"@combine must use exactly one space around each & and |\");","typeGuard":"const WELL_SPACED = /^(?:\\S+|\\([^()]*\\))(?:\\s[&|]\\s(?:\\S+|\\([^()]*\\)))*$/;\nfunction isWellSpaced(combine: string): boolean { return WELL_SPACED.test(combine); }","tryCatchPattern":null,"preventionTips":["Always type operators as ' & ' with a space on both sides.","Never minify whitespace inside the @combine string value.","Generate expressions with join(' & ') helpers."],"tags":["apijson","combine","whitespace","syntax-error"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}