Skip to content

Commit edd8570

Browse files
committed
远程函数:支持自动且智能解析参数值,兼容 key, 'value' 指定键值格式;@raw 支持远程函数和存储过程
1 parent 88e77c2 commit edd8570

File tree

4 files changed

+137
-30
lines changed

4 files changed

+137
-30
lines changed

APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java

Lines changed: 121 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.lang.reflect.InvocationTargetException;
1111
import java.lang.reflect.Method;
1212
import java.util.Arrays;
13+
import java.util.Collection;
1314
import java.util.HashMap;
1415
import java.util.List;
1516
import java.util.Map;
@@ -22,6 +23,8 @@
2223
import com.alibaba.fastjson.JSON;
2324
import com.alibaba.fastjson.JSONArray;
2425
import com.alibaba.fastjson.JSONObject;
26+
import com.alibaba.fastjson.parser.ParserConfig;
27+
import com.alibaba.fastjson.util.TypeUtils;
2528

2629
import apijson.Log;
2730
import apijson.NotNull;
@@ -34,6 +37,10 @@
3437
public class AbstractFunctionParser implements FunctionParser {
3538
private static final String TAG = "AbstractFunctionParser";
3639

40+
/**是否解析参数 key 的对应的值,不用手动编码 curObj.getString(key)
41+
*/
42+
public static boolean IS_PARSE_ARG_VALUE = false;
43+
3744
/**开启支持远程函数
3845
*/
3946
public static boolean ENABLE_REMOTE_FUNCTION = true;
@@ -155,11 +162,21 @@ public AbstractFunctionParser setCurrentObject(@NotNull JSONObject currentObject
155162
/**反射调用
156163
* @param function 例如get(object,key),参数只允许引用,不能直接传值
157164
* @param currentObject 不作为第一个参数,就不能远程调用invoke,避免死循环
158-
* @return {@link #invoke(AbstractFunctionParser, String, JSONObject)}
165+
* @return {@link #invoke(String, JSONObject, boolean)}
159166
*/
160167
@Override
161168
public Object invoke(@NotNull String function, @NotNull JSONObject currentObject) throws Exception {
162-
return invoke(this, function, currentObject);
169+
return invoke(function, currentObject, false);
170+
}
171+
/**反射调用
172+
* @param function 例如get(object,key),参数只允许引用,不能直接传值
173+
* @param currentObject 不作为第一个参数,就不能远程调用invoke,避免死循环
174+
* @param containRaw 包含原始 SQL 片段
175+
* @return {@link #invoke(AbstractFunctionParser, String, JSONObject, boolean)}
176+
*/
177+
@Override
178+
public Object invoke(@NotNull String function, @NotNull JSONObject currentObject, boolean containRaw) throws Exception {
179+
return invoke(this, function, currentObject, containRaw);
163180
}
164181

165182
/**反射调用
@@ -168,13 +185,13 @@ public Object invoke(@NotNull String function, @NotNull JSONObject currentObject
168185
* @param currentObject
169186
* @return {@link #invoke(AbstractFunctionParser, String, Class[], Object[])}
170187
*/
171-
public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String function, @NotNull JSONObject currentObject) throws Exception {
188+
public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String function, @NotNull JSONObject currentObject, boolean containRaw) throws Exception {
172189
if (ENABLE_REMOTE_FUNCTION == false) {
173190
throw new UnsupportedOperationException("AbstractFunctionParser.ENABLE_REMOTE_FUNCTION" +
174191
" == false 时不支持远程函数!如需支持则设置 AbstractFunctionParser.ENABLE_REMOTE_FUNCTION = true !");
175192
}
176193

177-
FunctionBean fb = parseFunction(function, currentObject, false);
194+
FunctionBean fb = parseFunction(function, currentObject, false, containRaw);
178195

179196
JSONObject row = FUNCTION_MAP.get(fb.getMethod());
180197
if (row == null) {
@@ -230,17 +247,31 @@ public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull Str
230247
}
231248

232249
/**反射调用
233-
* @param methodName
234-
* @param parameterTypes
235-
* @param args
236-
* @return
237-
*/
250+
* @param parser
251+
* @param methodName
252+
* @param parameterTypes
253+
* @param args
254+
* @return {@link #invoke(AbstractFunctionParser, String, Class[], Object[], String, JSONObject, int)}
255+
* @throws Exception
256+
*/
238257
public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String methodName
239258
, @NotNull Class<?>[] parameterTypes, @NotNull Object[] args) throws Exception {
240259
return invoke(parser, methodName, parameterTypes, args, null, null, TYPE_REMOTE_FUNCTION);
241260
}
261+
/**反射调用
262+
* @param parser
263+
* @param methodName
264+
* @param parameterTypes
265+
* @param args
266+
* @param returnType
267+
* @param currentObject
268+
* @param type
269+
* @return
270+
* @throws Exception
271+
*/
242272
public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String methodName
243-
, @NotNull Class<?>[] parameterTypes, @NotNull Object[] args, String returnType, JSONObject currentObject, int type) throws Exception {
273+
, @NotNull Class<?>[] parameterTypes, @NotNull Object[] args, String returnType
274+
, JSONObject currentObject, int type) throws Exception {
244275
if (type == TYPE_SCRIPT_FUNCTION) {
245276
return invokeScript(parser, methodName, parameterTypes, args, returnType, currentObject);
246277
}
@@ -276,11 +307,22 @@ public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull Str
276307
/*获取执行JavaScript的执行引擎*/
277308
SCRIPT_ENGINE = new ScriptEngineManager().getEngineByName("javascript");
278309
INVOCABLE = (Invocable) SCRIPT_ENGINE;
279-
} catch (Exception e) {
310+
}
311+
catch (Exception e) {
280312
e.printStackTrace();
281313
}
282314
}
283315

316+
/**Java 调用 JavaScript 函数
317+
* @param parser
318+
* @param methodName
319+
* @param parameterTypes
320+
* @param args
321+
* @param returnType
322+
* @param currentObject
323+
* @return
324+
* @throws Exception
325+
*/
284326
public static Object invokeScript(@NotNull AbstractFunctionParser parser, @NotNull String methodName
285327
, @NotNull Class<?>[] parameterTypes, @NotNull Object[] args, String returnType, JSONObject currentObject) throws Exception {
286328
JSONObject row = SCRIPT_MAP.get(methodName);
@@ -388,6 +430,17 @@ public static Object invokeScript(@NotNull AbstractFunctionParser parser, @NotNu
388430
*/
389431
@NotNull
390432
public static FunctionBean parseFunction(@NotNull String function, @NotNull JSONObject request, boolean isSQLFunction) throws Exception {
433+
return parseFunction(function, request, isSQLFunction, false);
434+
}
435+
/**解析函数,自动解析的值类型只支持 Boolean, Number, String, Map, List
436+
* @param function
437+
* @param request
438+
* @param isSQLFunction
439+
* @param containRaw
440+
* @return
441+
* @throws Exception
442+
*/
443+
public static FunctionBean parseFunction(@NotNull String function, @NotNull JSONObject request, boolean isSQLFunction, boolean containRaw) throws Exception {
391444

392445
int start = function.indexOf("(");
393446
int end = function.lastIndexOf(")");
@@ -405,14 +458,14 @@ public static FunctionBean parseFunction(@NotNull String function, @NotNull JSON
405458
Class<?>[] types;
406459
Object[] values;
407460

408-
if (isSQLFunction) {
461+
if (isSQLFunction || IS_PARSE_ARG_VALUE) {
409462
types = new Class<?>[length];
410463
values = new Object[length];
411464

412465
//碰到null就挂了!!!Number还得各种转换不灵活!不如直接传request和对应的key到函数里,函数内实现时自己 getLongValue,getJSONObject ...
413466
Object v;
414467
for (int i = 0; i < length; i++) {
415-
v = values[i] = request.get(keys[i]);
468+
v = values[i] = getArgValue(request, keys[i], containRaw); // request.get(keys[i]);
416469
if (v == null) {
417470
types[i] = Object.class;
418471
values[i] = null;
@@ -421,24 +474,29 @@ public static FunctionBean parseFunction(@NotNull String function, @NotNull JSON
421474

422475
if (v instanceof Boolean) {
423476
types[i] = Boolean.class; //只支持JSON的几种类型
424-
}
477+
} // 怎么都有 bug,如果是引用的值,很多情况下无法指定 // 用 1L 指定为 Long ? 其它的默认按长度分配为 Integer 或 Long?
478+
//else if (v instanceof Long || v instanceof Integer || v instanceof Short) {
479+
// types[i] = Long.class;
480+
//}
425481
else if (v instanceof Number) {
426482
types[i] = Number.class;
427483
}
428484
else if (v instanceof String) {
429485
types[i] = String.class;
430486
}
431-
else if (v instanceof JSONObject) { // Map) {
432-
types[i] = JSONObject.class;
433-
//性能比较差 values[i] = request.getJSONObject(keys[i]);
487+
else if (v instanceof Map) { // 泛型兼容? // JSONObject
488+
types[i] = Map.class;
489+
//性能比较差
490+
//values[i] = TypeUtils.cast(v, Map.class, ParserConfig.getGlobalInstance());
434491
}
435-
else if (v instanceof JSONArray) { // Collection) {
436-
types[i] = JSONArray.class;
437-
//性能比较差 values[i] = request.getJSONArray(keys[i]);
492+
else if (v instanceof Collection) { // 泛型兼容? // JSONArray
493+
types[i] = List.class;
494+
//性能比较差
495+
values[i] = TypeUtils.cast(v, List.class, ParserConfig.getGlobalInstance());
438496
}
439-
else { //FIXME 碰到null就挂了!!!
440-
throw new UnsupportedDataTypeException(keys[i] + ":value 中value不合法!远程函数 key():" + function + " 中的arg对应的值类型"
441-
+ "只能是 [Boolean, Number, String, JSONObject, JSONArray] 中的一种!");
497+
else {
498+
throw new UnsupportedDataTypeException(keys[i] + ":value 中value不合法!远程函数 key():"
499+
+ function + " 中的 arg 对应的值类型只能是 [Boolean, Number, String, JSONObject, JSONArray] 中的一种!");
442500
}
443501
}
444502
}
@@ -485,6 +543,46 @@ public static String getFunction(String method, String[] keys) {
485543
return f;
486544
}
487545

546+
public static <T> T getArgValue(@NotNull JSONObject currentObject, String keyOrValue) {
547+
return getArgValue(currentObject, keyOrValue, false);
548+
}
549+
public static <T> T getArgValue(@NotNull JSONObject currentObject, String keyOrValue, boolean containRaw) {
550+
if (keyOrValue == null) {
551+
return null;
552+
}
553+
554+
if (keyOrValue.endsWith("`") && keyOrValue.lastIndexOf("`") == 0) {
555+
return (T) currentObject.get(keyOrValue.substring(1, keyOrValue.length() - 1));
556+
}
557+
558+
if (keyOrValue.endsWith("'") && keyOrValue.lastIndexOf("'") == 0) {
559+
return (T) keyOrValue.substring(1, keyOrValue.length() - 1);
560+
}
561+
562+
if (StringUtil.isName(keyOrValue.startsWith("@") ? keyOrValue.substring(1) : keyOrValue)) {
563+
return (T) currentObject.get(keyOrValue);
564+
}
565+
566+
// 传参加上 @raw:"key()" 避免意外情况
567+
Object val = containRaw ? AbstractSQLConfig.RAW_MAP.get(keyOrValue) : null;
568+
if (val != null) {
569+
return (T) ("".equals(val) ? keyOrValue : val);
570+
}
571+
572+
try {
573+
val = JSON.parse(keyOrValue);
574+
if (apijson.JSON.isBooleanOrNumberOrString(val)) {
575+
return (T) val;
576+
}
577+
}
578+
catch (Throwable e) {
579+
Log.d(TAG, "getArgValue try {\n" +
580+
" Object val = JSON.parse(keyOrValue);" +
581+
"} catch (Throwable e) = " + e.getMessage());
582+
}
583+
584+
return (T) currentObject.get(keyOrValue);
585+
}
488586

489587
public static class FunctionBean {
490588
private String function;

APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ public AbstractObjectParser(@NotNull JSONObject request, String parentPath, SQLC
105105
request.remove(KEY_DROP);
106106
}
107107

108+
String raw = request.getString(JSONRequest.KEY_RAW);
109+
String[] rks = StringUtil.split(raw);
110+
rawKeyList = rks == null || rks.length <= 0 ? null : Arrays.asList(rks);
108111
}
109112

110113
@Override
@@ -172,6 +175,8 @@ public boolean isBreakParse() {
172175

173176
private int objectCount;
174177
private int arrayCount;
178+
179+
private List<String> rawKeyList;
175180
/**解析成员
176181
* response重新赋值
177182
* @return null or this
@@ -452,7 +457,7 @@ else if (isPlus) {
452457
}
453458

454459
if (isPlus == false && isTable == false) {
455-
parseFunction(k, (String) value, parentPath, name, request, isMinus);
460+
parseFunction(key, k, (String) value, parentPath, name, request, isMinus);
456461
}
457462
else {
458463
//远程函数比较少用,一般一个Table:{}内用到也就一两个,所以这里循环里new出来对性能影响不大。
@@ -795,19 +800,22 @@ public void onFunctionResponse(String type) throws Exception {
795800
JSONObject json = isMinus ? sqlRequest : response; // key-():function 是实时执行,而不是在这里批量执行
796801

797802
for (Entry<String, String> entry : functionSet) {
798-
parseFunction(entry.getKey(), entry.getValue(), parentPath, name, json, isMinus);
803+
parseFunction(entry.getKey(), entry.getKey(), entry.getValue(), parentPath, name, json, isMinus);
799804
}
800805
}
801806
}
802807

808+
803809
//public void parseFunction(String key, String value, String parentPath, String currentName, JSONObject currentObject) throws Exception {
804810
// parseFunction(key, value, parentPath, currentName, currentObject, false);
805811
//}
806-
public void parseFunction(String key, String value, String parentPath, String currentName, JSONObject currentObject, boolean isMinus) throws Exception {
812+
public void parseFunction(String rawKey, String key, String value, String parentPath, String currentName, JSONObject currentObject, boolean isMinus) throws Exception {
807813
Object result;
814+
boolean containRaw = rawKeyList != null && rawKeyList.contains(rawKey);
815+
808816
boolean isProcedure = key.startsWith("@");
809817
if (isProcedure) {
810-
FunctionBean fb = AbstractFunctionParser.parseFunction(value, currentObject, true);
818+
FunctionBean fb = AbstractFunctionParser.parseFunction(value, currentObject, true, containRaw);
811819

812820
SQLConfig config = newSQLConfig(true);
813821
config.setProcedure(fb.toFunctionCallString(true));
@@ -816,7 +824,7 @@ public void parseFunction(String key, String value, String parentPath, String cu
816824
key = key.substring(1);
817825
}
818826
else {
819-
result = parser.onFunctionParse(key, value, parentPath, currentName, currentObject);
827+
result = parser.onFunctionParse(key, value, parentPath, currentName, currentObject, containRaw);
820828
}
821829

822830
String k = AbstractSQLConfig.getRealKey(method, key, false, false);

APIJSONORM/src/main/java/apijson/orm/FunctionParser.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
public interface FunctionParser {
1818

1919
Object invoke(@NotNull String function, @NotNull JSONObject currentObject) throws Exception;
20-
20+
Object invoke(@NotNull String function, @NotNull JSONObject currentObject, boolean containRaw) throws Exception;
21+
2122
RequestMethod getMethod();
2223
FunctionParser setMethod(RequestMethod method);
2324

APIJSONORM/src/main/java/apijson/orm/Parser.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ JSONObject parseCorrectRequest(RequestMethod method, String tag, int version, St
7979
* @return
8080
* @throws Exception
8181
*/
82-
Object onFunctionParse(String key, String function, String parentPath, String currentName, JSONObject currentObject) throws Exception;
82+
Object onFunctionParse(String key, String function, String parentPath, String currentName, JSONObject currentObject, boolean containRaw) throws Exception;
8383

8484
ObjectParser createObjectParser(JSONObject request, String parentPath, SQLConfig arrayConfig, boolean isSubquery, boolean isTable, boolean isArrayMainTable) throws Exception;
8585

0 commit comments

Comments
 (0)