远程函数:支持自动且智能解析参数值,兼容 key
, 'value' 指定键值格式;@raw 支持远程函数和存储过程
This commit is contained in:
parent
88e77c23a3
commit
edd8570f7a
@ -10,6 +10,7 @@ import java.lang.invoke.WrongMethodTypeException;
|
|||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -22,6 +23,8 @@ import javax.script.ScriptEngineManager;
|
|||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONArray;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.alibaba.fastjson.parser.ParserConfig;
|
||||||
|
import com.alibaba.fastjson.util.TypeUtils;
|
||||||
|
|
||||||
import apijson.Log;
|
import apijson.Log;
|
||||||
import apijson.NotNull;
|
import apijson.NotNull;
|
||||||
@ -34,6 +37,10 @@ import apijson.StringUtil;
|
|||||||
public class AbstractFunctionParser implements FunctionParser {
|
public class AbstractFunctionParser implements FunctionParser {
|
||||||
private static final String TAG = "AbstractFunctionParser";
|
private static final String TAG = "AbstractFunctionParser";
|
||||||
|
|
||||||
|
/**是否解析参数 key 的对应的值,不用手动编码 curObj.getString(key)
|
||||||
|
*/
|
||||||
|
public static boolean IS_PARSE_ARG_VALUE = false;
|
||||||
|
|
||||||
/**开启支持远程函数
|
/**开启支持远程函数
|
||||||
*/
|
*/
|
||||||
public static boolean ENABLE_REMOTE_FUNCTION = true;
|
public static boolean ENABLE_REMOTE_FUNCTION = true;
|
||||||
@ -155,11 +162,21 @@ public class AbstractFunctionParser implements FunctionParser {
|
|||||||
/**反射调用
|
/**反射调用
|
||||||
* @param function 例如get(object,key),参数只允许引用,不能直接传值
|
* @param function 例如get(object,key),参数只允许引用,不能直接传值
|
||||||
* @param currentObject 不作为第一个参数,就不能远程调用invoke,避免死循环
|
* @param currentObject 不作为第一个参数,就不能远程调用invoke,避免死循环
|
||||||
* @return {@link #invoke(AbstractFunctionParser, String, JSONObject)}
|
* @return {@link #invoke(String, JSONObject, boolean)}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Object invoke(@NotNull String function, @NotNull JSONObject currentObject) throws Exception {
|
public Object invoke(@NotNull String function, @NotNull JSONObject currentObject) throws Exception {
|
||||||
return invoke(this, function, currentObject);
|
return invoke(function, currentObject, false);
|
||||||
|
}
|
||||||
|
/**反射调用
|
||||||
|
* @param function 例如get(object,key),参数只允许引用,不能直接传值
|
||||||
|
* @param currentObject 不作为第一个参数,就不能远程调用invoke,避免死循环
|
||||||
|
* @param containRaw 包含原始 SQL 片段
|
||||||
|
* @return {@link #invoke(AbstractFunctionParser, String, JSONObject, boolean)}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object invoke(@NotNull String function, @NotNull JSONObject currentObject, boolean containRaw) throws Exception {
|
||||||
|
return invoke(this, function, currentObject, containRaw);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**反射调用
|
/**反射调用
|
||||||
@ -168,13 +185,13 @@ public class AbstractFunctionParser implements FunctionParser {
|
|||||||
* @param currentObject
|
* @param currentObject
|
||||||
* @return {@link #invoke(AbstractFunctionParser, String, Class[], Object[])}
|
* @return {@link #invoke(AbstractFunctionParser, String, Class[], Object[])}
|
||||||
*/
|
*/
|
||||||
public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String function, @NotNull JSONObject currentObject) throws Exception {
|
public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String function, @NotNull JSONObject currentObject, boolean containRaw) throws Exception {
|
||||||
if (ENABLE_REMOTE_FUNCTION == false) {
|
if (ENABLE_REMOTE_FUNCTION == false) {
|
||||||
throw new UnsupportedOperationException("AbstractFunctionParser.ENABLE_REMOTE_FUNCTION" +
|
throw new UnsupportedOperationException("AbstractFunctionParser.ENABLE_REMOTE_FUNCTION" +
|
||||||
" == false 时不支持远程函数!如需支持则设置 AbstractFunctionParser.ENABLE_REMOTE_FUNCTION = true !");
|
" == false 时不支持远程函数!如需支持则设置 AbstractFunctionParser.ENABLE_REMOTE_FUNCTION = true !");
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionBean fb = parseFunction(function, currentObject, false);
|
FunctionBean fb = parseFunction(function, currentObject, false, containRaw);
|
||||||
|
|
||||||
JSONObject row = FUNCTION_MAP.get(fb.getMethod());
|
JSONObject row = FUNCTION_MAP.get(fb.getMethod());
|
||||||
if (row == null) {
|
if (row == null) {
|
||||||
@ -230,17 +247,31 @@ public class AbstractFunctionParser implements FunctionParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**反射调用
|
/**反射调用
|
||||||
* @param methodName
|
* @param parser
|
||||||
* @param parameterTypes
|
* @param methodName
|
||||||
* @param args
|
* @param parameterTypes
|
||||||
* @return
|
* @param args
|
||||||
*/
|
* @return {@link #invoke(AbstractFunctionParser, String, Class[], Object[], String, JSONObject, int)}
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String methodName
|
public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String methodName
|
||||||
, @NotNull Class<?>[] parameterTypes, @NotNull Object[] args) throws Exception {
|
, @NotNull Class<?>[] parameterTypes, @NotNull Object[] args) throws Exception {
|
||||||
return invoke(parser, methodName, parameterTypes, args, null, null, TYPE_REMOTE_FUNCTION);
|
return invoke(parser, methodName, parameterTypes, args, null, null, TYPE_REMOTE_FUNCTION);
|
||||||
}
|
}
|
||||||
|
/**反射调用
|
||||||
|
* @param parser
|
||||||
|
* @param methodName
|
||||||
|
* @param parameterTypes
|
||||||
|
* @param args
|
||||||
|
* @param returnType
|
||||||
|
* @param currentObject
|
||||||
|
* @param type
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String methodName
|
public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String methodName
|
||||||
, @NotNull Class<?>[] parameterTypes, @NotNull Object[] args, String returnType, JSONObject currentObject, int type) throws Exception {
|
, @NotNull Class<?>[] parameterTypes, @NotNull Object[] args, String returnType
|
||||||
|
, JSONObject currentObject, int type) throws Exception {
|
||||||
if (type == TYPE_SCRIPT_FUNCTION) {
|
if (type == TYPE_SCRIPT_FUNCTION) {
|
||||||
return invokeScript(parser, methodName, parameterTypes, args, returnType, currentObject);
|
return invokeScript(parser, methodName, parameterTypes, args, returnType, currentObject);
|
||||||
}
|
}
|
||||||
@ -276,11 +307,22 @@ public class AbstractFunctionParser implements FunctionParser {
|
|||||||
/*获取执行JavaScript的执行引擎*/
|
/*获取执行JavaScript的执行引擎*/
|
||||||
SCRIPT_ENGINE = new ScriptEngineManager().getEngineByName("javascript");
|
SCRIPT_ENGINE = new ScriptEngineManager().getEngineByName("javascript");
|
||||||
INVOCABLE = (Invocable) SCRIPT_ENGINE;
|
INVOCABLE = (Invocable) SCRIPT_ENGINE;
|
||||||
} catch (Exception e) {
|
}
|
||||||
|
catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**Java 调用 JavaScript 函数
|
||||||
|
* @param parser
|
||||||
|
* @param methodName
|
||||||
|
* @param parameterTypes
|
||||||
|
* @param args
|
||||||
|
* @param returnType
|
||||||
|
* @param currentObject
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
public static Object invokeScript(@NotNull AbstractFunctionParser parser, @NotNull String methodName
|
public static Object invokeScript(@NotNull AbstractFunctionParser parser, @NotNull String methodName
|
||||||
, @NotNull Class<?>[] parameterTypes, @NotNull Object[] args, String returnType, JSONObject currentObject) throws Exception {
|
, @NotNull Class<?>[] parameterTypes, @NotNull Object[] args, String returnType, JSONObject currentObject) throws Exception {
|
||||||
JSONObject row = SCRIPT_MAP.get(methodName);
|
JSONObject row = SCRIPT_MAP.get(methodName);
|
||||||
@ -388,6 +430,17 @@ public class AbstractFunctionParser implements FunctionParser {
|
|||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
public static FunctionBean parseFunction(@NotNull String function, @NotNull JSONObject request, boolean isSQLFunction) throws Exception {
|
public static FunctionBean parseFunction(@NotNull String function, @NotNull JSONObject request, boolean isSQLFunction) throws Exception {
|
||||||
|
return parseFunction(function, request, isSQLFunction, false);
|
||||||
|
}
|
||||||
|
/**解析函数,自动解析的值类型只支持 Boolean, Number, String, Map, List
|
||||||
|
* @param function
|
||||||
|
* @param request
|
||||||
|
* @param isSQLFunction
|
||||||
|
* @param containRaw
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static FunctionBean parseFunction(@NotNull String function, @NotNull JSONObject request, boolean isSQLFunction, boolean containRaw) throws Exception {
|
||||||
|
|
||||||
int start = function.indexOf("(");
|
int start = function.indexOf("(");
|
||||||
int end = function.lastIndexOf(")");
|
int end = function.lastIndexOf(")");
|
||||||
@ -405,14 +458,14 @@ public class AbstractFunctionParser implements FunctionParser {
|
|||||||
Class<?>[] types;
|
Class<?>[] types;
|
||||||
Object[] values;
|
Object[] values;
|
||||||
|
|
||||||
if (isSQLFunction) {
|
if (isSQLFunction || IS_PARSE_ARG_VALUE) {
|
||||||
types = new Class<?>[length];
|
types = new Class<?>[length];
|
||||||
values = new Object[length];
|
values = new Object[length];
|
||||||
|
|
||||||
//碰到null就挂了!!!Number还得各种转换不灵活!不如直接传request和对应的key到函数里,函数内实现时自己 getLongValue,getJSONObject ...
|
//碰到null就挂了!!!Number还得各种转换不灵活!不如直接传request和对应的key到函数里,函数内实现时自己 getLongValue,getJSONObject ...
|
||||||
Object v;
|
Object v;
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
v = values[i] = request.get(keys[i]);
|
v = values[i] = getArgValue(request, keys[i], containRaw); // request.get(keys[i]);
|
||||||
if (v == null) {
|
if (v == null) {
|
||||||
types[i] = Object.class;
|
types[i] = Object.class;
|
||||||
values[i] = null;
|
values[i] = null;
|
||||||
@ -421,24 +474,29 @@ public class AbstractFunctionParser implements FunctionParser {
|
|||||||
|
|
||||||
if (v instanceof Boolean) {
|
if (v instanceof Boolean) {
|
||||||
types[i] = Boolean.class; //只支持JSON的几种类型
|
types[i] = Boolean.class; //只支持JSON的几种类型
|
||||||
}
|
} // 怎么都有 bug,如果是引用的值,很多情况下无法指定 // 用 1L 指定为 Long ? 其它的默认按长度分配为 Integer 或 Long?
|
||||||
|
//else if (v instanceof Long || v instanceof Integer || v instanceof Short) {
|
||||||
|
// types[i] = Long.class;
|
||||||
|
//}
|
||||||
else if (v instanceof Number) {
|
else if (v instanceof Number) {
|
||||||
types[i] = Number.class;
|
types[i] = Number.class;
|
||||||
}
|
}
|
||||||
else if (v instanceof String) {
|
else if (v instanceof String) {
|
||||||
types[i] = String.class;
|
types[i] = String.class;
|
||||||
}
|
}
|
||||||
else if (v instanceof JSONObject) { // Map) {
|
else if (v instanceof Map) { // 泛型兼容? // JSONObject
|
||||||
types[i] = JSONObject.class;
|
types[i] = Map.class;
|
||||||
//性能比较差 values[i] = request.getJSONObject(keys[i]);
|
//性能比较差
|
||||||
|
//values[i] = TypeUtils.cast(v, Map.class, ParserConfig.getGlobalInstance());
|
||||||
}
|
}
|
||||||
else if (v instanceof JSONArray) { // Collection) {
|
else if (v instanceof Collection) { // 泛型兼容? // JSONArray
|
||||||
types[i] = JSONArray.class;
|
types[i] = List.class;
|
||||||
//性能比较差 values[i] = request.getJSONArray(keys[i]);
|
//性能比较差
|
||||||
|
values[i] = TypeUtils.cast(v, List.class, ParserConfig.getGlobalInstance());
|
||||||
}
|
}
|
||||||
else { //FIXME 碰到null就挂了!!!
|
else {
|
||||||
throw new UnsupportedDataTypeException(keys[i] + ":value 中value不合法!远程函数 key():" + function + " 中的arg对应的值类型"
|
throw new UnsupportedDataTypeException(keys[i] + ":value 中value不合法!远程函数 key():"
|
||||||
+ "只能是 [Boolean, Number, String, JSONObject, JSONArray] 中的一种!");
|
+ function + " 中的 arg 对应的值类型只能是 [Boolean, Number, String, JSONObject, JSONArray] 中的一种!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -485,6 +543,46 @@ public class AbstractFunctionParser implements FunctionParser {
|
|||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> T getArgValue(@NotNull JSONObject currentObject, String keyOrValue) {
|
||||||
|
return getArgValue(currentObject, keyOrValue, false);
|
||||||
|
}
|
||||||
|
public static <T> T getArgValue(@NotNull JSONObject currentObject, String keyOrValue, boolean containRaw) {
|
||||||
|
if (keyOrValue == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyOrValue.endsWith("`") && keyOrValue.lastIndexOf("`") == 0) {
|
||||||
|
return (T) currentObject.get(keyOrValue.substring(1, keyOrValue.length() - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyOrValue.endsWith("'") && keyOrValue.lastIndexOf("'") == 0) {
|
||||||
|
return (T) keyOrValue.substring(1, keyOrValue.length() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtil.isName(keyOrValue.startsWith("@") ? keyOrValue.substring(1) : keyOrValue)) {
|
||||||
|
return (T) currentObject.get(keyOrValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 传参加上 @raw:"key()" 避免意外情况
|
||||||
|
Object val = containRaw ? AbstractSQLConfig.RAW_MAP.get(keyOrValue) : null;
|
||||||
|
if (val != null) {
|
||||||
|
return (T) ("".equals(val) ? keyOrValue : val);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
val = JSON.parse(keyOrValue);
|
||||||
|
if (apijson.JSON.isBooleanOrNumberOrString(val)) {
|
||||||
|
return (T) val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Throwable e) {
|
||||||
|
Log.d(TAG, "getArgValue try {\n" +
|
||||||
|
" Object val = JSON.parse(keyOrValue);" +
|
||||||
|
"} catch (Throwable e) = " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (T) currentObject.get(keyOrValue);
|
||||||
|
}
|
||||||
|
|
||||||
public static class FunctionBean {
|
public static class FunctionBean {
|
||||||
private String function;
|
private String function;
|
||||||
|
@ -105,6 +105,9 @@ public abstract class AbstractObjectParser implements ObjectParser {
|
|||||||
request.remove(KEY_DROP);
|
request.remove(KEY_DROP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String raw = request.getString(JSONRequest.KEY_RAW);
|
||||||
|
String[] rks = StringUtil.split(raw);
|
||||||
|
rawKeyList = rks == null || rks.length <= 0 ? null : Arrays.asList(rks);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -172,6 +175,8 @@ public abstract class AbstractObjectParser implements ObjectParser {
|
|||||||
|
|
||||||
private int objectCount;
|
private int objectCount;
|
||||||
private int arrayCount;
|
private int arrayCount;
|
||||||
|
|
||||||
|
private List<String> rawKeyList;
|
||||||
/**解析成员
|
/**解析成员
|
||||||
* response重新赋值
|
* response重新赋值
|
||||||
* @return null or this
|
* @return null or this
|
||||||
@ -452,7 +457,7 @@ public abstract class AbstractObjectParser implements ObjectParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isPlus == false && isTable == false) {
|
if (isPlus == false && isTable == false) {
|
||||||
parseFunction(k, (String) value, parentPath, name, request, isMinus);
|
parseFunction(key, k, (String) value, parentPath, name, request, isMinus);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//远程函数比较少用,一般一个Table:{}内用到也就一两个,所以这里循环里new出来对性能影响不大。
|
//远程函数比较少用,一般一个Table:{}内用到也就一两个,所以这里循环里new出来对性能影响不大。
|
||||||
@ -795,19 +800,22 @@ public abstract class AbstractObjectParser implements ObjectParser {
|
|||||||
JSONObject json = isMinus ? sqlRequest : response; // key-():function 是实时执行,而不是在这里批量执行
|
JSONObject json = isMinus ? sqlRequest : response; // key-():function 是实时执行,而不是在这里批量执行
|
||||||
|
|
||||||
for (Entry<String, String> entry : functionSet) {
|
for (Entry<String, String> entry : functionSet) {
|
||||||
parseFunction(entry.getKey(), entry.getValue(), parentPath, name, json, isMinus);
|
parseFunction(entry.getKey(), entry.getKey(), entry.getValue(), parentPath, name, json, isMinus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//public void parseFunction(String key, String value, String parentPath, String currentName, JSONObject currentObject) throws Exception {
|
//public void parseFunction(String key, String value, String parentPath, String currentName, JSONObject currentObject) throws Exception {
|
||||||
// parseFunction(key, value, parentPath, currentName, currentObject, false);
|
// parseFunction(key, value, parentPath, currentName, currentObject, false);
|
||||||
//}
|
//}
|
||||||
public void parseFunction(String key, String value, String parentPath, String currentName, JSONObject currentObject, boolean isMinus) throws Exception {
|
public void parseFunction(String rawKey, String key, String value, String parentPath, String currentName, JSONObject currentObject, boolean isMinus) throws Exception {
|
||||||
Object result;
|
Object result;
|
||||||
|
boolean containRaw = rawKeyList != null && rawKeyList.contains(rawKey);
|
||||||
|
|
||||||
boolean isProcedure = key.startsWith("@");
|
boolean isProcedure = key.startsWith("@");
|
||||||
if (isProcedure) {
|
if (isProcedure) {
|
||||||
FunctionBean fb = AbstractFunctionParser.parseFunction(value, currentObject, true);
|
FunctionBean fb = AbstractFunctionParser.parseFunction(value, currentObject, true, containRaw);
|
||||||
|
|
||||||
SQLConfig config = newSQLConfig(true);
|
SQLConfig config = newSQLConfig(true);
|
||||||
config.setProcedure(fb.toFunctionCallString(true));
|
config.setProcedure(fb.toFunctionCallString(true));
|
||||||
@ -816,7 +824,7 @@ public abstract class AbstractObjectParser implements ObjectParser {
|
|||||||
key = key.substring(1);
|
key = key.substring(1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result = parser.onFunctionParse(key, value, parentPath, currentName, currentObject);
|
result = parser.onFunctionParse(key, value, parentPath, currentName, currentObject, containRaw);
|
||||||
}
|
}
|
||||||
|
|
||||||
String k = AbstractSQLConfig.getRealKey(method, key, false, false);
|
String k = AbstractSQLConfig.getRealKey(method, key, false, false);
|
||||||
|
@ -17,7 +17,8 @@ import apijson.RequestMethod;
|
|||||||
public interface FunctionParser {
|
public interface FunctionParser {
|
||||||
|
|
||||||
Object invoke(@NotNull String function, @NotNull JSONObject currentObject) throws Exception;
|
Object invoke(@NotNull String function, @NotNull JSONObject currentObject) throws Exception;
|
||||||
|
Object invoke(@NotNull String function, @NotNull JSONObject currentObject, boolean containRaw) throws Exception;
|
||||||
|
|
||||||
RequestMethod getMethod();
|
RequestMethod getMethod();
|
||||||
FunctionParser setMethod(RequestMethod method);
|
FunctionParser setMethod(RequestMethod method);
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ public interface Parser<T extends Object> {
|
|||||||
* @return
|
* @return
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
Object onFunctionParse(String key, String function, String parentPath, String currentName, JSONObject currentObject) throws Exception;
|
Object onFunctionParse(String key, String function, String parentPath, String currentName, JSONObject currentObject, boolean containRaw) throws Exception;
|
||||||
|
|
||||||
ObjectParser createObjectParser(JSONObject request, String parentPath, SQLConfig arrayConfig, boolean isSubquery, boolean isTable, boolean isArrayMainTable) throws Exception;
|
ObjectParser createObjectParser(JSONObject request, String parentPath, SQLConfig arrayConfig, boolean isSubquery, boolean isTable, boolean isArrayMainTable) throws Exception;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user