diff --git a/APIJSONORM/README.md b/APIJSONORM/README.md
index 745733b4..3ad56245 100644
--- a/APIJSONORM/README.md
+++ b/APIJSONORM/README.md
@@ -1,6 +1,6 @@
-# APIJSONORM [](https://jitpack.io/#Tencent/APIJSON) [
](https://deepwiki.com/Tencent/APIJSON)
-腾讯 [APIJSON](https://github.com/Tencent/APIJSON) ORM 库,可通过 Maven, Gradle 等远程依赖。
-Tencent [APIJSON](https://github.com/Tencent/APIJSON) ORM library for remote dependencies with Maven, Gradle, etc.
+# APIJSONORM [](https://jitpack.io/#APIJSON/APIJSON) [
](https://deepwiki.com/APIJSON/APIJSON)
+[APIJSON](https://github.com/APIJSON/APIJSON) ORM 库,可通过 Maven, Gradle 等远程依赖。
+[APIJSON](https://github.com/APIJSON/APIJSON) ORM library for remote dependencies with Maven, Gradle, etc.
### Maven
#### 1. 在 pom.xml 中添加 JitPack 仓库
@@ -19,9 +19,9 @@ Tencent [APIJSON](https://github.com/Tencent/APIJSON) ORM library for remote dep
#### 2. Add the APIJSON dependency to pom.xml
```xml
- com.github.Tencent
+ com.github.APIJSON
APIJSON
- 8.1.8
+ latest
```
@@ -45,7 +45,7 @@ Tencent [APIJSON](https://github.com/Tencent/APIJSON) ORM library for remote dep
#### 2. Add the APIJSON dependency in one of your modules(such as `app`)
```gradle
dependencies {
- implementation 'com.github.Tencent:APIJSON:8.1.8'
+ implementation 'com.github.APIJSON:APIJSON:latest'
}
```
@@ -54,7 +54,7 @@ Tencent [APIJSON](https://github.com/Tencent/APIJSON) ORM library for remote dep
### FASTJSON 2
#### Code
-https://github.com/Tencent/APIJSON/tree/fastjson2
+https://github.com/APIJSON/APIJSON/tree/fastjson2
#### Maven
https://mvnrepository.com/artifact/com.github.linushp/zikai-apijson/1.0
diff --git a/APIJSONORM/pom.xml b/APIJSONORM/pom.xml
index 7a35eb01..41ccd10b 100644
--- a/APIJSONORM/pom.xml
+++ b/APIJSONORM/pom.xml
@@ -3,9 +3,9 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
- com.github.Tencent
+ com.github.APIJSON
APIJSON
- 8.1.8
+ 10.0.0
jar
APIJSONORM
@@ -21,6 +21,12 @@
+
+ junit
+ junit
+ 4.13.2
+ test
+
diff --git a/APIJSONORM/src/main/java/apijson/JSON.java b/APIJSONORM/src/main/java/apijson/JSON.java
index 0a14e042..3f13dc8b 100755
--- a/APIJSONORM/src/main/java/apijson/JSON.java
+++ b/APIJSONORM/src/main/java/apijson/JSON.java
@@ -1,4 +1,4 @@
-/*Copyright (C) 2020 Tencent. All rights reserved.
+/*Copyright (C) 2026 the APIJSON group. All rights reserved.
This source code is licensed under the Apache License Version 2.0.*/
diff --git a/APIJSONORM/src/main/java/apijson/JSONCreator.java b/APIJSONORM/src/main/java/apijson/JSONCreator.java
index df0d9066..79395a86 100755
--- a/APIJSONORM/src/main/java/apijson/JSONCreator.java
+++ b/APIJSONORM/src/main/java/apijson/JSONCreator.java
@@ -1,4 +1,4 @@
-/*Copyright (C) 2020 Tencent. All rights reserved.
+/*Copyright (C) 2026 the APIJSON group. All rights reserved.
This source code is licensed under the Apache License Version 2.0.*/
diff --git a/APIJSONORM/src/main/java/apijson/JSONList.java b/APIJSONORM/src/main/java/apijson/JSONList.java
index 092bf9f3..8130f63a 100644
--- a/APIJSONORM/src/main/java/apijson/JSONList.java
+++ b/APIJSONORM/src/main/java/apijson/JSONList.java
@@ -1,4 +1,4 @@
-/*Copyright (C) 2020 Tencent. All rights reserved.
+/*Copyright (C) 2026 the APIJSON group. All rights reserved.
This source code is licensed under the Apache License Version 2.0.*/
diff --git a/APIJSONORM/src/main/java/apijson/JSONMap.java b/APIJSONORM/src/main/java/apijson/JSONMap.java
index c2913055..03c9642c 100755
--- a/APIJSONORM/src/main/java/apijson/JSONMap.java
+++ b/APIJSONORM/src/main/java/apijson/JSONMap.java
@@ -1,4 +1,4 @@
-/*Copyright (C) 2020 Tencent. All rights reserved.
+/*Copyright (C) 2026 the APIJSON group. All rights reserved.
This source code is licensed under the Apache License Version 2.0.*/
diff --git a/APIJSONORM/src/main/java/apijson/JSONParser.java b/APIJSONORM/src/main/java/apijson/JSONParser.java
index 7c38a39d..feb64528 100755
--- a/APIJSONORM/src/main/java/apijson/JSONParser.java
+++ b/APIJSONORM/src/main/java/apijson/JSONParser.java
@@ -1,4 +1,4 @@
-/*Copyright (C) 2020 Tencent. All rights reserved.
+/*Copyright (C) 2026 the APIJSON group. All rights reserved.
This source code is licensed under the Apache License Version 2.0.*/
diff --git a/APIJSONORM/src/main/java/apijson/JSONRequest.java b/APIJSONORM/src/main/java/apijson/JSONRequest.java
index c74dfe34..4d7f4f9b 100755
--- a/APIJSONORM/src/main/java/apijson/JSONRequest.java
+++ b/APIJSONORM/src/main/java/apijson/JSONRequest.java
@@ -1,4 +1,4 @@
-/*Copyright (C) 2020 Tencent. All rights reserved.
+/*Copyright (C) 2026 the APIJSON group. All rights reserved.
This source code is licensed under the Apache License Version 2.0.*/
diff --git a/APIJSONORM/src/main/java/apijson/JSONResponse.java b/APIJSONORM/src/main/java/apijson/JSONResponse.java
index 7527adff..4e76f59e 100755
--- a/APIJSONORM/src/main/java/apijson/JSONResponse.java
+++ b/APIJSONORM/src/main/java/apijson/JSONResponse.java
@@ -1,4 +1,4 @@
-/*Copyright (C) 2020 Tencent. All rights reserved.
+/*Copyright (C) 2026 the APIJSON group. All rights reserved.
This source code is licensed under the Apache License Version 2.0.*/
diff --git a/APIJSONORM/src/main/java/apijson/Log.java b/APIJSONORM/src/main/java/apijson/Log.java
index f00e495a..6b1c3b65 100755
--- a/APIJSONORM/src/main/java/apijson/Log.java
+++ b/APIJSONORM/src/main/java/apijson/Log.java
@@ -1,4 +1,4 @@
-/*Copyright (C) 2020 Tencent. All rights reserved.
+/*Copyright (C) 2026 the APIJSON group. All rights reserved.
This source code is licensed under the Apache License Version 2.0.*/
@@ -12,7 +12,7 @@
*/
public class Log {
public static boolean DEBUG = false;
- public static final String VERSION = "8.1.8";
+ public static final String VERSION = "10.0.0";
public static final String LEVEL_VERBOSE = "VERBOSE";
public static final String LEVEL_INFO = "INFO";
diff --git a/APIJSONORM/src/main/java/apijson/MethodAccess.java b/APIJSONORM/src/main/java/apijson/MethodAccess.java
index 1804f7a7..ac9f9d0e 100755
--- a/APIJSONORM/src/main/java/apijson/MethodAccess.java
+++ b/APIJSONORM/src/main/java/apijson/MethodAccess.java
@@ -1,4 +1,4 @@
-/*Copyright (C) 2020 Tencent. All rights reserved.
+/*Copyright (C) 2026 the APIJSON group. All rights reserved.
This source code is licensed under the Apache License Version 2.0.*/
diff --git a/APIJSONORM/src/main/java/apijson/NotNull.java b/APIJSONORM/src/main/java/apijson/NotNull.java
index 1265ccac..61145216 100755
--- a/APIJSONORM/src/main/java/apijson/NotNull.java
+++ b/APIJSONORM/src/main/java/apijson/NotNull.java
@@ -1,4 +1,4 @@
-/*Copyright (C) 2020 Tencent. All rights reserved.
+/*Copyright (C) 2026 the APIJSON group. All rights reserved.
This source code is licensed under the Apache License Version 2.0.*/
diff --git a/APIJSONORM/src/main/java/apijson/RequestMethod.java b/APIJSONORM/src/main/java/apijson/RequestMethod.java
index 27e4cab6..cc2a3814 100755
--- a/APIJSONORM/src/main/java/apijson/RequestMethod.java
+++ b/APIJSONORM/src/main/java/apijson/RequestMethod.java
@@ -1,4 +1,4 @@
-/*Copyright (C) 2020 Tencent. All rights reserved.
+/*Copyright (C) 2026 the APIJSON group. All rights reserved.
This source code is licensed under the Apache License Version 2.0.*/
diff --git a/APIJSONORM/src/main/java/apijson/SQL.java b/APIJSONORM/src/main/java/apijson/SQL.java
index 868f0d2a..17288135 100755
--- a/APIJSONORM/src/main/java/apijson/SQL.java
+++ b/APIJSONORM/src/main/java/apijson/SQL.java
@@ -1,4 +1,4 @@
-/*Copyright (C) 2020 Tencent. All rights reserved.
+/*Copyright (C) 2026 the APIJSON group. All rights reserved.
This source code is licensed under the Apache License Version 2.0.*/
diff --git a/APIJSONORM/src/main/java/apijson/StringUtil.java b/APIJSONORM/src/main/java/apijson/StringUtil.java
index 17916100..180cdfbe 100755
--- a/APIJSONORM/src/main/java/apijson/StringUtil.java
+++ b/APIJSONORM/src/main/java/apijson/StringUtil.java
@@ -1,4 +1,4 @@
-/*Copyright (C) 2020 Tencent. All rights reserved.
+/*Copyright (C) 2026 the APIJSON group. All rights reserved.
This source code is licensed under the Apache License Version 2.0.*/
@@ -114,7 +114,7 @@ public static String get(Object[] arr, boolean ignoreEmptyItem) {
public static String get(Object[] arr, String split) {
return get(arr, split, false);
}
- //CS304 Issue link: https://github.com/Tencent/APIJSON/issues/182
+ //CS304 Issue link: https://github.com/APIJSON/APIJSON/issues/182
/**获取string,为null则返回""
* @param arr -the str arr given
* @param split -the token used to split
@@ -192,7 +192,7 @@ public static String getString(Object[] array, boolean ignoreEmptyItem) {
public static String getString(Object[] array, String split) {
return get(array, split, false);
}
- //CS304 Issue link: https://github.com/Tencent/APIJSON/issues/182
+ //CS304 Issue link: https://github.com/APIJSON/APIJSON/issues/182
/**FIXME 用 get 替代
* @param array -the str array given
* @param split -the token used to split
@@ -755,7 +755,7 @@ public static String getNumber(String s) {
return getNumber(s, false);
}
- //CS304 Issue link: https://github.com/Tencent/APIJSON/issues/182
+ //CS304 Issue link: https://github.com/APIJSON/APIJSON/issues/182
/**去掉string内所有非数字类型字符
* @param s -string passed in
* @param onlyStart 中间有非数字时只获取前面的数字
@@ -858,7 +858,7 @@ public static String getCorrectEmail(String email) {
public static String getPrice(String price) {
return getPrice(price, PRICE_FORMAT_DEFAULT);
}
- //CS304 Issue link: https://github.com/Tencent/APIJSON/issues/182
+ //CS304 Issue link: https://github.com/APIJSON/APIJSON/issues/182
/**获取价格,保留两位小数
* @param price -price passed in
* @param formatType 添加单位(元)
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java
index 7ed7fc4d..6c4e248e 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java
@@ -1,4 +1,4 @@
-/*Copyright (C) 2020 Tencent. All rights reserved.
+/*Copyright (C) 2026 the APIJSON group. All rights reserved.
This source code is licensed under the Apache License Version 2.0.*/
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java
index 5fd00c17..79ed5738 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java
@@ -1,4 +1,4 @@
-/*Copyright (C) 2020 Tencent. All rights reserved.
+/*Copyright (C) 2026 the APIJSON group. All rights reserved.
This source code is licensed under the Apache License Version 2.0.*/
@@ -486,6 +486,11 @@ else if (value instanceof String) { // //key{}@ getRealKey, 引用赋值路径
if (target == null) { // String#equals(null)会出错
Log.d(TAG, "onParse target == null >> return true;");
+ if (method == POST || method == PUT) {
+ throw new UnsupportedOperationException("引用赋值 " + path + "/" + key + ": " + targetPath
+ + " 解析失败,POST 和 PUT 接口必须保证每个对象执行都成功!");
+ }
+
if (Log.DEBUG) {
parser.putWarnIfNeed(AbstractParser.KEY_REF, path + "/" + key + ": " + targetPath + " 引用赋值获取路径对应的值为 null!请检查路径是否错误!");
}
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
index defccc93..159536fd 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
@@ -1,4 +1,4 @@
-/*Copyright (C) 2020 Tencent. All rights reserved.
+/*Copyright (C) 2026 the APIJSON group. All rights reserved.
This source code is licensed under the Apache License Version 2.0.*/
@@ -646,7 +646,7 @@ public M parseResponse(M request) {
onClose();
- // CS304 Issue link: https://github.com/Tencent/APIJSON/issues/232
+ // CS304 Issue link: https://github.com/APIJSON/APIJSON/issues/232
if (IS_PRINT_REQUEST_STRING_LOG || Log.DEBUG || error != null) {
Log.sl("\n\n\n", '<', "");
Log.fd(TAG, requestMethod + "/parseResponse request = \n" + requestString + "\n\n");
@@ -829,8 +829,8 @@ public M extendResult(M object, int code, String msg, String warn, boolean isRoo
+ " \n数据库: DEFAULT_DATABASE = " + AbstractSQLConfig.DEFAULT_DATABASE
+ " \nJDK: " + Log.JAVA_VERSION + " " + Log.OS_ARCH
+ " \nAPIJSON: " + Log.VERSION
- + " \n \n【常见问题】:https://github.com/Tencent/APIJSON/issues/36"
- + " \n【通用文档】:https://github.com/Tencent/APIJSON/blob/master/Document.md"
+ + " \n \n【常见问题】:https://github.com/APIJSON/APIJSON/issues/36"
+ + " \n【通用文档】:https://github.com/APIJSON/APIJSON/blob/master/Document.md"
+ " \n【视频教程】:https://search.bilibili.com/all?keyword=APIJSON");
msg = index >= 0 ? msg.substring(0, index) : msg;
@@ -985,11 +985,11 @@ public M extendErrorResult(M object, Throwable e, RequestMethod requestMethod, S
msg += Log.KEY_SYSTEM_INFO_DIVIDER + " 浏览器打开以下链接查看解答"
+ (isSQLException ? "" : apiatuoAndGitHubLink)
- // GitHub Issue 搜索貌似是精准包含,不易找到答案 + " \n\nGitHub: \n https://github.com/Tencent/APIJSON/issues?q=is%3Aissue+" + encodedMsg
+ // GitHub Issue 搜索貌似是精准包含,不易找到答案 + " \n\nGitHub: \n https://github.com/APIJSON/APIJSON/issues?q=is%3Aissue+" + encodedMsg
+ " \n\n【Google】:\n https://www.google.com/search?q=" + encodedMsg
+ " \n\n【百度】:\n https://www.baidu.com/s?ie=UTF-8&wd=" + encodedMsg
+ (isSQLException ? apiatuoAndGitHubLink : "")
- + " \n\n都没找到答案?打开这个链接 \n https://github.com/Tencent/APIJSON/issues/new?assignees=&labels=&template=--bug.md "
+ + " \n\n都没找到答案?打开这个链接 \n https://github.com/APIJSON/APIJSON/issues/new?assignees=&labels=&template=--bug.md "
+ " \n然后提交问题,推荐用以下模板修改,注意要换行保持清晰可读。"
+ " \n【标题】:" + msg
+ " \n【内容】:" + env + "\n\n**问题描述**\n" + msg
@@ -2012,7 +2012,7 @@ public void putQueryResult(String path, Object result) {
queryResultMap.put(path, result);
// }
}
- //CS304 Issue link: https://github.com/Tencent/APIJSON/issues/48
+ //CS304 Issue link: https://github.com/APIJSON/APIJSON/issues/48
/**根据路径获取值
* @param valuePath -the path need to get value
* @return parent == null ? valuePath : parent.get(keys[keys.length - 1])
@@ -2303,6 +2303,86 @@ protected M getRequestStructure(RequestMethod method, String tag, int version) t
KEY_METHOD_ENUM_MAP.put(KEY_DELETE, RequestMethod.DELETE);
}
+ private void parseMethodDirective(String key, RequestMethod keyMethod, @NotNull M request) throws Exception {
+ boolean isPost = KEY_POST.equals(key);
+ Object val = request.get(key);
+ Map obj = val instanceof Map, ?> ? JSON.get(request, key) : null;
+ if (obj == null) {
+ if (val instanceof String) {
+ String[] tbls = StringUtil.split((String) val);
+ if (tbls != null && tbls.length > 0) {
+ obj = new LinkedHashMap();
+ for (String tbl : tbls) {
+ if (obj.containsKey(tbl)) {
+ throw new ConflictException(key + ": value 中 " + tbl + " 已经存在,不能重复!");
+ }
+
+ obj.put(tbl, isPost && isTableArray(tbl)
+ ? tbl.substring(0, tbl.length() - 2) + ":[]" : "");
+ }
+ }
+ }
+ else {
+ throw new IllegalArgumentException(key + ": value 中 value 类型错误,只能是 String 或 Map {} !");
+ }
+ }
+
+ Set> set = obj == null ? new HashSet<>() : obj.entrySet();
+ for (Entry objEntry : set) {
+ String objKey = objEntry == null ? null : objEntry.getKey();
+ if (objKey == null) {
+ continue;
+ }
+
+ Map objAttrMap = new HashMap<>();
+ objAttrMap.put(KEY_METHOD, keyMethod);
+ keyObjectAttributesMap.put(objKey, objAttrMap);
+
+ Object objVal = objEntry.getValue();
+ Map objAttrJson = objVal instanceof Map, ?> ? JSON.getMap(obj, objKey) : null;
+ if (objAttrJson == null) {
+ if (objVal instanceof String) {
+ objAttrMap.put(KEY_TAG, "".equals(objVal) ? objKey : objVal);
+ }
+ else {
+ throw new IllegalArgumentException(key + ": { " + objKey + ": value 中 value 类型错误,只能是 String 或 Map {} !");
+ }
+ }
+ else {
+ boolean hasTag = false;
+ for (Entry entry : objAttrJson.entrySet()) {
+ String objAttrKey = entry == null ? null : entry.getKey();
+ if (objAttrKey == null) {
+ continue;
+ }
+
+ switch (objAttrKey) {
+ case KEY_DATABASE:
+ case KEY_DATASOURCE:
+ case KEY_NAMESPACE:
+ case KEY_CATALOG:
+ case KEY_SCHEMA:
+ case KEY_VERSION:
+ case KEY_ROLE:
+ objAttrMap.put(objAttrKey, entry.getValue());
+ break;
+ case KEY_TAG:
+ hasTag = true;
+ objAttrMap.put(objAttrKey, entry.getValue());
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (hasTag == false) {
+ objAttrMap.put(KEY_TAG, isPost && isTableArray(objKey)
+ ? objKey.substring(0, objKey.length() - 2) + ":[]" : objKey);
+ }
+ }
+ }
+ }
+
protected M batchVerify(RequestMethod method, String tag, int version, String name, @NotNull M request, int maxUpdateCount, SQLCreator creator) throws Exception {
M correctRequest = JSON.createJSONObject();
List removeTmpKeys = new ArrayList<>(); // 请求json里面的临时变量,不需要带入后面的业务中,比如 @post、@get等
@@ -2312,103 +2392,34 @@ protected M batchVerify(RequestMethod method, String tag, int version, String na
throw new IllegalArgumentException("JSON 对象格式不正确 !正确示例例如 \"User\": {}");
}
+ // 先收集所有显式方法,避免同一请求中方法指令的字段顺序影响对象解析结果。
for (String key : reqSet) {
- // key 重复直接抛错(xxx:alias, xxx:alias[])
- if (correctRequest.containsKey(key) || correctRequest.containsKey(key + KEY_ARRAY)) {
- throw new IllegalArgumentException("对象名重复,请添加别名区分 ! 重复对象名为: " + key);
+ RequestMethod keyMethod = KEY_POST.equals(key) ? RequestMethod.POST : KEY_METHOD_ENUM_MAP.get(key);
+ if (keyMethod == null) {
+ continue;
}
- boolean isPost = KEY_POST.equals(key);
- // @post、@get 等 RequestMethod
+ removeTmpKeys.add(key);
try {
- RequestMethod keyMethod = isPost ? RequestMethod.POST : KEY_METHOD_ENUM_MAP.get(key);
- if (keyMethod != null) {
- // 如果不匹配,异常不处理即可
- removeTmpKeys.add(key);
-
- Object val = request.get(key);
- Map obj = val instanceof Map, ?> ? JSON.get(request, key) : null;
- if (obj == null) {
- if (val instanceof String) {
- String[] tbls = StringUtil.split((String) val);
- if (tbls != null && tbls.length > 0) {
- obj = new LinkedHashMap();
- for (int i = 0; i < tbls.length; i++) {
- String tbl = tbls[i];
- if (obj.containsKey(tbl)) {
- throw new ConflictException(key + ": value 中 " + tbl + " 已经存在,不能重复!");
- }
-
- obj.put(tbl, isPost && isTableArray(tbl)
- ? tbl.substring(0, tbl.length() - 2) + ":[]" : "");
- }
- }
- }
- else {
- throw new IllegalArgumentException(key + ": value 中 value 类型错误,只能是 String 或 Map {} !");
- }
- }
-
- Set> set = obj == null ? new HashSet<>() : obj.entrySet();
-
- for (Entry objEntry : set) {
- String objKey = objEntry == null ? null : objEntry.getKey();
- if (objKey == null) {
- continue;
- }
-
- Map objAttrMap = new HashMap<>();
- objAttrMap.put(KEY_METHOD, keyMethod);
- keyObjectAttributesMap.put(objKey, objAttrMap);
-
- Object objVal = objEntry.getValue();
- Map objAttrJson = objVal instanceof Map, ?> ? JSON.getMap(obj, objKey) : null;
- if (objAttrJson == null) {
- if (objVal instanceof String) {
- objAttrMap.put(KEY_TAG, "".equals(objVal) ? objKey : objVal);
- }
- else {
- throw new IllegalArgumentException(key + ": { " + objKey + ": value 中 value 类型错误,只能是 String 或 Map {} !");
- }
- }
- else {
- Set> objSet = objAttrJson.entrySet();
-
- boolean hasTag = false;
- for (Entry entry : objSet) {
- String objAttrKey = entry == null ? null : entry.getKey();
- if (objAttrKey == null) {
- continue;
- }
+ parseMethodDirective(key, keyMethod, request);
+ }
+ catch (Exception e) {
+ Log.e(TAG, "parse method directive failed", e);
+ throw e;
+ }
+ }
- switch (objAttrKey) {
- case KEY_DATABASE:
- case KEY_DATASOURCE:
- case KEY_NAMESPACE:
- case KEY_CATALOG:
- case KEY_SCHEMA:
- case KEY_VERSION:
- case KEY_ROLE:
- objAttrMap.put(objAttrKey, entry.getValue());
- break;
- case KEY_TAG:
- hasTag = true;
- objAttrMap.put(objAttrKey, entry.getValue());
- break;
- default:
- break;
- }
- }
+ for (String key : reqSet) {
+ // key 重复直接抛错(xxx:alias, xxx:alias[])
+ if (correctRequest.containsKey(key) || correctRequest.containsKey(key + KEY_ARRAY)) {
+ throw new IllegalArgumentException("对象名重复,请添加别名区分 ! 重复对象名为: " + key);
+ }
- if (hasTag == false) {
- objAttrMap.put(KEY_TAG, isPost && isTableArray(objKey)
- ? objKey.substring(0, objKey.length() - 2) + ":[]" : objKey);
- }
- }
- }
- continue;
- }
+ if (KEY_POST.equals(key) || KEY_METHOD_ENUM_MAP.containsKey(key)) {
+ continue;
+ }
+ try {
// 1、非crud,对于没有显式声明操作方法的,直接用 URL(/get, /post 等) 对应的默认操作方法
// 2、crud, 没有声明就用 GET
// 3、兼容 sql@ Map,设置 GET方法
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
index 05e9f04e..ca47bdf2 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
@@ -1,4 +1,4 @@
-/*Copyright (C) 2020 Tencent. All rights reserved.
+/*Copyright (C) 2026 the APIJSON group. All rights reserved.
This source code is licensed under the Apache License Version 2.0.*/
@@ -86,6 +86,7 @@ public abstract class AbstractSQLConfig, L exte
* 表名映射,隐藏真实表名,对安全要求很高的表可以这么做
*/
public static Map TABLE_KEY_MAP;
+ public static Map UPSERT_TABLE_MAP;
/**
* 字段名映射,隐藏真实字段名,对安全要求很高的表可以这么做,另外可以配置 name_tag:(name,tag) 来实现多字段 IN,length_tag:length(tag) 来实现 SQL 函数复杂条件
*/
@@ -135,6 +136,8 @@ public abstract class AbstractSQLConfig, L exte
TABLE_KEY_MAP.put(AllTableComment.class.getSimpleName(), AllTableComment.TABLE_NAME);
TABLE_KEY_MAP.put(AllColumnComment.class.getSimpleName(), AllColumnComment.TABLE_NAME);
+ UPSERT_TABLE_MAP = new HashMap<>();
+
ALLOW_PARTIAL_UPDATE_FAIL_TABLE_MAP = new HashMap<>();
CONFIG_TABLE_LIST = new ArrayList<>(); // Table, Column 等是系统表 AbstractVerifier.SYSTEM_ACCESS_MAP.keySet());
@@ -154,6 +157,9 @@ public abstract class AbstractSQLConfig, L exte
DATABASE_LIST.add(DATABASE_COCKROACHDB);
DATABASE_LIST.add(DATABASE_DAMENG);
DATABASE_LIST.add(DATABASE_KINGBASE);
+ DATABASE_LIST.add(DATABASE_KINGBASE_MYSQL);
+ DATABASE_LIST.add(DATABASE_KINGBASE_ORACLE);
+ DATABASE_LIST.add(DATABASE_KINGBASE_SQLSERVER);
DATABASE_LIST.add(DATABASE_ELASTICSEARCH);
DATABASE_LIST.add(DATABASE_MANTICORE);
DATABASE_LIST.add(DATABASE_CLICKHOUSE);
@@ -178,6 +184,7 @@ public abstract class AbstractSQLConfig, L exte
DATABASE_LIST.add(DATABASE_SURREALDB);
DATABASE_LIST.add(DATABASE_OPENGAUSS);
DATABASE_LIST.add(DATABASE_DORIS);
+ DATABASE_LIST.add(DATABASE_STARROCKS);
RAW_MAP = new LinkedHashMap<>(); // 保证顺序,避免配置冲突等意外情况
@@ -893,6 +900,7 @@ public String getUserIdKey() {
private boolean main = true;
private Object id; // Table 的 id
+ private boolean idGeneratedByAPIJSON;
private Object idIn; // User Table 的 id IN
private Object userId; // Table 的 userId
private Object userIdIn; // Table 的 userId IN
@@ -1010,6 +1018,15 @@ public AbstractSQLConfig setId(Object id) {
this.id = id;
return this;
}
+ @Override
+ public boolean isIdGeneratedByAPIJSON() {
+ return idGeneratedByAPIJSON;
+ }
+ @Override
+ public AbstractSQLConfig setIdGeneratedByAPIJSON(boolean generated) {
+ this.idGeneratedByAPIJSON = generated;
+ return this;
+ }
@Override
public Object getIdIn() {
@@ -1083,11 +1100,11 @@ public String gainSQLDatabase() {
@Override
public boolean isTSQL() { // 兼容 TSQL 语法
- return isOracle() || isSQLServer() || isDb2();
+ return isOracle() || isSQLServer() || isDb2() || isKingBaseOracle() || isKingBaseSQLServer();
}
@Override
public boolean isMSQL() { // 兼容 MySQL 语法,但不一定可以使用它的 JDBC/ODBC
- return isMySQL() || isTiDB() || isMariaDB() || isSQLite() || isTDengine();
+ return isMySQL() || isTiDB() || isMariaDB() || isSQLite() || isTDengine() || isKingBaseMySQL();
}
@Override
public boolean isPSQL() { // 兼容 PostgreSQL 语法,但不一定可以使用它的 JDBC/ODBC
@@ -1171,7 +1188,31 @@ public boolean isKingBase() {
return isKingBase(gainSQLDatabase());
}
public static boolean isKingBase(String db) {
- return DATABASE_KINGBASE.equals(db);
+ return KingbaseSQLDialect.from(db).isKingbase();
+ }
+
+ @Override
+ public boolean isKingBaseMySQL() {
+ return isKingBaseMySQL(gainSQLDatabase());
+ }
+ public static boolean isKingBaseMySQL(String db) {
+ return KingbaseSQLDialect.from(db).isMySQL();
+ }
+
+ @Override
+ public boolean isKingBaseOracle() {
+ return isKingBaseOracle(gainSQLDatabase());
+ }
+ public static boolean isKingBaseOracle(String db) {
+ return KingbaseSQLDialect.from(db).isOracle();
+ }
+
+ @Override
+ public boolean isKingBaseSQLServer() {
+ return isKingBaseSQLServer(gainSQLDatabase());
+ }
+ public static boolean isKingBaseSQLServer(String db) {
+ return KingbaseSQLDialect.from(db).isSQLServer();
}
@Override
@@ -1375,12 +1416,24 @@ public static boolean isDoris(String db) {
return DATABASE_DORIS.equals(db);
}
+ @Override
+ public boolean isStarRocks() {
+ return isStarRocks(gainSQLDatabase());
+ }
+ public static boolean isStarRocks(String db) {
+ return DATABASE_STARROCKS.equals(db);
+ }
+
@Override
public String getQuote() { // MongoDB 同时支持 `tbl` 反引号 和 "col" 双引号
if(isElasticsearch() || isManticore() || isIoTDB() || isSurrealDB()) {
return "";
}
- return isMySQL() || isMariaDB() || isTiDB() || isClickHouse() || isTDengine() || isMilvus() || isDoris() ? "`" : "\"";
+ KingbaseSQLDialect kingbaseDialect = KingbaseSQLDialect.from(gainSQLDatabase());
+ if (kingbaseDialect.isKingbase()) {
+ return kingbaseDialect.getIdentifierQuote();
+ }
+ return isMySQL() || isMariaDB() || isTiDB() || isClickHouse() || isTDengine() || isMilvus() || isDoris() || isStarRocks() ? "`" : "\"";
}
public String quote(String s) {
@@ -1516,7 +1569,7 @@ public AbstractSQLConfig setTable(String table) { //Table已经在Parse
}
public String gainAs() {
- return isOracle() || isManticore() ? " " : " AS ";
+ return isOracle() || isKingBaseOracle() || isManticore() ? " " : " AS ";
}
@Override
@@ -1716,7 +1769,8 @@ protected String gainHavingItem(String quote, String table, String alias
+ "预编译模式下 @having:\"column?value;function(arg0,arg1,...)?value...\""
+ " 中 column?value 必须符合正则表达式 " + PATTERN_FUNCTION + " 且不包含连续减号 -- !不允许空格!");
}
- return expression;
+
+ return parseSQLExpression(KEY_HAVING, expression, containRaw, false, null);
}
int end = expression.lastIndexOf(")");
@@ -2065,7 +2119,7 @@ public String gainOrderString(boolean hasPrefix) {
// return (hasPrefix ? " ORDER BY " : "") + StringUtil.concat(order, joinOrder, ", ");
// }
- if (getCount() > 0 && (isSQLServer() || isDb2())) {
+ if (getCount() > 0 && (isSQLServer() || isKingBaseSQLServer() || isDb2())) {
// Oracle, SQL Server, DB2 的 OFFSET 必须加 ORDER BY.去掉Oracle,Oracle里面没有offset关键字
// String[] ss = StringUtil.split(order);
@@ -2575,7 +2629,7 @@ else if (SQL_FUNCTION_MAP.containsKey(fun) == false) {
}
// 获取前半部分函数的参数解析 fun(arg0,agr1)
- String agrsString1[] = parseArgsSplitWithComma(
+ String[] args = parseArgsSplitWithComma(
s1.substring(index1 + 1, s1.lastIndexOf(")")), false, containRaw, allowAlias
);
@@ -2599,9 +2653,9 @@ else if (SQL_FUNCTION_MAP.containsKey(fun) == false) {
}
// 获取后半部分的参数解析 (agr0 agr1 ...)
- String[] argsString2 = parseArgsSplitWithComma(argString2, false, containRaw, allowAlias);
- expression = fun + "(" + StringUtil.get(agrsString1) + (containOver ? ") OVER (" : ") AGAINST (")
- + StringUtil.get(argsString2) + ")" + suffix // 传参不传空格,拼接带空格
+ String[] args2 = parseArgsSplitWithComma(argString2, false, containRaw, allowAlias);
+ expression = fun + "(" + StringUtil.get(args) + (containOver ? ") OVER (" : ") AGAINST (")
+ + StringUtil.get(args2) + ")" + suffix // 传参不传空格,拼接带空格
+ (StringUtil.isEmpty(alias, true) ? "" : gainAs() + quote + alias + quote);
}
}
@@ -2845,7 +2899,7 @@ else if (ck.contains("`") || ck.contains("'") || origin.startsWith("_") || origi
public List> getValues() {
return values;
}
- public String getValuesString() {
+ public String gainValuesString() {
String s = "";
if (values != null && values.size() > 0) {
Object[] items = new Object[values.size()];
@@ -3064,8 +3118,14 @@ else if (isSurrealDB()) {
}
}
+ KingbaseSQLDialect kingbaseDialect = KingbaseSQLDialect.from(gainSQLDatabase());
+ String kingbaseLimit = kingbaseDialect.getSelectLimit(getOffset(page, count), count);
+ if (kingbaseLimit != null) {
+ return kingbaseLimit;
+ }
+
boolean isOracle = isOracle();
- return gainLimitString(page, count, isTSQL(), isOracle || isDameng() || isKingBase(), isPresto() || isTrino());
+ return gainLimitString(page, count, isTSQL(), isOracle || isDameng() || isKingBaseOracle(), isPresto() || isTrino());
}
/**获取限制数量及偏移量
* @param page
@@ -3193,7 +3253,7 @@ public AbstractSQLConfig setWhere(Map where) {
public Object getWhere(String key) {
return getWhere(key, false);
}
- //CS304 Issue link: https://github.com/Tencent/APIJSON/issues/48
+ //CS304 Issue link: https://github.com/APIJSON/APIJSON/issues/48
/**
* @param key - the key passed in
* @param exactMatch - whether it is exact match
@@ -4005,7 +4065,7 @@ public String gainCompareString(String key, String column, Object value, String
public String gainKey(@NotNull String key) {
String lenFun = "";
if (key.endsWith("[")) {
- lenFun = isSQLServer() ? "datalength" : "length";
+ lenFun = isSQLServer() || isKingBaseSQLServer() ? "datalength" : "length";
key = key.substring(0, key.length() - 1);
}
else if (key.endsWith("{")) {
@@ -4293,10 +4353,11 @@ public String gainRegExpString(String key, String column, Object[] values, int t
* @return key REGEXP 'value'
*/
public String gainRegExpString(String key, String column, String value, boolean ignoreCase) {
- if (isPSQL()) {
+ if (isPSQL() || isKingBaseSQLServer()) {
return gainKey(column) + " ~" + (ignoreCase ? "* " : " ") + gainValue(key, column, value);
}
- if (isOracle() || isDameng() || isKingBase() || (isMySQL() && gainDBVersionNums()[0] >= 8)) {
+ if (isOracle() || isDameng() || DATABASE_KINGBASE.equals(gainSQLDatabase())
+ || isKingBaseOracle() || isKingBaseMySQL() || (isMySQL() && gainDBVersionNums()[0] >= 8)) {
return "regexp_like(" + gainKey(column) + ", " + gainValue(key, column, value) + (ignoreCase ? ", 'i'" : ", 'c'") + ")";
}
if (isPresto() || isTrino()) {
@@ -4615,7 +4676,10 @@ public String gainContainString(String key, String column, Object[] childs, int
condition += (gainKey(column) + " @> " + gainValue(key, column, newJSONArray(c)));
// operator does not exist: jsonb @> character varying "[" + c + "]");
}
- else if (isOracle() || isDameng() || isKingBase()) {
+ else if (isKingBase() && isKingBaseOracle() == false) {
+ condition += (gainKey(column) + "::jsonb @> " + gainValue(key, column, newJSONArray(c)) + "::jsonb");
+ }
+ else if (isOracle() || isDameng() || isKingBaseOracle()) {
condition += ("json_textcontains(" + gainKey(column) + ", " + (StringUtil.isEmpty(path, true)
? "'$'" : gainValue(key, column, path)) + ", " + gainValue(key, column, c == null ? null : c.toString()) + ")");
}
@@ -4662,7 +4726,7 @@ public List getWithAsExprSQLList() {
}
private void clearWithAsExprListIfNeed() {
// mysql8版本以上,子查询支持with as表达式
- if(this.isMySQL() && this.gainDBVersionNums()[0] >= 8) {
+ if((this.isMySQL() || this.isKingBaseMySQL()) && this.gainDBVersionNums()[0] >= 8) {
this.withAsExprSQLList = new ArrayList<>();
}
}
@@ -4716,7 +4780,7 @@ private String withAsExprSubqueryString(SQLConfig cfg, Subquery> L newJSONArray(Object obj) {
public String gainSetString() throws Exception {
return gainSetString(getMethod(), getContent(), ! isTest());
}
- //CS304 Issue link: https://github.com/Tencent/APIJSON/issues/48
+ //CS304 Issue link: https://github.com/APIJSON/APIJSON/issues/48
/**获取SET
* @param method -the method used
* @param content -the content map
@@ -4944,13 +5008,13 @@ public static , L extends List