{"record":{"id":"56f39956cf358248","repo":"Tencent/APIJSON","slug":"put","errorCode":null,"errorMessage":"PUT {}, {}/{} 已存在！","messagePattern":"PUT (.+?), (.+?)/(.+?) 已存在！","errorType":"exception","errorClass":"ConflictException","httpStatus":null,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java","lineNumber":754,"sourceCode":"\t\t\t\t\t\t: \" 类型为 \" + target.getClass().getSimpleName() + \"，不支持这样移除！\")\n\t\t\t\t\t\t+ \"对应字段在数据库的值必须为 JSONArray, JSONObject 中的一种，且 key- 移除时，本身的值不能为 null！\"\n\t\t\t\t\t\t+ \"值为 JSONRequest 类型时传参必须是 'key+': [{'key': value, 'key2': value2}] 或 'key-': ['key', 'key2'] ！\"\n\t\t\t\t);\n\t\t\t}\n\n\t\t\ttargetArray = JSON.createJSONArray();\n\t\t}\n\n\t\tfor (int i = 0; i < array.size(); i++) {\n\t\t\tObject obj = array.get(i);\n\t\t\tif (obj == null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (isAdd) {\n\t\t\t\tif (targetArray != null) {\n\t\t\t\t\tif (targetArray.contains(obj)) {\n\t\t\t\t\t\tthrow new ConflictException(\"PUT \" + path + \", \" + key + \"/\" + i + \" 已存在！\");\n\t\t\t\t\t}\n\t\t\t\t\ttargetArray.add(obj);\n\t\t\t\t} else {\n\t\t\t\t\tif (obj != null && obj instanceof Map == false) {\n\t\t\t\t\t\tthrow new ConflictException(\"PUT \" + path + \", \" + key + \"/\" + i + \" 必须为 JSONRequest {} ！\");\n\t\t\t\t\t}\n\t\t\t\t\ttargetObj.putAll((Map) obj);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (targetArray != null) {\n\t\t\t\t\tif (targetArray.contains(obj) == false) {\n\t\t\t\t\t\tthrow new NullPointerException(\"PUT \" + path + \", \" + key + \"/\" + i + \" 不存在！\");\n\t\t\t\t\t}\n\t\t\t\t\ttargetArray.remove(obj);\n\t\t\t\t} else {\n\t\t\t\t\tif (obj instanceof String == false) {\n\t\t\t\t\t\tthrow new ConflictException(\"PUT \" + path + \", \" + key + \"/\" + i + \" 必须为 String 类型 ！\");\n\t\t\t\t\t}","sourceCodeStart":736,"sourceCodeEnd":772,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java#L736-L772","documentation":"During 'key+': [...] processing on a JSONArray-valued column, each element to add is checked with targetArray.contains(obj); if the element is already present, a ConflictException is thrown identifying key and array index. This preserves set-like semantics for JSON array increments — duplicates are rejected rather than appended.","triggerScenarios":"PUT { \"tags+\": [\"music\"] } when the tags column already contains \"music\". Duplicate detection is exact equals on the parsed JSON value, so {\"a\":1} vs {\"a\":1} as equal Maps also conflicts.","commonSituations":"Retry of a previously successful PUT (idempotency mismatch); UI allowing double-submits; concurrent updates adding the same tag; number formatting differences (1 vs 1.0) making values look equal or not.","solutions":["Client-side: diff against the current value and only send elements not yet present.","Make PUT-with-key+ idempotent by catching ConflictException and treating 'already exists' as success when the retry is a duplicate submit.","Guard against double submits in the UI/request layer."],"exampleFix":"// before\nput(new String[]{ \"music\" }); // tags already has \"music\" -> ConflictException\n// after\nList<String> add = currentTags.stream().filter(t -> !currentTags.contains(t)).collect(toList());\nif (!add.isEmpty()) put(add.toArray(new String[0]));","handlingStrategy":"try-catch","validationCode":"JSONArray current = fetchArrayColumn(tableName, id, key);\nJSONArray toAdd = new JSONArray();\nfor (Object o : payload) if (!current.contains(o)) toAdd.add(o); // dedupe before sending\nif (!toAdd.isEmpty()) sendKeyPlus(key, toAdd);","typeGuard":"function filterExisting<T>(current: T[], add: T[]): T[] {\n  return add.filter(x => !current.some(c => JSON.stringify(c) === JSON.stringify(x)));\n}","tryCatchPattern":"try { sendKeyPlus(...); } catch (ConflictException e) { if (e.getMessage().contains(\"已存在\")) { /* duplicate submit: refetch and treat as success */ } else throw e; }","preventionTips":["Diff against the freshest value before sending key+ payloads.","Debounce/prevent double submits in the UI.","Treat '已存在' ConflictException on retries as idempotent success after re-fetching."],"tags":["apijson","put","conflict","duplicate","json-array"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}