
zikai.apijson.core.orm.AbstractFunctionParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of zikai-apijson Show documentation
Show all versions of zikai-apijson Show documentation
apijson的简化版本,升级fastjson到2.0
The newest version!
/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
This source code is licensed under the Apache License Version 2.0.*/
package zikai.apijson.core.orm;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.activation.UnsupportedDataTypeException;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import zikai.apijson.core.Log;
import zikai.apijson.core.NotNull;
import zikai.apijson.core.RequestMethod;
import zikai.apijson.core.StringUtil;
/**可远程调用的函数类
* @author Lemon
*/
public class AbstractFunctionParser implements FunctionParser {
// private static final String TAG = "AbstractFunctionParser";
//
// >
public static Map FUNCTION_MAP;
static {
FUNCTION_MAP = new HashMap<>();
}
private RequestMethod method;
private String tag;
private int version;
private JSONObject request;
public AbstractFunctionParser() {
this(null, null, 0, null);
}
public AbstractFunctionParser(RequestMethod method, String tag, int version, @NotNull JSONObject request) {
setMethod(method == null ? RequestMethod.GET : method);
setTag(tag);
setVersion(version);
setRequest(request);
}
@Override
public RequestMethod getMethod() {
return method;
}
@Override
public AbstractFunctionParser setMethod(RequestMethod method) {
this.method = method;
return this;
}
@Override
public String getTag() {
return tag;
}
@Override
public AbstractFunctionParser setTag(String tag) {
this.tag = tag;
return this;
}
@Override
public int getVersion() {
return version;
}
@Override
public AbstractFunctionParser setVersion(int version) {
this.version = version;
return this;
}
private String key;
@Override
public String getKey() {
return key;
}
@Override
public AbstractFunctionParser setKey(String key) {
this.key = key;
return this;
}
private String parentPath;
@Override
public String getParentPath() {
return parentPath;
}
@Override
public AbstractFunctionParser setParentPath(String parentPath) {
this.parentPath = parentPath;
return this;
}
private String currentName;
@Override
public String getCurrentName() {
return currentName;
}
@Override
public AbstractFunctionParser setCurrentName(String currentName) {
this.currentName = currentName;
return this;
}
@NotNull
@Override
public JSONObject getRequest() {
return request;
}
@Override
public AbstractFunctionParser setRequest(@NotNull JSONObject request) {
this.request = request;
return this;
}
private JSONObject currentObject;
@NotNull
@Override
public JSONObject getCurrentObject() {
return currentObject;
}
@Override
public AbstractFunctionParser setCurrentObject(@NotNull JSONObject currentObject) {
this.currentObject = currentObject;
return this;
}
/**反射调用
* @param function 例如get(object,key),参数只允许引用,不能直接传值
* @param currentObject 不作为第一个参数,就不能远程调用invoke,避免死循环
* @return {@link #invoke(AbstractFunctionParser, String, JSONObject)}
*/
@Override
public Object invoke(@NotNull String function, @NotNull JSONObject currentObject) throws Exception {
return invoke(this, function, currentObject);
}
/**反射调用
* @param parser
* @param request
* @param function 例如get(Map:map,key),参数只允许引用,不能直接传值
* @return {@link #invoke(AbstractFunctionParser, String, Class[], Object[])}
*/
public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String function, @NotNull JSONObject currentObject) throws Exception {
FunctionBean fb = parseFunction(function, currentObject, false);
JSONObject row = FUNCTION_MAP.get(fb.getMethod());
if (row == null) {
throw new UnsupportedOperationException("不允许调用远程函数 " + fb.getMethod() + " !");
}
int v = row.getIntValue("version");
if (parser.getVersion() < v) {
throw new UnsupportedOperationException("不允许 version = " + parser.getVersion() + " 的请求调用远程函数 " + fb.getMethod() + " ! 必须满足 version >= " + v + " !");
}
String t = row.getString("tag");
if (t != null && !t.equals(parser.getTag())) {
throw new UnsupportedOperationException("不允许 tag = " + parser.getTag() + " 的请求调用远程函数 " + fb.getMethod() + " ! 必须满足 tag = " + t + " !");
}
String[] methods = StringUtil.split(row.getString("methods"));
List ml = methods == null || methods.length <= 0 ? null : Arrays.asList(methods);
if (ml != null && !ml.contains(parser.getMethod().toString())) {
throw new UnsupportedOperationException("不允许 method = " + parser.getMethod() + " 的请求调用远程函数 " + fb.getMethod() + " ! 必须满足 method 在 " + Arrays.toString(methods) + "内 !");
}
try {
return invoke(parser, fb.getMethod(), fb.getTypes(), fb.getValues());
} catch (Exception e) {
if (e instanceof NoSuchMethodException) {
throw new IllegalArgumentException("字符 " + function + " 对应的远程函数 " + getFunction(fb.getMethod(), fb.getKeys()) + " 不在后端工程的DemoFunction内!"
+ "\n请检查函数名和参数数量是否与已定义的函数一致!"
+ "\n且必须为 function(key0,key1,...) 这种单函数格式!"
+ "\nfunction必须符合Java函数命名,key是用于在request内取值的键!"
+ "\n调用时不要有空格!" + (Log.DEBUG ? e.getMessage() : ""));
}
if (e instanceof InvocationTargetException) {
Throwable te = ((InvocationTargetException) e).getTargetException();
if (StringUtil.isNotEmpty(te.getMessage(), true)) { //到处把函数声明throws Exception改成throws Throwable挺麻烦
throw te instanceof Exception ? (Exception) te : new Exception(te.getMessage());
}
throw new IllegalArgumentException("字符 " + function + " 对应的远程函数传参类型错误!"
+ "\n请检查 key:value 中value的类型是否满足已定义的函数 " + getFunction(fb.getMethod(), fb.getKeys()) + " 的要求!"
+ (Log.DEBUG ? e.getMessage() : ""));
}
throw e;
}
}
/**反射调用
* @param methodName
* @param parameterTypes
* @param args
* @return
*/
public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String methodName, @NotNull Class>[] parameterTypes, @NotNull Object[] args) throws Exception {
return parser.getClass().getMethod(methodName, parameterTypes).invoke(parser, args);
}
/**解析函数
* @param function
* @param request
* @param isSQLFunction
* @return
* @throws Exception
*/
@NotNull
public static FunctionBean parseFunction(@NotNull String function, @NotNull JSONObject request, boolean isSQLFunction) throws Exception {
int start = function.indexOf("(");
int end = function.lastIndexOf(")");
String method = (start <= 0 || end != function.length() - 1) ? null : function.substring(0, start);
if (StringUtil.isEmpty(method, true)) {
throw new IllegalArgumentException("字符 " + function + " 不合法!函数的名称 function 不能为空,"
+ "且必须为 function(key0,key1,...) 这种单函数格式!"
+ "\nfunction必须符合 " + (isSQLFunction ? "SQL 函数/SQL 存储过程" : "Java 函数") + " 命名,key 是用于在 request 内取值的键!");
}
String[] keys = StringUtil.split(function.substring(start + 1, end));
int length = keys == null ? 0 : keys.length;
Class>[] types;
Object[] values;
if (isSQLFunction) {
types = new Class>[length];
values = new Object[length];
//碰到null就挂了!!!Number还得各种转换不灵活!不如直接传request和对应的key到函数里,函数内实现时自己 getLongValue,getJSONObject ...
Object v;
for (int i = 0; i < length; i++) {
v = values[i] = request.get(keys[i]);
if (v == null) {
types[i] = Object.class;
values[i] = null;
break;
}
if (v instanceof Boolean) {
types[i] = Boolean.class; //只支持JSON的几种类型
}
else if (v instanceof Number) {
types[i] = Number.class;
}
else if (v instanceof String) {
types[i] = String.class;
}
else if (v instanceof JSONObject) { // Map) {
types[i] = JSONObject.class;
//性能比较差 values[i] = request.getJSONObject(keys[i]);
}
else if (v instanceof JSONArray) { // Collection) {
types[i] = JSONArray.class;
//性能比较差 values[i] = request.getJSONArray(keys[i]);
}
else { //FIXME 碰到null就挂了!!!
throw new UnsupportedDataTypeException(keys[i] + ":value 中value不合法!远程函数 key():" + function + " 中的arg对应的值类型"
+ "只能是 [Boolean, Number, String, JSONObject, JSONArray] 中的一种!");
}
}
}
else {
types = new Class>[length + 1];
types[0] = JSONObject.class;
values = new Object[length + 1];
values[0] = request;
for (int i = 0; i < length; i++) {
types[i + 1] = String.class;
values[i + 1] = keys[i];
}
}
FunctionBean fb = new FunctionBean();
fb.setFunction(function);
fb.setMethod(method);
fb.setKeys(keys);
fb.setTypes(types);
fb.setValues(values);
return fb;
}
/**
* @param method
* @param keys
* @return
*/
public static String getFunction(String method, String[] keys) {
String f = method + "(JSONObject request";
if (keys != null) {
for (int i = 0; i < keys.length; i++) {
f += (", String " + keys[i]);
}
}
f += ")";
return f;
}
public static class FunctionBean {
private String function;
private String method;
private String[] keys;
private Class>[] types;
private Object[] values;
public String getFunction() {
return function;
}
public void setFunction(String function) {
this.function = function;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String[] getKeys() {
return keys;
}
public void setKeys(String[] keys) {
this.keys = keys;
}
public Class>[] getTypes() {
return types;
}
public void setTypes(Class>[] types) {
this.types = types;
}
public Object[] getValues() {
return values;
}
public void setValues(Object[] values) {
this.values = values;
}
/**
* @param useValue
* @return
*/
public String toFunctionCallString(boolean useValue) {
return toFunctionCallString(useValue, null);
}
/**
* @param useValue
* @param quote
* @return
*/
public String toFunctionCallString(boolean useValue, String quote) {
String s = getMethod() + "(";
Object[] args = useValue ? getValues() : getKeys();
if (args != null && args.length > 0) {
if (quote == null) {
quote = "'";
}
Object arg;
for (int i = 0; i < args.length; i++) {
arg = args[i];
s += (i <= 0 ? "" : ",") + (arg instanceof Boolean || arg instanceof Number ? arg : quote + arg + quote);
}
}
return s + ")";
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy