diff --git a/APIJSONORM/README.md b/APIJSONORM/README.md index 8007c02c3..0cb431e27 100644 --- a/APIJSONORM/README.md +++ b/APIJSONORM/README.md @@ -1,4 +1,4 @@ -# APIJSONORM [![](https://jitpack.io/v/Tencent/APIJSON.svg)](https://jitpack.io/#Tencent/APIJSON) +# APIJSONORM [![](https://jitpack.io/v/Tencent/APIJSON.svg)](https://jitpack.io/#Tencent/APIJSON) [Ask DeepWiki.com](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. diff --git a/APIJSONORM/pom.xml b/APIJSONORM/pom.xml index 391319beb..bd340fa5f 100644 --- a/APIJSONORM/pom.xml +++ b/APIJSONORM/pom.xml @@ -5,7 +5,7 @@ com.github.Tencent APIJSON - 8.0.0 + 8.0.2 jar APIJSONORM diff --git a/APIJSONORM/src/main/java/apijson/JSON.java b/APIJSONORM/src/main/java/apijson/JSON.java index c2039c958..0a14e0420 100755 --- a/APIJSONORM/src/main/java/apijson/JSON.java +++ b/APIJSONORM/src/main/java/apijson/JSON.java @@ -1,9 +1,11 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ package apijson; +import java.util.Collection; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -11,60 +13,68 @@ * @author Lemon */ public class JSON { - public static Class JSON_OBJECT_CLASS = JSONObject.class; - public static Class JSON_ARRAY_CLASS = JSONArray.class; static final String TAG = "JSON"; public static JSONParser, ? extends List> DEFAULT_JSON_PARSER; static { - DEFAULT_JSON_PARSER = new JSONParser() { - - @Override - public JSONObject createJSONObject() { - return new JSONObject(); - } - - @Override - public JSONArray createJSONArray() { - return new JSONArray(); - } - - @Override - public String toJSONString(Object obj, boolean format) { - throw new UnsupportedOperationException(); - } - - @Override - public Object parseJSON(Object json) { - throw new UnsupportedOperationException(); - } - - @Override - public JSONObject parseObject(Object json) { - throw new UnsupportedOperationException(); - } - - @Override - public T parseObject(Object json, Class clazz) { - throw new UnsupportedOperationException(); - } - - @Override - public JSONArray parseArray(Object json) { - throw new UnsupportedOperationException(); - } - - @Override - public List parseArray(Object json, Class clazz) { - throw new UnsupportedOperationException(); - } + //DEFAULT_JSON_PARSER = new JSONParser, List>() { + // + // @Override + // public LinkedHashMap createJSONObject() { + // throw new UnsupportedOperationException(); + // } + // + // @Override + // public List createJSONArray() { + // throw new UnsupportedOperationException(); + // } + // + // @Override + // public String toJSONString(Object obj, boolean format) { + // throw new UnsupportedOperationException(); + // } + // + // @Override + // public Object parse(Object json) { + // throw new UnsupportedOperationException(); + // } + // + // @Override + // public LinkedHashMap parseObject(Object json) { + // throw new UnsupportedOperationException(); + // } + // + // @Override + // public T parseObject(Object json, Class clazz) { + // throw new UnsupportedOperationException(); + // } + // + // @Override + // public List parseArray(Object json) { + // throw new UnsupportedOperationException(); + // } + // + // @Override + // public List parseArray(Object json, Class clazz) { + // throw new UnsupportedOperationException(); + // } + // + //}; - }; } // public static JSONCreator, ? extends List> DEFAULT_JSON_CREATOR = DEFAULT_JSON_PARSER; +// public static > M newObj() { +// return createJSONObject(); +// } +// public static > M newObj(String key, Object value) { +// return createJSONObject(key, value); +// } +// public static > M newObj(Map map) { +// return createJSONObject(map); +// } public static > M createJSONObject() { return (M) DEFAULT_JSON_PARSER.createJSONObject(); @@ -76,65 +86,47 @@ public static > M createJSONObject(Map> L newArr() { + // return createJSONArray(); + //} + //public static > L newArr(Object obj) { + // return createJSONArray(obj); + //} + //public static > L newArr(List list) { + // return createJSONArray(list); + //} + public static > L createJSONArray() { return (L) DEFAULT_JSON_PARSER.createJSONArray(); } public static > L createJSONArray(Object obj) { return (L) DEFAULT_JSON_PARSER.createJSONArray(obj); } - public static > L createJSONArray(List list) { + public static > L createJSONArray(Collection list) { return (L) DEFAULT_JSON_PARSER.createJSONArray(list); } - public static Object parseJSON(Object json) { - if (json instanceof Boolean || json instanceof Number || json instanceof Enum) { - return json; - } - - String s = StringUtil.trim(toJSONString(json)); - if (s.startsWith("{")) { - return parseObject(json, DEFAULT_JSON_PARSER); - } - - if (s.startsWith("[")) { - return parseArray(json, DEFAULT_JSON_PARSER); - } - - throw new IllegalArgumentException("JSON 格式错误!" + s); + public static Object parse(Object json) { + return DEFAULT_JSON_PARSER.parse(json); } - /** - * @param json - * @return - */ - public static > M parseObject(Object json) { - return (M) parseObject(json, DEFAULT_JSON_PARSER); - } - public static , L extends List> M parseObject(Object json, JSONParser parser) { + public static > M parseObject(Object json) { String s = toJSONString(json); if (StringUtil.isEmpty(s, true)) { return null; } - return parser.parseObject(s); + return (M) DEFAULT_JSON_PARSER.parseObject(s); } public static T parseObject(Object json, Class clazz) { - return parseObject(json, clazz, DEFAULT_JSON_PARSER); - } - - public static , L extends List> T parseObject(Object json, Class clazz, JSONParser parser) { String s = toJSONString(json); if (StringUtil.isEmpty(s, true)) { return null; } - if (parser == null) { - parser = (JSONParser) DEFAULT_JSON_PARSER; - } - - return parser.parseObject(s, clazz); + return DEFAULT_JSON_PARSER.parseObject(s, clazz); } /** @@ -142,17 +134,13 @@ public static , L extends List> T parse * @return */ public static > L parseArray(Object json) { - return (L) parseArray(json, DEFAULT_JSON_PARSER); - } - - public static , L extends List> L parseArray(Object json, JSONParser parser) { String s = toJSONString(json); if (StringUtil.isEmpty(s, true)) { return null; } try { - L arr = parser.parseArray(s); + L arr = (L) DEFAULT_JSON_PARSER.parseArray(s); return arr; } catch (Exception e) { Log.i(TAG, "parseArray catch \n" + e.getMessage()); @@ -161,17 +149,13 @@ public static , L extends List> L parseArr } public static List parseArray(Object json, Class clazz) { - return parseArray(json, clazz, DEFAULT_JSON_PARSER); - } - - public static , L extends List> List parseArray(Object json, Class clazz, JSONParser parser) { String s = toJSONString(json); if (StringUtil.isEmpty(s, true)) { return null; } try { - return parser.parseArray(s, clazz); + return DEFAULT_JSON_PARSER.parseArray(s, clazz); } catch (Exception e) { Log.i(TAG, "parseArray catch \n" + e.getMessage()); } @@ -343,14 +327,14 @@ public static > L getJSONArray(List list, int ind * @throws IllegalArgumentException If value is not a Map and cannot be converted */ @SuppressWarnings("unchecked") - public static Map getMap(Map map, String key) throws IllegalArgumentException { + public static Map getMap(Map map, String key) throws IllegalArgumentException { Object value = map == null || key == null ? null : map.get(key); if (value == null) { return null; } if (value instanceof Map) { - return (Map) value; + return (Map) value; } throw new IllegalArgumentException("Value for key '" + key + "' is not a Map: " + value.getClass().getName()); @@ -364,14 +348,14 @@ public static Map getMap(Map map, String key) th * @throws IllegalArgumentException If value is not a List and cannot be converted */ @SuppressWarnings("unchecked") - public static List getList(Map map, String key) throws IllegalArgumentException { + public static List getList(Map map, String key) throws IllegalArgumentException { Object value = map == null || key == null ? null : map.get(key); if (value == null) { return null; } if (value instanceof List) { - return (List) value; + return (List) value; } throw new IllegalArgumentException("Value for key '" + key + "' is not a List: " + value.getClass().getName()); @@ -690,4 +674,18 @@ public static String getString(Map map, String key) { return value.toString(); } + + public static Object getFromObjOrArr(Object parent, String k) { + if (parent instanceof Map) { + return ((Map) parent).get(k); + } + + if (parent instanceof List) { + int j = Integer.valueOf(k); + return ((List) parent).get(j); + } + + return null; + } + } diff --git a/APIJSONORM/src/main/java/apijson/JSONArray.java b/APIJSONORM/src/main/java/apijson/JSONArray.java deleted file mode 100644 index 60c7926df..000000000 --- a/APIJSONORM/src/main/java/apijson/JSONArray.java +++ /dev/null @@ -1,376 +0,0 @@ -/*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 apijson; - -import java.util.*; - -/** - * Custom JSONArray implementation based on ArrayList to replace com.alibaba.fastjson.JSONArray - * Maintains same API as fastjson but uses standard Java List implementation - * @author Lemon - */ -public class JSONArray extends JSON implements List { - private static final String TAG = "JSONArray"; - - private ArrayList list = new ArrayList<>(); - /** - * Create an empty JSONArray - */ - public JSONArray() { - super(); - } - - private int initialCapacity = 10; - /** - * Create a JSONArray with initial capacity - * @param initialCapacity the initial capacity - */ - public JSONArray(int initialCapacity) { - this.initialCapacity = initialCapacity; - this.list = new ArrayList<>(initialCapacity); - } - - /** - * Create a JSONArray from a Collection - * @param collection the collection to copy from - */ - public JSONArray(Collection collection) { - super(); - if (collection != null) { - addAll(collection); - } - } - - /** - * Create a JSONArray from a JSON string - * @param json JSON string - */ - public JSONArray(String json) { - this(); - List list = JSON.parseArray(json); - if (list != null) { - addAll(list); - } - } - - /** - * Get a JSONObject at the specified index - * @param index the index - * @return the JSONObject or null if not a JSONObject - */ - public JSONObject getJSONObject(int index) { - if (index < 0 || index >= size()) { - return null; - } - - Object obj = get(index); - if (obj instanceof JSONObject) { - return (JSONObject) obj; - } - else if (obj instanceof Map) { - return new JSONObject(obj); - } - return null; - } - - /** - * Get a JSONArray at the specified index - * @param index the index - * @return the JSONArray or null if not a JSONArray - */ - public JSONArray getJSONArray(int index) { - if (index < 0 || index >= size()) { - return null; - } - - Object obj = get(index); - if (obj instanceof List) { - @SuppressWarnings("unchecked") - List list = (List) obj; - return new JSONArray(list); - } else if (obj instanceof List) { - return (JSONArray) obj; - } - return null; - } - - /** - * Get a boolean value at the specified index - * @param index the index - * @return the boolean value or false if not found - */ - public boolean getBooleanValue(int index) { - if (index < 0 || index >= size()) { - return false; - } - - Object obj = get(index); - if (obj instanceof Boolean) { - return (Boolean) obj; - } else if (obj instanceof Number) { - return ((Number) obj).intValue() != 0; - } else if (obj instanceof String) { - return Boolean.parseBoolean((String) obj); - } - return false; - } - - /** - * Get an integer value at the specified index - * @param index the index - * @return the integer value or 0 if not found - */ - public int getIntValue(int index) { - if (index < 0 || index >= size()) { - return 0; - } - - Object obj = get(index); - if (obj instanceof Number) { - return ((Number) obj).intValue(); - } else if (obj instanceof String) { - try { - return Integer.parseInt((String) obj); - } catch (NumberFormatException e) { - // Ignore - } - } - return 0; - } - - /** - * Get a long value at the specified index - * @param index the index - * @return the long value or 0 if not found - */ - public long getLongValue(int index) { - if (index < 0 || index >= size()) { - return 0L; - } - - Object obj = get(index); - if (obj instanceof Number) { - return ((Number) obj).longValue(); - } else if (obj instanceof String) { - try { - return Long.parseLong((String) obj); - } catch (NumberFormatException e) { - // Ignore - } - } - return 0L; - } - - /** - * Get a double value at the specified index - * @param index the index - * @return the double value or 0 if not found - */ - public double getDoubleValue(int index) { - if (index < 0 || index >= size()) { - return 0.0; - } - - Object obj = get(index); - if (obj instanceof Number) { - return ((Number) obj).doubleValue(); - } else if (obj instanceof String) { - try { - return Double.parseDouble((String) obj); - } catch (NumberFormatException e) { - // Ignore - } - } - return 0.0; - } - - /** - * Get a string value at the specified index - * @param index the index - * @return the string value or null if not found - */ - public String getString(int index) { - if (index < 0 || index >= size()) { - return null; - } - - Object obj = get(index); - return obj != null ? obj.toString() : null; - } - - /** - * Add a value to the JSONArray - * @param obj the value to add - * @return this JSONArray - */ - public JSONArray fluentAdd(Object obj) { - add(obj); - return this; - } - - @Override - public String toString() { - return JSON.toJSONString(this); - } - - @Override - public int size() { - return list.size(); - } - - @Override - public boolean isEmpty() { - return list.isEmpty(); - } - - @Override - public boolean contains(Object o) { - return list.contains(o); - } - - @Override - public Iterator iterator() { - return list.iterator(); - } - - @Override - public Object[] toArray() { - return list.toArray(); - } - - @Override - public T[] toArray(T[] a) { - return list.toArray(a); - } - - @Override - public boolean add(Object o) { - return list.add(o); - } - - @Override - public boolean remove(Object o) { - return list.remove(o); - } - - @Override - public boolean containsAll(Collection c) { - if (c == null || c.isEmpty()) { - return true; - } - return list.containsAll(c); - } - - @Override - public boolean addAll(Collection c) { - if (c == null || c.isEmpty()) { - return true; - } - return list.addAll(c); - } - - @Override - public boolean addAll(int index, Collection c) { - int sz = size(); - if (index < 0) { - index += sz; - } - - if (c == null || c.isEmpty()) { - return true; - } - return list.addAll(index, c); - } - - @Override - public boolean removeAll(Collection c) { - if (c == null || c.isEmpty()) { - return true; - } - return list.removeAll(c); - } - - @Override - public boolean retainAll(Collection c) { - if (c == null || c.isEmpty()) { - return true; - } - return list.retainAll(c); - } - - @Override - public void clear() { - list.clear(); - } - - @Override - public Object get(int index) { - int sz = size(); - if (index < 0) { - index += sz; - } - - return list.get(index); - } - - @Override - public Object set(int index, Object element) { - return list.set(index, element); - } - - @Override - public void add(int index, Object element) { - list.add(index, element); - } - - @Override - public Object remove(int index) { - int sz = size(); - if (index < 0) { - index += sz; - } - if (index >= sz) { - return null; - } - - return list.remove(index); - } - - @Override - public int indexOf(Object o) { - return list.indexOf(o); - } - - @Override - public int lastIndexOf(Object o) { - return list.lastIndexOf(o); - } - - @Override - public ListIterator listIterator() { - return list.listIterator(); - } - - @Override - public ListIterator listIterator(int index) { - int sz = size(); - if (index < 0) { - index += sz; - } - - return list.listIterator(index); - } - - @Override - public List subList(int fromIndex, int toIndex) { - if (fromIndex < 0) { - fromIndex += size(); - } - if (toIndex < 0) { - toIndex += size(); - } - return list.subList(fromIndex, toIndex); - } -} \ No newline at end of file diff --git a/APIJSONORM/src/main/java/apijson/JSONCreator.java b/APIJSONORM/src/main/java/apijson/JSONCreator.java index 8e4f6c8cb..df0d9066a 100755 --- a/APIJSONORM/src/main/java/apijson/JSONCreator.java +++ b/APIJSONORM/src/main/java/apijson/JSONCreator.java @@ -1,17 +1,15 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ package apijson; -import apijson.orm.SQLConfig; -import apijson.orm.SQLExecutor; - +import java.util.Collection; import java.util.List; import java.util.Map; -/**SQL相关创建器 +/**JSON相关创建器 * @author Lemon */ public interface JSONCreator, L extends List> { @@ -46,10 +44,10 @@ default L createJSONArray(Object obj){ } @NotNull - default L createJSONArray(List l){ + default L createJSONArray(Collection list){ L arr = createJSONArray(); - if (l != null && ! l.isEmpty()) { - arr.addAll(l); + if (list != null && ! list.isEmpty()) { + arr.addAll(list); } return arr; } diff --git a/APIJSONORM/src/main/java/apijson/JSONField.java b/APIJSONORM/src/main/java/apijson/JSONField.java deleted file mode 100644 index 11a5cc309..000000000 --- a/APIJSONORM/src/main/java/apijson/JSONField.java +++ /dev/null @@ -1,5 +0,0 @@ -package apijson; - -public @interface JSONField { - boolean serialize() default true; -} diff --git a/APIJSONORM/src/main/java/apijson/JSONList.java b/APIJSONORM/src/main/java/apijson/JSONList.java new file mode 100644 index 000000000..092bf9f39 --- /dev/null +++ b/APIJSONORM/src/main/java/apijson/JSONList.java @@ -0,0 +1,312 @@ +/*Copyright (C) 2020 Tencent. All rights reserved. + +This source code is licensed under the Apache License Version 2.0.*/ + +package apijson; + +import java.util.*; + +/** + * Custom JSONList implementation based on ArrayList to replace com.alibaba.fastjson.JSONList + * Maintains same API as fastjson but uses standard Java List implementation + * @author Lemon + */ +public interface JSONList, L extends List> extends List { + public static final String TAG = "JSONList"; + + ///** + // * Create an empty JSONList + // */ + //default JSONList() { + // super(); + //} + // + //private int initialCapacity = 10; + ///** + // * Create a JSONList with initial capacity + // * @param initialCapacity the initial capacity + // */ + //default JSONList(int initialCapacity) { + // super(initialCapacity); + //} + // + ///** + // * Create a JSONList from a Collection + // * @param collection the collection to copy from + // */ + //default JSONList(Collection collection) { + // super(collection); + //} + // + ///** + // * Create a JSONList from a JSON string + // * @param json JSON string + // */ + //default JSONList(String json) { + // this(); + // List list = JSON.parseArray(json); + // if (list != null) { + // addAll(list); + // } + //} + // + /** + * Get a JSONMap at the specified index + * @param index the index + * @return the JSONMap or null if not a JSONMap + */ + default M getJSONObject(int index) { + if (index < 0 || index >= size()) { + return null; + } + + Object obj = get(index); + if (obj instanceof Map) { + return JSON.createJSONObject((Map) obj); + } + + return null; + } + + /** + * Get a JSONList at the specified index + * @param index the index + * @return the JSONList or null if not a JSONList + */ + default L getJSONArray(int index) { + if (index < 0 || index >= size()) { + return null; + } + + Object obj = get(index); + if (obj instanceof List) { + return JSON.createJSONArray((List) obj); + } + + return null; + } + + /** + * Get a boolean value at the specified index + * @param index the index + * @return the boolean value or false if not found + */ + default boolean getBooleanValue(int index) { + if (index < 0 || index >= size()) { + return false; + } + + Object obj = get(index); + if (obj instanceof Boolean) { + return (Boolean) obj; + } else if (obj instanceof Number) { + return ((Number) obj).intValue() != 0; + } else if (obj instanceof String) { + return Boolean.parseBoolean((String) obj); + } + + return false; + } + + /** + * Get an integer value at the specified index + * @param index the index + * @return the integer value or 0 if not found + */ + default int getIntValue(int index) { + if (index < 0 || index >= size()) { + return 0; + } + + Object obj = get(index); + if (obj instanceof Number) { + return ((Number) obj).intValue(); + } else if (obj instanceof String) { + try { + return Integer.parseInt((String) obj); + } catch (NumberFormatException e) { + // Ignore + } + } + return 0; + } + + /** + * Get a long value at the specified index + * @param index the index + * @return the long value or 0 if not found + */ + default long getLongValue(int index) { + if (index < 0 || index >= size()) { + return 0L; + } + + Object obj = get(index); + if (obj instanceof Number) { + return ((Number) obj).longValue(); + } else if (obj instanceof String) { + try { + return Long.parseLong((String) obj); + } catch (NumberFormatException e) { + // Ignore + } + } + return 0L; + } + + /** + * Get a double value at the specified index + * @param index the index + * @return the double value or 0 if not found + */ + default double getDoubleValue(int index) { + if (index < 0 || index >= size()) { + return 0.0; + } + + Object obj = get(index); + if (obj instanceof Number) { + return ((Number) obj).doubleValue(); + } else if (obj instanceof String) { + try { + return Double.parseDouble((String) obj); + } catch (NumberFormatException e) { + // Ignore + } + } + return 0.0; + } + + /** + * Get a string value at the specified index + * @param index the index + * @return the string value or null if not found + */ + default String getString(int index) { + if (index < 0 || index >= size()) { + return null; + } + + Object obj = get(index); + return obj != null ? obj.toString() : null; + } + + + default String toJSONString() { + return JSON.toJSONString(this); + } + + //@Override + //default boolean containsAll(Collection c) { + // if (c == null || c.isEmpty()) { + // return true; + // } + // return super.containsAll(c); + //} + // + //@Override + //default boolean addAll(Collection c) { + // if (c == null || c.isEmpty()) { + // return true; + // } + // return super.addAll(c); + //} + // + //@Override + //default boolean addAll(int index, Collection c) { + // if (c == null || c.isEmpty()) { + // return true; + // } + // + // int sz = size(); + // if (index < 0 || index >= sz) { + // index += sz; + // } + // + // return super.addAll(index, c); + //} + // + //@Override + //default boolean removeAll(Collection c) { + // if (c == null || c.isEmpty()) { + // return true; + // } + // return super.removeAll(c); + //} + // + //@Override + //default boolean retainAll(Collection c) { + // if (c == null || c.isEmpty()) { + // return true; + // } + // return super.retainAll(c); + //} + // + // + //@Override + //default Object get(int index) { + // int sz = size(); + // if (index < 0 || index >= sz) { + // index += sz; + // } + // + // return super.get(index); + //} + // + //@Override + //default Object set(int index, Object element) { + // int sz = size(); + // if (index < 0 || index >= sz) { + // index += sz; + // } + // + // return super.set(index, element); + //} + // + //@Override + //default void add(int index, Object element) { + // int sz = size(); + // if (index < 0 || index >= sz) { + // index += sz; + // } + // + // super.add(index, element); + //} + // + //@Override + //default Object remove(int index) { + // int sz = size(); + // if (index < 0 && index >= -sz) { + // index += sz; + // } + // if (index < 0 || index >= sz) { + // return null; + // } + // + // return super.remove(index); + //} + // + //@Override + //default ListIterator listIterator(int index) { + // int sz = size(); + // if (index < 0 && index >= -sz) { + // index += sz; + // } + // + // return super.listIterator(index); + //} + // + //@Override + //default List subList(int fromIndex, int toIndex) { + // int sz = size(); + // if (fromIndex < 0 && fromIndex >= -sz) { + // fromIndex += sz; + // } + // if (toIndex < 0 && toIndex >= -sz) { + // toIndex += sz; + // } + // + // return super.subList(fromIndex, toIndex); + //} + +} \ No newline at end of file diff --git a/APIJSONORM/src/main/java/apijson/JSONMap.java b/APIJSONORM/src/main/java/apijson/JSONMap.java new file mode 100755 index 000000000..29d88f756 --- /dev/null +++ b/APIJSONORM/src/main/java/apijson/JSONMap.java @@ -0,0 +1,810 @@ +/*Copyright (C) 2020 Tencent. All rights reserved. + +This source code is licensed under the Apache License Version 2.0.*/ + + +package apijson; + +import java.util.*; + + +/**use this class instead of com.alibaba.fastjson.JSONMap + * @author Lemon + * @see #put + * @see #puts + * @see #putsAll + */ +//default class JSONMap extends LinkedHashMap { +public interface JSONMap, L extends List> extends Map { + static final String TAG = "JSONMap"; + + // 只能是 static public Map map = new LinkedHashMap<>(); + + ///**ordered + // */ + //default JSONMap() { + // super(); + //} + ///**transfer Object to JSONMap + // * @param object + // * @see {@link #JSONMap(Object)} + // */ + //default JSONMap(Object object) { + // this(); + // if (object instanceof Map) { + // @SuppressWarnings("unchecked") + // Map map = (Map) object; + // putAll(map); + // } else if (object != null) { + // String json = JSON.toJSONString(object); + // if (json != null) { + // Map map = JSON.parseObject(json); + // if (map != null) { + // putAll(map); + // } + // } + // } + //} + ///**parse JSONMap with JSON String + // * @param json + // * @see {@link #JSONMap(String)} + // */ + //default JSONMap(String json) { + // this(); + // Map map = JSON.parseObject(json); + // if (map != null) { + // putAll(map); + // } + //} + ///**transfer com.alibaba.fastjson.JSONMap to JSONMap + // * @param object + // * @see {@link #putsAll(Map)} + // */ + //default JSONMap(Map object) { + // this(); + // putsAll(object); + //} + + //public static JSONMap valueOf(Object obj) { + // JSONMap req = new JSONMap() {}; + // Map m = JSON.parseObject(obj); + // if (m != null && ! m.isEmpty()) { + // req.map.putAll(m); + // } + // return req; + //} + + //judge <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + String KEY_ARRAY = "[]"; + + /**判断是否为Array的key + * @param key + * @return + */ + public static boolean isArrayKey(String key) { + return key != null && key.endsWith(KEY_ARRAY); + } + /**判断是否为对应Table的key + * @param key + * @return + */ + public static boolean isTableKey(String key) { + return StringUtil.isBigName(key); + } + /**判断是否为对应Table数组的 key + * @param key + * @return + */ + public static boolean isTableArray(String key) { + return isArrayKey(key) && isTableKey(key.substring(0, key.length() - KEY_ARRAY.length())); + } + //judge >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + + + //JSONObject内关键词 key <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + + public static String KEY_ID = "id"; + public static String KEY_ID_IN = KEY_ID + "{}"; + public static String KEY_USER_ID = "userId"; + public static String KEY_USER_ID_IN = KEY_USER_ID + "{}"; + + /**set "id":id in Table layer + * @param id + * @return + */ + default JSONMap setId(Long id) { + return puts(KEY_ID, id); + } + /**set "id{}":[] in Table layer + * @param list + * @return + */ + default JSONMap setIdIn(List list) { + return puts(KEY_ID_IN, list); + } + + /**set "userId":userId in Table layer + * @param id + * @return + */ + default JSONMap setUserId(Long id) { + return puts(KEY_USER_ID, id); + } + /**set "userId{}":[] in Table layer + * @param list + * @return + */ + default JSONMap setUserIdIn(List list) { + return puts(KEY_USER_ID_IN, list); + } + + + int CACHE_ALL = 0; + int CACHE_ROM = 1; + int CACHE_RAM = 2; + + String CACHE_ALL_STRING = "ALL"; + String CACHE_ROM_STRING = "ROM"; + String CACHE_RAM_STRING = "RAM"; + + + //@key关键字都放这个类 <<<<<<<<<<<<<<<<<<<<<< + String KEY_TRY = "@try"; //尝试,忽略异常 + String KEY_CATCH = "@catch"; //TODO 捕捉到异常后,处理方式 null-不处理;DEFAULT-返回默认值;ORIGIN-返回请求里的原始值 + String KEY_DROP = "@drop"; //丢弃,不返回,TODO 应该通过 fastjson 的 ignore 之类的机制来处理,避免导致下面的对象也不返回 + // String KEY_KEEP = "@keep"; //一定会返回,为 null 或 空对象时,会使用默认值(非空),解决其它对象因为不关联的第一个对为空导致也不返回 + String KEY_DEFULT = "@default"; //TODO 自定义默认值 { "@default":true },@default 可完全替代 @keep + String KEY_NULL = "@null"; //值为 null 的键值对 "@null":"tag,pictureList",允许 is NULL 条件判断, SET tag = NULL 修改值为 NULL 等 + String KEY_CAST = "@cast"; //类型转换 cast(date AS DATE) + + String KEY_ROLE = "@role"; //角色,拥有对某些数据的某些操作的权限 + String KEY_DATABASE = "@database"; //数据库类型,默认为MySQL + String KEY_DATASOURCE = "@datasource"; //数据源 + String KEY_NAMESPACE = "@namespace"; //命名空间,Table 在非默认 namespace 内时需要声明 + String KEY_CATALOG = "@catalog"; //目录,Table 在非默认 catalog 内时需要声明 + String KEY_SCHEMA = "@schema"; //数据库,Table 在非默认 schema 内时需要声明 + String KEY_EXPLAIN = "@explain"; //分析 true/false + String KEY_CACHE = "@cache"; //缓存 RAM/ROM/ALL + String KEY_COLUMN = "@column"; //查询的Table字段或SQL函数 + String KEY_FROM = "@from"; //FROM语句 + String KEY_COMBINE = "@combine"; //条件组合,每个条件key前面可以放&,|,!逻辑关系 "id!{},&sex,!name&$" + String KEY_GROUP = "@group"; //分组方式 + String KEY_HAVING = "@having"; //聚合函数条件,一般和@group一起用 + String KEY_HAVING_AND = "@having&"; //聚合函数条件,一般和@group一起用 + String KEY_SAMPLE = "@sample"; //取样方式 + String KEY_LATEST = "@latest"; //最近方式 + String KEY_PARTITION = "@partition"; //分区方式 + String KEY_FILL = "@fill"; //填充方式 + String KEY_ORDER = "@order"; //排序方式 + String KEY_KEY = "@key"; // key 映射,year:left(date,4);name_tag:(name,tag) + String KEY_RAW = "@raw"; // 自定义原始 SQL 片段 + String KEY_JSON = "@json"; //SQL Server 把字段转为 JSON 输出 + String KEY_METHOD = "@method"; // json 对象配置操作方法 + String KEY_GET = "@get"; // json 对象配置操作方法 + String KEY_GETS = "@gets"; // json 对象配置操作方法 + String KEY_HEAD = "@head"; // json 对象配置操作方法 + String KEY_HEADS = "@heads"; // json 对象配置操作方法 + String KEY_POST = "@post"; // json 对象配置操作方法 + String KEY_PUT = "@put"; // json 对象配置操作方法 + String KEY_DELETE = "@delete"; // json 对象配置操作方法 + + List TABLE_KEY_LIST = new ArrayList<>(Arrays.asList( + KEY_ROLE, + KEY_DATABASE, + KEY_DATASOURCE, + KEY_NAMESPACE, + KEY_CATALOG, + KEY_SCHEMA, + KEY_EXPLAIN, + KEY_CACHE, + KEY_COLUMN, + KEY_FROM, + KEY_NULL, + KEY_CAST, + KEY_COMBINE, + KEY_GROUP, + KEY_HAVING, + KEY_HAVING_AND, + KEY_SAMPLE, + KEY_LATEST, + KEY_PARTITION, + KEY_FILL, + KEY_ORDER, + KEY_KEY, + KEY_RAW, + KEY_JSON, + KEY_METHOD, + KEY_GET, + KEY_GETS, + KEY_HEAD, + KEY_HEADS, + KEY_POST, + KEY_PUT, + KEY_DELETE + )); + + //@key关键字都放这个类 >>>>>>>>>>>>>>>>>>>>>> + + + /**set try, ignore exceptions + * @param tri + * @return this + */ + default JSONMap setTry(Boolean tri) { + return puts(KEY_TRY, tri); + } + + /**set catch + * @param isCatch + * @return this + */ + default JSONMap setCatch(String isCatch) { + return puts(KEY_CATCH, isCatch); + } + /**set drop, data dropped will not return + * @param drop + * @return this + */ + default JSONMap setDrop(Boolean drop) { + return puts(KEY_DROP, drop); + } + + /**set if has default + * @param hasDefault + * @return this + */ + default JSONMap setDefault(Boolean hasDefault) { + return puts(KEY_DEFULT, hasDefault); + } + + + /**set role of request sender + * @param role + * @return this + */ + default JSONMap setRole(String role) { + return puts(KEY_ROLE, role); + } + /**set database where table was puts + * @param database + * @return this + */ + default JSONMap setDatabase(String database) { + return puts(KEY_DATABASE, database); + } + /**set datasource where table was puts + * @param datasource + * @return this + */ + default JSONMap setDatasource(String datasource) { + return puts(KEY_DATASOURCE, datasource); + } + /**set namespace where table was puts + * @param namespace + * @return this + */ + default JSONMap setNamespace(String namespace) { + return puts(KEY_NAMESPACE, namespace); + } + /**set catalog where table was puts + * @param catalog + * @return this + */ + default JSONMap setCatalog(String catalog) { + return puts(KEY_CATALOG, catalog); + } + /**set schema where table was puts + * @param schema + * @return this + */ + default JSONMap setSchema(String schema) { + return puts(KEY_SCHEMA, schema); + } + /**set if return explain informations + * @param explain + * @return + */ + default JSONMap setExplain(Boolean explain) { + return puts(KEY_EXPLAIN, explain); + } + /**set cache type + * @param cache + * @return + * @see {@link #CACHE_ALL} + * @see {@link #CACHE_RAM} + * @see {@link #CACHE_ROM} + */ + default JSONMap setCache(Integer cache) { + return puts(KEY_CACHE, cache); + } + /**set cache type + * @param cache + * @return + * @see {@link #CACHE_ALL_STRING} + * @see {@link #CACHE_RAM_STRING} + * @see {@link #CACHE_ROM_STRING} + */ + default JSONMap setCache(String cache) { + return puts(KEY_CACHE, cache); + } + + /**set keys need to be returned + * @param keys key0, key1, key2 ... + * @return {@link #setColumn(String)} + */ + default JSONMap setColumn(String... keys) { + return setColumn(StringUtil.get(keys, true)); + } + /**set keys need to be returned + * @param keys "key0,key1,key2..." + * @return + */ + default JSONMap setColumn(String keys) { + return puts(KEY_COLUMN, keys); + } + + /**set keys whose value is null + * @param keys key0, key1, key2 ... + * @return {@link #setNull(String)} + */ + default JSONMap setNull(String... keys) { + return setNull(StringUtil.get(keys, true)); + } + /**set keys whose value is null + * @param keys "key0,key1,key2..." + * @return + */ + default JSONMap setNull(String keys) { + return puts(KEY_NULL, keys); + } + + /**set keys and types whose value should be cast to type, cast(value AS DATE) + * @param keyTypes key0:type0, key1:type1, key2:type2 ... + * @return {@link #setCast(String)} + */ + default JSONMap setCast(String... keyTypes) { + return setCast(StringUtil.get(keyTypes, true)); + } + /**set keys and types whose value should be cast to type, cast(value AS DATE) + * @param keyTypes "key0:type0,key1:type1,key2:type2..." + * @return + */ + default JSONMap setCast(String keyTypes) { + return puts(KEY_CAST, keyTypes); + } + + /**set combination of keys for conditions + * @param keys key0,&key1,|key2,!key3 ... TODO or key0> | (key1{} & !key2)... + * @return {@link #setColumn(String)} + */ + default JSONMap setCombine(String... keys) { + return setCombine(StringUtil.get(keys, true)); + } + /**set combination of keys for conditions + * @param keys key0,&key1,|key2,!key3 ... TODO or key0> | (key1{} & !key2)... + * @return + */ + default JSONMap setCombine(String keys) { + return puts(KEY_COMBINE, keys); + } + + /**set keys for group by + * @param keys key0, key1, key2 ... + * @return {@link #setGroup(String)} + */ + default JSONMap setGroup(String... keys) { + return setGroup(StringUtil.get(keys, true)); + } + /**set keys for group by + * @param keys "key0,key1,key2..." + * @return + */ + default JSONMap setGroup(String keys) { + return puts(KEY_GROUP, keys); + } + + /**set keys for having + * @param keys count(key0) > 1, sum(key1) <= 5, function2(key2) ? value2 ... + * @return {@link #setHaving(String)} + */ + default JSONMap setHaving(String... keys) { + return setHaving(StringUtil.get(keys, true)); + } + /**set keys for having + * @param keys "key0,key1,key2..." + * @return + */ + default JSONMap setHaving(String keys) { + return setHaving(keys, false); + } + /**set keys for having + * @param keys "key0,key1,key2..." + * @return + */ + default JSONMap setHaving(String keys, boolean isAnd) { + return puts(isAnd ? KEY_HAVING_AND : KEY_HAVING, keys); + } + + /**set keys for sample by + * @param keys key0, key1, key2 ... + * @return {@link #setSample(String)} + */ + default JSONMap setSample(String... keys) { + return setSample(StringUtil.get(keys, true)); + } + /**set keys for sample by + * @param keys "key0,key1,key2..." + * @return + */ + default JSONMap setSample(String keys) { + return puts(KEY_SAMPLE, keys); + } + + /**set keys for latest on + * @param keys key0, key1, key2 ... + * @return {@link #setLatest(String)} + */ + default JSONMap setLatest(String... keys) { + return setLatest(StringUtil.get(keys, true)); + } + /**set keys for latest on + * @param keys "key0,key1,key2..." + * @return + */ + default JSONMap setLatest(String keys) { + return puts(KEY_LATEST, keys); + } + + /**set keys for partition by + * @param keys key0, key1, key2 ... + * @return {@link #setPartition(String)} + */ + default JSONMap setPartition(String... keys) { + return setPartition(StringUtil.get(keys, true)); + } + /**set keys for partition by + * @param keys key0, key1, key2 ... + * @return + */ + default JSONMap setPartition(String keys) { + return puts(KEY_PARTITION, keys); + } + + /**set keys for fill(key): fill(null), fill(linear), fill(prev) + * @param keys key0, key1, key2 ... + * @return {@link #setFill(String)} + */ + default JSONMap setFill(String... keys) { + return setFill(StringUtil.get(keys, true)); + } + /**set keys for fill(key): fill(null), fill(linear), fill(prev) + * @param keys key0, key1, key2 ... + * @return + */ + default JSONMap setFill(String keys) { + return puts(KEY_FILL, keys); + } + + /**set keys for order by + * @param keys key0, key1+, key2- ... + * @return {@link #setOrder(String)} + */ + default JSONMap setOrder(String... keys) { + return setOrder(StringUtil.get(keys, true)); + } + /**set keys for order by + * @param keys "key0,key1+,key2-..." + * @return + */ + default JSONMap setOrder(String keys) { + return puts(KEY_ORDER, keys); + } + + /**set key map + * @param keyMap "name_tag:(name,tag);year:left(date,1,5)..." + * @return + */ + default JSONMap setKey(String keyMap) { + return puts(KEY_KEY, keyMap); + } + + /**set keys to raw + * @param keys "key0,key1,key2..." + * @return + */ + default JSONMap setRaw(String keys) { + return puts(KEY_RAW, keys); + } + + /**set keys to cast to json + * @param keys "key0,key1,key2..." + * @return + */ + default JSONMap setJson(String keys) { + return puts(KEY_JSON, keys); + } + + //JSONObject内关键词 key >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + + + + //Request <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + + /** + * @param key + * @param keys path = keys[0] + "/" + keys[1] + "/" + keys[2] + ... + * @return {@link #puts(String, Object)} + */ + default JSONMap putsPath(String key, String... keys) { + return puts(key+"@", StringUtil.get(keys, "/")); + } + + /** + * @param key + * @param isNull + * @return {@link #puts(String, Object)} + */ + default JSONMap putsNull(String key, boolean isNull) { + return puts(key+"{}", SQL.isNull(isNull)); + } + /** + * trim = false + * @param key + * @param isEmpty + * @return {@link #putsEmpty(String, boolean, boolean)} + */ + default JSONMap putsEmpty(String key, boolean isEmpty) { + return putsEmpty(key, isEmpty, false); + } + /** + * @param key + * @param isEmpty + * @return {@link #puts(String, Object)} + */ + default JSONMap putsEmpty(String key, boolean isEmpty, boolean trim) { + return puts(key+"{}", SQL.isEmpty(key, isEmpty, trim)); + } + /** + * @param key + * @param compare <=0, >5 ... + * @return {@link #puts(String, Object)} + */ + default JSONMap putsLength(String key, String compare) { + return puts(key+"{}", SQL.length(key) + compare); + } + /** + * @param key + * @param compare <=, > ... + * @param value 1, 5, 3.14, -99 ... + * @return {@link #puts(String, Object)} + */ + default JSONMap putsLength(String key, String compare, Object value) { + return puts(key+"["+(StringUtil.isEmpty(compare) || "=".equals(compare) ? "" : ("!=".equals(compare) ? "!" : compare)), value); + } + /** + * @param key + * @param compare <=0, >5 ... + * @return {@link #puts(String, Object)} + */ + default JSONMap putsJSONLength(String key, String compare) { + return puts(key+"{}", SQL.json_length(key) + compare); + } + /** + * @param key + * @param compare <=0, >5 ... + * @return {@link #puts(String, Object)} + */ + default JSONMap putsJSONLength(String key, String compare, Object value) { + return puts(key + "{" + (StringUtil.isEmpty(compare) || "=".equals(compare) ? "" : ("!=".equals(compare) ? "!" : compare)), value); + } + + /**设置搜索 + * type = SEARCH_TYPE_CONTAIN_FULL + * @param key + * @param value + * @return {@link #putsSearch(String, String, int)} + */ + default JSONMap putsSearch(String key, String value) { + return putsSearch(key, value, SQL.SEARCH_TYPE_CONTAIN_FULL); + } + /**设置搜索 + * @param key + * @param value + * @param type + * @return {@link #puts(String, Object)} + */ + default JSONMap putsSearch(String key, String value, int type) { + return puts(key+"$", SQL.search(value, type)); + } + + //Request >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + + /**put and return this + * @param value must be annotated by {@link MethodAccess} + * @return {@link #puts(String, Object)} + */ + default JSONMap puts(Object value) { + put(value); + return this; + } + /**put and return this + * @param key + * @param value + * @return this + */ + default JSONMap puts(String key, Object value) { + put(key, value); + return this; + } + + /**put and return value + * @param value must be annotated by {@link MethodAccess} + */ + default Object put(Object value) { + Class clazz = value.getClass(); //should not return null + if (clazz.getAnnotation(MethodAccess.class) == null) { + throw new IllegalArgumentException("puts StringUtil.isEmpty(key, true)" + + " clazz.getAnnotation(MethodAccess.class) == null" + + " \n key为空时仅支持 类型被@MethodAccess注解 的value !!!" + + " \n 如果一定要这么用,请对 " + clazz.getName() + " 注解!" + + " \n 如果是类似 key[]:{} 结构的请求,建议用 putsAll(...) !"); + } + return put(clazz.getSimpleName(), value); + } + + /**puts key-value in object into this + * @param map + * @return this + */ + default JSONMap putsAll(Map map) { + putAll(map); + return this; + } + + + /** + * Get a boolean value from the JSONMap + * @param key the key + * @return the boolean value or false if not found + */ + default boolean getBooleanValue(String key) { + return JSON.getBooleanValue(this, key); + } + + /** + * Get an integer value from the JSONMap + * @param key the key + * @return the integer value or 0 if not found + */ + default int getIntValue(String key) { + return JSON.getIntValue(this, key); + } + + /** + * Get a long value from the JSONMap + * @param key the key + * @return the long value or 0 if not found + */ + default long getLongValue(String key) { + return JSON.getLongValue(this, key); + } + + /** + * Get a double value from the JSONMap + * @param key the key + * @return the double value or 0 if not found + */ + default double getDoubleValue(String key) { + return JSON.getDoubleValue(this, key); + } + + /** + * Get a string value from the JSONMap + * @param key the key + * @return the string value or null if not found + */ + default String getString(String key) { + Object value = get(key); + return value != null ? value.toString() : null; + } + + /** + * Get a JSONMap value from the JSONMap + * @param key the key + * @return the JSONMap value or null if not found + */ + default M getJSONObject(String key) { + Map map = JSON.getMap(this, key); + return map != null ? JSON.createJSONObject(map) : null; + } + + /** + * Get a JSONList value from the JSONMap + * @param key the key + * @return the JSONList value or null if not found + */ + default L getJSONArray(String key) { + List list = JSON.getList(this, key); + return list != null ? JSON.createJSONArray(list) : null; + } + + @Override + default void putAll(Map map) { + Set> set = map == null ? null : map.entrySet(); + if (set != null || set.isEmpty()) { + return; + } + + for (Map.Entry entry : set) { + put(entry.getKey(), entry.getValue()); + } + } + + default String toJSONString() { + return JSON.toJSONString(this); + } + + //@Override + //default int size() { + // return map.size(); + //} + // + //@Override + //default boolean isEmpty() { + // return map.isEmpty(); + //} + // + //@Override + //default boolean containsKey(Object key) { + // return map.containsKey(key); + //} + // + //@Override + //default boolean containsValue(Object value) { + // return map.containsValue(value); + //} + // + //@Override + //default Object get(Object key) { + // return map.get(key); + //} + // + //@Override + //default Object put(String key, Object value) { + // return map.put(key, value); + //} + // + //@Override + //default Object remove(Object key) { + // return map.remove(key); + //} + + + //@Override + //default void clear() { + // map.clear(); + //} + // + //@Override + //default Set keySet() { + // return map.keySet(); + //} + // + //@Override + //default Collection values() { + // return map.values(); + //} + // + //@Override + //default Set> entrySet() { + // return map.entrySet(); + //} + + //@Override + //default String toString() { + // return JSON.toJSONString(this); + //} + +} diff --git a/APIJSONORM/src/main/java/apijson/JSONObject.java b/APIJSONORM/src/main/java/apijson/JSONObject.java deleted file mode 100755 index 05eb221d6..000000000 --- a/APIJSONORM/src/main/java/apijson/JSONObject.java +++ /dev/null @@ -1,849 +0,0 @@ -/*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 apijson; - -import java.util.*; - - -/**use this class instead of com.alibaba.fastjson.JSONObject - * @author Lemon - * @see #put - * @see #puts - * @see #putsAll - */ -public class JSONObject extends JSON implements Map { - private static final String TAG = "JSONObject"; - - private final LinkedHashMap map = new LinkedHashMap<>(); - - /**ordered - */ - public JSONObject() { - super(); - } - /**transfer Object to JSONObject - * @param object - * @see {@link #JSONObject(Object)} - */ - public JSONObject(Object object) { - this(); - if (object instanceof Map) { - @SuppressWarnings("unchecked") - Map map = (Map) object; - putAll(map); - } else if (object != null) { - String json = JSON.toJSONString(object); - if (json != null) { - Map map = JSON.parseObject(json); - if (map != null) { - putAll(map); - } - } - } - } - /**parse JSONObject with JSON String - * @param json - * @see {@link #JSONObject(String)} - */ - public JSONObject(String json) { - this(); - Map map = JSON.parseObject(json); - if (map != null) { - putAll(map); - } - } - /**transfer com.alibaba.fastjson.JSONObject to JSONObject - * @param object - * @see {@link #putsAll(Map)} - */ - public JSONObject(Map object) { - this(); - putsAll(object); - } - - - //judge <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - public static final String KEY_ARRAY = "[]"; - - /**判断是否为Array的key - * @param key - * @return - */ - public static boolean isArrayKey(String key) { - return key != null && key.endsWith(KEY_ARRAY); - } - /**判断是否为对应Table的key - * @param key - * @return - */ - public static boolean isTableKey(String key) { - return StringUtil.isBigName(key); - } - /**判断是否为对应Table数组的 key - * @param key - * @return - */ - public static boolean isTableArray(String key) { - return isArrayKey(key) && isTableKey(key.substring(0, key.length() - KEY_ARRAY.length())); - } - //judge >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - - - //JSONObject内关键词 key <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - - - public static String KEY_ID = "id"; - public static String KEY_ID_IN = KEY_ID + "{}"; - public static String KEY_USER_ID = "userId"; - public static String KEY_USER_ID_IN = KEY_USER_ID + "{}"; - - /**set "id":id in Table layer - * @param id - * @return - */ - public JSONObject setId(Long id) { - return puts(KEY_ID, id); - } - /**set "id{}":[] in Table layer - * @param list - * @return - */ - public JSONObject setIdIn(List list) { - return puts(KEY_ID_IN, list); - } - - /**set "userId":userId in Table layer - * @param id - * @return - */ - public JSONObject setUserId(Long id) { - return puts(KEY_USER_ID, id); - } - /**set "userId{}":[] in Table layer - * @param list - * @return - */ - public JSONObject setUserIdIn(List list) { - return puts(KEY_USER_ID_IN, list); - } - - - public static final int CACHE_ALL = 0; - public static final int CACHE_ROM = 1; - public static final int CACHE_RAM = 2; - - public static final String CACHE_ALL_STRING = "ALL"; - public static final String CACHE_ROM_STRING = "ROM"; - public static final String CACHE_RAM_STRING = "RAM"; - - - //@key关键字都放这个类 <<<<<<<<<<<<<<<<<<<<<< - public static final String KEY_TRY = "@try"; //尝试,忽略异常 - public static final String KEY_CATCH = "@catch"; //TODO 捕捉到异常后,处理方式 null-不处理;DEFAULT-返回默认值;ORIGIN-返回请求里的原始值 - public static final String KEY_DROP = "@drop"; //丢弃,不返回,TODO 应该通过 fastjson 的 ignore 之类的机制来处理,避免导致下面的对象也不返回 - // public static final String KEY_KEEP = "@keep"; //一定会返回,为 null 或 空对象时,会使用默认值(非空),解决其它对象因为不关联的第一个对为空导致也不返回 - public static final String KEY_DEFULT = "@default"; //TODO 自定义默认值 { "@default":true },@default 可完全替代 @keep - public static final String KEY_NULL = "@null"; //TODO 值为 null 的键值对 "@null":"tag,pictureList",允许 is NULL 条件判断, SET tag = NULL 修改值为 NULL 等 - public static final String KEY_CAST = "@cast"; //TODO 类型转换 cast(date AS DATE) - - public static final String KEY_ROLE = "@role"; //角色,拥有对某些数据的某些操作的权限 - public static final String KEY_DATABASE = "@database"; //数据库类型,默认为MySQL - public static final String KEY_DATASOURCE = "@datasource"; //数据源 - public static final String KEY_NAMESPACE = "@namespace"; //命名空间,Table 在非默认 namespace 内时需要声明 - public static final String KEY_CATALOG = "@catalog"; //目录,Table 在非默认 catalog 内时需要声明 - public static final String KEY_SCHEMA = "@schema"; //数据库,Table 在非默认 schema 内时需要声明 - public static final String KEY_EXPLAIN = "@explain"; //分析 true/false - public static final String KEY_CACHE = "@cache"; //缓存 RAM/ROM/ALL - public static final String KEY_COLUMN = "@column"; //查询的Table字段或SQL函数 - public static final String KEY_FROM = "@from"; //FROM语句 - public static final String KEY_COMBINE = "@combine"; //条件组合,每个条件key前面可以放&,|,!逻辑关系 "id!{},&sex,!name&$" - public static final String KEY_GROUP = "@group"; //分组方式 - public static final String KEY_HAVING = "@having"; //聚合函数条件,一般和@group一起用 - public static final String KEY_HAVING_AND = "@having&"; //聚合函数条件,一般和@group一起用 - public static final String KEY_SAMPLE = "@sample"; //取样方式 - public static final String KEY_LATEST = "@latest"; //最近方式 - public static final String KEY_PARTITION = "@partition"; //分区方式 - public static final String KEY_FILL = "@fill"; //填充方式 - public static final String KEY_ORDER = "@order"; //排序方式 - public static final String KEY_KEY = "@key"; // key 映射,year:left(date,4);name_tag:(name,tag) - public static final String KEY_RAW = "@raw"; // 自定义原始 SQL 片段 - public static final String KEY_JSON = "@json"; //SQL Server 把字段转为 JSON 输出 - public static final String KEY_METHOD = "@method"; // json 对象配置操作方法 - public static final String KEY_GET = "@get"; // json 对象配置操作方法 - public static final String KEY_GETS = "@gets"; // json 对象配置操作方法 - public static final String KEY_HEAD = "@head"; // json 对象配置操作方法 - public static final String KEY_HEADS = "@heads"; // json 对象配置操作方法 - public static final String KEY_POST = "@post"; // json 对象配置操作方法 - public static final String KEY_PUT = "@put"; // json 对象配置操作方法 - public static final String KEY_DELETE = "@delete"; // json 对象配置操作方法 - - public static final Map KEY_METHOD_ENUM_MAP; - - public static final List TABLE_KEY_LIST; - static { - TABLE_KEY_LIST = new ArrayList(); - TABLE_KEY_LIST.add(KEY_ROLE); - TABLE_KEY_LIST.add(KEY_DATABASE); - TABLE_KEY_LIST.add(KEY_DATASOURCE); - TABLE_KEY_LIST.add(KEY_NAMESPACE); - TABLE_KEY_LIST.add(KEY_CATALOG); - TABLE_KEY_LIST.add(KEY_SCHEMA); - TABLE_KEY_LIST.add(KEY_EXPLAIN); - TABLE_KEY_LIST.add(KEY_CACHE); - TABLE_KEY_LIST.add(KEY_COLUMN); - TABLE_KEY_LIST.add(KEY_FROM); - TABLE_KEY_LIST.add(KEY_NULL); - TABLE_KEY_LIST.add(KEY_CAST); - TABLE_KEY_LIST.add(KEY_COMBINE); - TABLE_KEY_LIST.add(KEY_GROUP); - TABLE_KEY_LIST.add(KEY_HAVING); - TABLE_KEY_LIST.add(KEY_HAVING_AND); - TABLE_KEY_LIST.add(KEY_SAMPLE); - TABLE_KEY_LIST.add(KEY_LATEST); - TABLE_KEY_LIST.add(KEY_PARTITION); - TABLE_KEY_LIST.add(KEY_FILL); - TABLE_KEY_LIST.add(KEY_ORDER); - TABLE_KEY_LIST.add(KEY_KEY); - TABLE_KEY_LIST.add(KEY_RAW); - TABLE_KEY_LIST.add(KEY_JSON); - TABLE_KEY_LIST.add(KEY_METHOD); - TABLE_KEY_LIST.add(KEY_GET); - TABLE_KEY_LIST.add(KEY_GETS); - TABLE_KEY_LIST.add(KEY_HEAD); - TABLE_KEY_LIST.add(KEY_HEADS); - TABLE_KEY_LIST.add(KEY_POST); - TABLE_KEY_LIST.add(KEY_PUT); - TABLE_KEY_LIST.add(KEY_DELETE); - - KEY_METHOD_ENUM_MAP = new LinkedHashMap<>(); - KEY_METHOD_ENUM_MAP.put(KEY_GET, RequestMethod.GET); - KEY_METHOD_ENUM_MAP.put(KEY_GETS, RequestMethod.GETS); - KEY_METHOD_ENUM_MAP.put(KEY_HEAD, RequestMethod.HEAD); - KEY_METHOD_ENUM_MAP.put(KEY_HEADS, RequestMethod.HEADS); - KEY_METHOD_ENUM_MAP.put(KEY_POST, RequestMethod.POST); - KEY_METHOD_ENUM_MAP.put(KEY_PUT, RequestMethod.PUT); - KEY_METHOD_ENUM_MAP.put(KEY_DELETE, RequestMethod.DELETE); - } - - //@key关键字都放这个类 >>>>>>>>>>>>>>>>>>>>>> - - - /**set try, ignore exceptions - * @param tri - * @return this - */ - public JSONObject setTry(Boolean tri) { - return puts(KEY_TRY, tri); - } - - /**set catch - * @param isCatch - * @return this - */ - public JSONObject setCatch(String isCatch) { - return puts(KEY_CATCH, isCatch); - } - /**set drop, data dropped will not return - * @param drop - * @return this - */ - public JSONObject setDrop(Boolean drop) { - return puts(KEY_DROP, drop); - } - - /**set if has default - * @param hasDefault - * @return this - */ - public JSONObject setDefault(Boolean hasDefault) { - return puts(KEY_DEFULT, hasDefault); - } - - - /**set role of request sender - * @param role - * @return this - */ - public JSONObject setRole(String role) { - return puts(KEY_ROLE, role); - } - /**set database where table was puts - * @param database - * @return this - */ - public JSONObject setDatabase(String database) { - return puts(KEY_DATABASE, database); - } - /**set datasource where table was puts - * @param datasource - * @return this - */ - public JSONObject setDatasource(String datasource) { - return puts(KEY_DATASOURCE, datasource); - } - /**set namespace where table was puts - * @param namespace - * @return this - */ - public JSONObject setNamespace(String namespace) { - return puts(KEY_NAMESPACE, namespace); - } - /**set catalog where table was puts - * @param catalog - * @return this - */ - public JSONObject setCatalog(String catalog) { - return puts(KEY_CATALOG, catalog); - } - /**set schema where table was puts - * @param schema - * @return this - */ - public JSONObject setSchema(String schema) { - return puts(KEY_SCHEMA, schema); - } - /**set if return explain informations - * @param explain - * @return - */ - public JSONObject setExplain(Boolean explain) { - return puts(KEY_EXPLAIN, explain); - } - /**set cache type - * @param cache - * @return - * @see {@link #CACHE_ALL} - * @see {@link #CACHE_RAM} - * @see {@link #CACHE_ROM} - */ - public JSONObject setCache(Integer cache) { - return puts(KEY_CACHE, cache); - } - /**set cache type - * @param cache - * @return - * @see {@link #CACHE_ALL_STRING} - * @see {@link #CACHE_RAM_STRING} - * @see {@link #CACHE_ROM_STRING} - */ - public JSONObject setCache(String cache) { - return puts(KEY_CACHE, cache); - } - - /**set keys need to be returned - * @param keys key0, key1, key2 ... - * @return {@link #setColumn(String)} - */ - public JSONObject setColumn(String... keys) { - return setColumn(StringUtil.get(keys, true)); - } - /**set keys need to be returned - * @param keys "key0,key1,key2..." - * @return - */ - public JSONObject setColumn(String keys) { - return puts(KEY_COLUMN, keys); - } - - /**set keys whose value is null - * @param keys key0, key1, key2 ... - * @return {@link #setNull(String)} - */ - public JSONObject setNull(String... keys) { - return setNull(StringUtil.get(keys, true)); - } - /**set keys whose value is null - * @param keys "key0,key1,key2..." - * @return - */ - public JSONObject setNull(String keys) { - return puts(KEY_NULL, keys); - } - - /**set keys and types whose value should be cast to type, cast(value AS DATE) - * @param keyTypes key0:type0, key1:type1, key2:type2 ... - * @return {@link #setCast(String)} - */ - public JSONObject setCast(String... keyTypes) { - return setCast(StringUtil.get(keyTypes, true)); - } - /**set keys and types whose value should be cast to type, cast(value AS DATE) - * @param keyTypes "key0:type0,key1:type1,key2:type2..." - * @return - */ - public JSONObject setCast(String keyTypes) { - return puts(KEY_CAST, keyTypes); - } - - /**set combination of keys for conditions - * @param keys key0,&key1,|key2,!key3 ... TODO or key0> | (key1{} & !key2)... - * @return {@link #setColumn(String)} - */ - public JSONObject setCombine(String... keys) { - return setCombine(StringUtil.get(keys, true)); - } - /**set combination of keys for conditions - * @param keys key0,&key1,|key2,!key3 ... TODO or key0> | (key1{} & !key2)... - * @return - */ - public JSONObject setCombine(String keys) { - return puts(KEY_COMBINE, keys); - } - - /**set keys for group by - * @param keys key0, key1, key2 ... - * @return {@link #setGroup(String)} - */ - public JSONObject setGroup(String... keys) { - return setGroup(StringUtil.get(keys, true)); - } - /**set keys for group by - * @param keys "key0,key1,key2..." - * @return - */ - public JSONObject setGroup(String keys) { - return puts(KEY_GROUP, keys); - } - - /**set keys for having - * @param keys count(key0) > 1, sum(key1) <= 5, function2(key2) ? value2 ... - * @return {@link #setHaving(String)} - */ - public JSONObject setHaving(String... keys) { - return setHaving(StringUtil.get(keys, true)); - } - /**set keys for having - * @param keys "key0,key1,key2..." - * @return - */ - public JSONObject setHaving(String keys) { - return setHaving(keys, false); - } - /**set keys for having - * @param keys "key0,key1,key2..." - * @return - */ - public JSONObject setHaving(String keys, boolean isAnd) { - return puts(isAnd ? KEY_HAVING_AND : KEY_HAVING, keys); - } - - /**set keys for sample by - * @param keys key0, key1, key2 ... - * @return {@link #setSample(String)} - */ - public JSONObject setSample(String... keys) { - return setSample(StringUtil.get(keys, true)); - } - /**set keys for sample by - * @param keys "key0,key1,key2..." - * @return - */ - public JSONObject setSample(String keys) { - return puts(KEY_SAMPLE, keys); - } - - /**set keys for latest on - * @param keys key0, key1, key2 ... - * @return {@link #setLatest(String)} - */ - public JSONObject setLatest(String... keys) { - return setLatest(StringUtil.get(keys, true)); - } - /**set keys for latest on - * @param keys "key0,key1,key2..." - * @return - */ - public JSONObject setLatest(String keys) { - return puts(KEY_LATEST, keys); - } - - /**set keys for partition by - * @param keys key0, key1, key2 ... - * @return {@link #setPartition(String)} - */ - public JSONObject setPartition(String... keys) { - return setPartition(StringUtil.get(keys, true)); - } - /**set keys for partition by - * @param keys key0, key1, key2 ... - * @return - */ - public JSONObject setPartition(String keys) { - return puts(KEY_PARTITION, keys); - } - - /**set keys for fill(key): fill(null), fill(linear), fill(prev) - * @param keys key0, key1, key2 ... - * @return {@link #setFill(String)} - */ - public JSONObject setFill(String... keys) { - return setFill(StringUtil.get(keys, true)); - } - /**set keys for fill(key): fill(null), fill(linear), fill(prev) - * @param keys key0, key1, key2 ... - * @return - */ - public JSONObject setFill(String keys) { - return puts(KEY_FILL, keys); - } - - /**set keys for order by - * @param keys key0, key1+, key2- ... - * @return {@link #setOrder(String)} - */ - public JSONObject setOrder(String... keys) { - return setOrder(StringUtil.get(keys, true)); - } - /**set keys for order by - * @param keys "key0,key1+,key2-..." - * @return - */ - public JSONObject setOrder(String keys) { - return puts(KEY_ORDER, keys); - } - - /**set key map - * @param keyMap "name_tag:(name,tag);year:left(date,1,5)..." - * @return - */ - public JSONObject setKey(String keyMap) { - return puts(KEY_KEY, keyMap); - } - - /**set keys to raw - * @param keys "key0,key1,key2..." - * @return - */ - public JSONObject setRaw(String keys) { - return puts(KEY_RAW, keys); - } - - /**set keys to cast to json - * @param keys "key0,key1,key2..." - * @return - */ - public JSONObject setJson(String keys) { - return puts(KEY_JSON, keys); - } - - //JSONObject内关键词 key >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - - - - //Request <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - - - /** - * @param key - * @param keys path = keys[0] + "/" + keys[1] + "/" + keys[2] + ... - * @return {@link #puts(String, Object)} - */ - public JSONObject putsPath(String key, String... keys) { - return puts(key+"@", StringUtil.get(keys, "/")); - } - - /** - * @param key - * @param isNull - * @return {@link #puts(String, Object)} - */ - public JSONObject putsNull(String key, boolean isNull) { - return puts(key+"{}", SQL.isNull(isNull)); - } - /** - * trim = false - * @param key - * @param isEmpty - * @return {@link #putsEmpty(String, boolean, boolean)} - */ - public JSONObject putsEmpty(String key, boolean isEmpty) { - return putsEmpty(key, isEmpty, false); - } - /** - * @param key - * @param isEmpty - * @return {@link #puts(String, Object)} - */ - public JSONObject putsEmpty(String key, boolean isEmpty, boolean trim) { - return puts(key+"{}", SQL.isEmpty(key, isEmpty, trim)); - } - /** - * @param key - * @param compare <=0, >5 ... - * @return {@link #puts(String, Object)} - */ - public JSONObject putsLength(String key, String compare) { - return puts(key+"{}", SQL.length(key) + compare); - } - /** - * @param key - * @param compare <=, > ... - * @param value 1, 5, 3.14, -99 ... - * @return {@link #puts(String, Object)} - */ - public JSONObject putsLength(String key, String compare, Object value) { - return puts(key+"["+(StringUtil.isEmpty(compare) || "=".equals(compare) ? "" : ("!=".equals(compare) ? "!" : compare)), value); - } - /** - * @param key - * @param compare <=0, >5 ... - * @return {@link #puts(String, Object)} - */ - public JSONObject putsJSONLength(String key, String compare) { - return puts(key+"{}", SQL.json_length(key) + compare); - } - /** - * @param key - * @param compare <=0, >5 ... - * @return {@link #puts(String, Object)} - */ - public JSONObject putsJSONLength(String key, String compare, Object value) { - return puts(key + "{" + (StringUtil.isEmpty(compare) || "=".equals(compare) ? "" : ("!=".equals(compare) ? "!" : compare)), value); - } - - /**设置搜索 - * type = SEARCH_TYPE_CONTAIN_FULL - * @param key - * @param value - * @return {@link #putsSearch(String, String, int)} - */ - public JSONObject putsSearch(String key, String value) { - return putsSearch(key, value, SQL.SEARCH_TYPE_CONTAIN_FULL); - } - /**设置搜索 - * @param key - * @param value - * @param type - * @return {@link #puts(String, Object)} - */ - public JSONObject putsSearch(String key, String value, int type) { - return puts(key+"$", SQL.search(value, type)); - } - - //Request >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - - /**put and return this - * @param value must be annotated by {@link MethodAccess} - * @return {@link #puts(String, Object)} - */ - public JSONObject puts(Object value) { - return puts(null, value); - } - /**put and return this - * @param key - * @param value - * @return this - * @see {@link #put(String, Object)} - */ - public JSONObject puts(String key, Object value) { - put(key, value); - return this; - } - - /**put and return value - * @param value must be annotated by {@link MethodAccess} - * @return {@link #put(String, Object)} - */ - public Object put(Object value) { - return put(null, value); - } - /**put and return value - * @param key StringUtil.isEmpty(key, true) ? key = value.getClass().getSimpleName(); - * @param value - * @return value - */ - @Override - public Object put(String key, Object value) { - if (value == null) { - Log.e(TAG, "put value == null >> return null;"); - return null; - } - if (StringUtil.isEmpty(key, true)) { - Class clazz = value.getClass(); //should not return null - if (clazz.getAnnotation(MethodAccess.class) == null) { - throw new IllegalArgumentException("puts StringUtil.isEmpty(key, true)" + - " clazz.getAnnotation(MethodAccess.class) == null" + - " \n key为空时仅支持 类型被@MethodAccess注解 的value !!!" + - " \n 如果一定要这么用,请对 " + clazz.getName() + " 注解!" + - " \n 如果是类似 key[]:{} 结构的请求,建议用 putsAll(...) !"); - } - key = value.getClass().getSimpleName(); - } - - return map.put(key, value); - } - - /**puts key-value in object into this - * @param map - * @return this - */ - public JSONObject putsAll(Map map) { - putAll(map); - return this; - } - - - /** - * Get a boolean value from the JSONObject - * @param key the key - * @return the boolean value or false if not found - */ - public boolean getBooleanValue(String key) { - try { - return JSON.getBooleanValue(this, key); - } catch (IllegalArgumentException e) { - return false; - } - } - - /** - * Get an integer value from the JSONObject - * @param key the key - * @return the integer value or 0 if not found - */ - public int getIntValue(String key) { - try { - return JSON.getIntValue(this, key); - } catch (IllegalArgumentException e) { - return 0; - } - } - - /** - * Get a long value from the JSONObject - * @param key the key - * @return the long value or 0 if not found - */ - public long getLongValue(String key) { - try { - return JSON.getLongValue(this, key); - } catch (IllegalArgumentException e) { - return 0L; - } - } - - /** - * Get a double value from the JSONObject - * @param key the key - * @return the double value or 0 if not found - */ - public double getDoubleValue(String key) { - try { - return JSON.getDoubleValue(this, key); - } catch (IllegalArgumentException e) { - return 0.0; - } - } - - /** - * Get a string value from the JSONObject - * @param key the key - * @return the string value or null if not found - */ - public String getString(String key) { - Object value = get(key); - return value != null ? value.toString() : null; - } - - /** - * Get a JSONObject value from the JSONObject - * @param key the key - * @return the JSONObject value or null if not found - */ - public JSONObject getJSONObject(String key) { - try { - Map map = JSON.getMap(this, key); - return map != null ? new JSONObject(map) : null; - } catch (IllegalArgumentException e) { - return null; - } - } - - /** - * Get a JSONArray value from the JSONObject - * @param key the key - * @return the JSONArray value or null if not found - */ - public JSONArray getJSONArray(String key) { - try { - List list = JSON.getList(this, key); - return list != null ? new JSONArray(list) : null; - } catch (IllegalArgumentException e) { - return null; - } - } - - @Override - public int size() { - return map.size(); - } - - /** - * Check if the JSONObject is empty or has no values other than null - * @return true if empty - */ - public boolean isEmpty() { - return map.isEmpty(); - } - - @Override - public boolean containsKey(Object key) { - return map.containsKey(key); - } - - @Override - public boolean containsValue(Object value) { - return map.containsValue(value); - } - - @Override - public Object get(Object key) { - return map.get(key); - } - - @Override - public void putAll(Map map) { - Set> set = map == null ? null : map.entrySet(); - if (set != null || set.isEmpty()) { - return; - } - - for (Entry entry : set) { - put(entry.getKey(), entry.getValue()); - } - } - - @Override - public Object remove(Object key) { - return map.remove(key); - } - - @Override - public void clear() { - map.clear(); - } - - @Override - public Set keySet() { - return map.keySet(); - } - - @Override - public Collection values() { - return map.values(); - } - - @Override - public Set> entrySet() { - return map.entrySet(); - } - - @Override - public String toString() { - return JSON.toJSONString(map); - } - -} diff --git a/APIJSONORM/src/main/java/apijson/JSONParser.java b/APIJSONORM/src/main/java/apijson/JSONParser.java index f06b263a6..7c38a39df 100755 --- a/APIJSONORM/src/main/java/apijson/JSONParser.java +++ b/APIJSONORM/src/main/java/apijson/JSONParser.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ @@ -8,12 +8,12 @@ import java.util.List; import java.util.Map; -/**SQL相关创建器 +/**JSON 相关解析器 * @author Lemon */ public interface JSONParser, L extends List> extends JSONCreator { - Object parseJSON(Object json); + Object parse(Object json); M parseObject(Object json); diff --git a/APIJSONORM/src/main/java/apijson/JSONRequest.java b/APIJSONORM/src/main/java/apijson/JSONRequest.java index 0d47e4392..c74dfe349 100755 --- a/APIJSONORM/src/main/java/apijson/JSONRequest.java +++ b/APIJSONORM/src/main/java/apijson/JSONRequest.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ @@ -6,6 +6,7 @@ package apijson; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; @@ -15,35 +16,40 @@ * @author Lemon * @see #puts * @see #toArray - * @use JSONRequest request = JSON.createJSONObject(...); + * @use JSONRequest request = JSON.createJSONObject(...); *
request.puts(...);//not a must *
request.toArray(...);//not a must */ -public class JSONRequest extends JSONObject { - private static final long serialVersionUID = 1L; - - public JSONRequest() { - super(); - } - /** - * @param object must be annotated by {@link MethodAccess} - * @see {@link #JSONRequest(String, Object)} - */ - public JSONRequest(Object object) { - this(null, object); - } - /** - * @param name - * @param object - * @see {@link #puts(String, Object)} - */ - public JSONRequest(String name, Object object) { - this(); - puts(name, object); - } - - - +public interface JSONRequest, L extends List> extends JSONMap { + + //default JSONRequest() { + // super(); + //} + ///** + // * @param object must be annotated by {@link MethodAccess} + // * @see {@link #JSONRequest(String, Object)} + // */ + //default JSONRequest(Object object) { + // this(null, object); + //} + ///** + // * @param name + // * @param object + // * @see {@link #puts(String, Object)} + // */ + //default JSONRequest(String name, Object object) { + // this(); + // puts(name, object); + //} + + //public static JSONRequest valueOf(Object obj) { + // JSONRequest req = new JSONRequest() {}; + // Map m = JSON.parseObject(obj); + // if (m != null && ! m.isEmpty()) { + // req.map.putAll(m); + // } + // return req; + //} public static final String KEY_TAG = "tag";//只在最外层,最外层用JSONRequest public static final String KEY_VERSION = "version";//只在最外层,最外层用JSONRequest @@ -54,23 +60,25 @@ public JSONRequest(String name, Object object) { * @param tag * @return */ - public JSONRequest setTag(String tag) { + default JSONRequest setTag(String tag) { return puts(KEY_TAG, tag); } + /**set "version":version in outermost layer * for target version of request * @param version * @return */ - public JSONRequest setVersion(Integer version) { + default JSONRequest setVersion(Integer version) { return puts(KEY_VERSION, version); } + /**set "format":format in outermost layer * for format APIJSON special keys to normal keys of response * @param format * @return */ - public JSONRequest setFormat(Boolean format) { + default JSONRequest setFormat(Boolean format) { return puts(KEY_FORMAT, format); } @@ -80,14 +88,14 @@ public JSONRequest setFormat(Boolean format) { public static final int QUERY_TABLE = 0; public static final int QUERY_TOTAL = 1; public static final int QUERY_ALL = 2; - + public static final String QUERY_TABLE_STRING = "TABLE"; public static final String QUERY_TOTAL_STRING = "TOTAL"; public static final String QUERY_ALL_STRING = "ALL"; public static final String SUBQUERY_RANGE_ALL = "ALL"; public static final String SUBQUERY_RANGE_ANY = "ANY"; - + public static final String KEY_QUERY = "query"; public static final String KEY_COMPAT = "compat"; public static final String KEY_COUNT = "count"; @@ -96,17 +104,9 @@ public JSONRequest setFormat(Boolean format) { public static final String KEY_SUBQUERY_RANGE = "range"; public static final String KEY_SUBQUERY_FROM = "from"; - public static final List ARRAY_KEY_LIST; - static { - ARRAY_KEY_LIST = new ArrayList(); - ARRAY_KEY_LIST.add(KEY_QUERY); - ARRAY_KEY_LIST.add(KEY_COMPAT); - ARRAY_KEY_LIST.add(KEY_COUNT); - ARRAY_KEY_LIST.add(KEY_PAGE); - ARRAY_KEY_LIST.add(KEY_JOIN); - ARRAY_KEY_LIST.add(KEY_SUBQUERY_RANGE); - ARRAY_KEY_LIST.add(KEY_SUBQUERY_FROM); - } + public static final List ARRAY_KEY_LIST = new ArrayList<>(Arrays.asList( + KEY_QUERY, KEY_COMPAT ,KEY_COUNT, KEY_PAGE, KEY_JOIN, KEY_SUBQUERY_RANGE, KEY_SUBQUERY_FROM + )); /**set what to query in Array layer * @param query what need to query, Table,total,ALL? @@ -115,86 +115,95 @@ public JSONRequest setFormat(Boolean format) { * @see {@link #QUERY_TOTAL} * @see {@link #QUERY_ALL} */ - public JSONRequest setQuery(int query) { + default JSONRequest setQuery(int query) { return puts(KEY_QUERY, query); } + /**set maximum count of Tables to query in Array layer * @param count <= 0 || >= max ? max : count * @return */ - public JSONRequest setCount(int count) { + default JSONRequest setCount(int count) { return puts(KEY_COUNT, count); } + /**set page of Tables to query in Array layer * @param page <= 0 ? 0 : page * @return */ - public JSONRequest setPage(int page) { + default JSONRequest setPage(int page) { return puts(KEY_PAGE, page); } - + /**set joins of Main Table and it's Vice Tables in Array layer * @param joins "@/User/id@", "&/User/id@,>/Comment/momentId@" ... * @return */ - public JSONRequest setJoin(String... joins) { - return puts(KEY_JOIN, StringUtil.get(joins)); + default JSONRequest setJoin(String... joins) { + return setJson(this, StringUtil.get(joins)); } - + + public static > M setJson(M m, String... joins) { + m.put(KEY_JOIN, StringUtil.get(joins)); + return m; + } + /**set range for Subquery * @param range * @return * @see {@link #SUBQUERY_RANGE_ALL} * @see {@link #SUBQUERY_RANGE_ANY} */ - public JSONRequest setSubqueryRange(String range) { + default JSONRequest setSubqueryRange(String range) { return puts(KEY_SUBQUERY_RANGE, range); } - + /**set from for Subquery * @param from * @return */ - public JSONRequest setSubqueryFrom(String from) { + default JSONRequest setSubqueryFrom(String from) { return puts(KEY_SUBQUERY_FROM, from); } - - //array object >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + //array object >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - /**create a parent JSONObject named KEY_ARRAY + /**create a parent JSONMap named KEY_ARRAY * @param count * @param page * @return {@link #toArray(int, int)} */ - public JSONRequest toArray(int count, int page) { + default M toArray(int count, int page) { return toArray(count, page, null); } - /**create a parent JSONObject named name+KEY_ARRAY. + + /**create a parent JSONMap named name+KEY_ARRAY. * @param count * @param page * @param name * @return {name+KEY_ARRAY : this}. if needs to be put, use {@link #putsAll(Map)} instead */ - public JSONRequest toArray(int count, int page, String name) { - return new JSONRequest(StringUtil.get(name) + KEY_ARRAY, this.setCount(count).setPage(page)); + default M toArray(int count, int page, String name) { + return JSON.createJSONObject(StringUtil.get(name) + KEY_ARRAY, this.setCount(count).setPage(page)); } @Override - public JSONObject putsAll(Map map) { - super.putsAll(map); + default JSONRequest putsAll(Map map) { + putAll(map); return this; } @Override - public JSONRequest puts(Object value) { - return puts(null, value); + default JSONRequest puts(Object value) { + put(value); + return this; } + @Override - public JSONRequest puts(String key, Object value) { - super.puts(key, value); + default JSONRequest puts(String key, Object value) { + put(key, value); return this; } diff --git a/APIJSONORM/src/main/java/apijson/JSONResponse.java b/APIJSONORM/src/main/java/apijson/JSONResponse.java index a405d346f..c39aa1ace 100755 --- a/APIJSONORM/src/main/java/apijson/JSONResponse.java +++ b/APIJSONORM/src/main/java/apijson/JSONResponse.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ @@ -7,8 +7,6 @@ import java.util.*; -import static apijson.JSON.parseObject; - /**parser for response * @author Lemon * @see #getObject @@ -17,8 +15,8 @@ *
User user = response.getObject(User.class);//not a must *
List commenntList = response.getList("Comment[]", Comment.class);//not a must */ -public class JSONResponse, L extends List> extends apijson.JSONObject implements Map { - private static final long serialVersionUID = 1L; +public interface JSONResponse, L extends List> extends JSONMap { + static final String TAG = "JSONResponse"; // 节约性能和减少 bug,除了关键词 @key ,一般都符合变量命名规范,不符合也原样返回便于调试 /**格式化带 - 中横线的单词 @@ -31,23 +29,22 @@ public class JSONResponse, L extends List> */ public static boolean IS_FORMAT_DOLLAR = false; - private static final String TAG = "JSONResponse"; - public JSONResponse() { - super(); - } - public JSONResponse(Object json) { - this(parseObject(json)); - } - public JSONResponse(Object json, JSONParser parser) { - this(parseObject(json, parser)); - } - public JSONResponse(Map object) { - super(format(object)); - } - public JSONResponse(M object, JSONCreator creator) { - super(format(object, creator)); - } + //default JSONResponse() { + // super(); + //} + //default JSONResponse(Object json) { + // this(parseObject(json)); + //} + //default JSONResponse(Object json, JSONParser parser) { + // this(parseObject(json, parser)); + //} + //default JSONResponse(Map object) { + // super(format(object)); + //} + //default JSONResponse(M object, JSONCreator creator) { + // super(format(object, creator)); + //} //状态信息,非GET请求获得的信息<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @@ -85,9 +82,9 @@ public JSONResponse(M object, JSONCreator creator) { /**获取状态 * @return */ - public int getCode() { + default int getCode() { try { - return getIntValue(KEY_CODE); + return JSON.getIntValue(this, KEY_CODE); } catch (Exception e) { //empty } @@ -107,8 +104,8 @@ public static int getCode(Map reponse) { /**获取状态描述 * @return */ - public String getMsg() { - return getString(KEY_MSG); + default String getMsg() { + return JSON.getString(this, KEY_MSG); } /**获取状态描述 * @param response @@ -120,9 +117,9 @@ public static String getMsg(Map response) { /**获取id * @return */ - public long getId() { + default long getId() { try { - return getLongValue(KEY_ID); + return JSON.getLongValue(this, KEY_ID); } catch (Exception e) { //empty } @@ -131,9 +128,9 @@ public long getId() { /**获取数量 * @return */ - public int getCount() { + default int getCount() { try { - return getIntValue(KEY_COUNT); + return JSON.getIntValue(this, KEY_COUNT); } catch (Exception e) { //empty } @@ -142,9 +139,9 @@ public int getCount() { /**获取总数 * @return */ - public int getTotal() { + default int getTotal() { try { - return getIntValue(KEY_TOTAL); + return JSON.getIntValue(this, KEY_TOTAL); } catch (Exception e) { //empty } @@ -155,7 +152,7 @@ public int getTotal() { /**是否成功 * @return */ - public boolean isSuccess() { + default boolean isSuccess() { return isSuccess(getCode()); } /**是否成功 @@ -177,17 +174,13 @@ public static boolean isSuccess(JSONResponse response) { * @return */ public static boolean isSuccess(Map response) { - try { - return response != null && isSuccess(JSON.getIntValue(response, KEY_CODE)); - } catch (IllegalArgumentException e) { - return false; - } + return response != null && isSuccess(JSON.getIntValue(response, KEY_CODE)); } /**校验服务端是否存在table * @return */ - public boolean isExist() { + default boolean isExist() { return isExist(getCount()); } /**校验服务端是否存在table @@ -204,21 +197,18 @@ public static boolean isExist(int count) { public static boolean isExist(JSONResponse response) { return response != null && response.isExist(); } - - /**获取内部的JSONResponse - * @param key - * @return - */ - public JSONResponse getJSONResponse(String key) { - return getObject(key, JSONResponse.class, null); + public static boolean isExist(Map response) { + return response != null && isExist(JSON.getIntValue(response, KEY_COUNT)); } + /**获取内部的JSONResponse * @param key * @return */ - public JSONResponse getJSONResponse(String key, JSONParser parser) { - return getObject(key, JSONResponse.class, parser); + default JSONResponse getJSONResponse(String key) { + return getObject(key, JSONResponse.class); } + //cannot get javaBeanDeserizer // /**获取内部的JSONResponse // * @param response @@ -236,32 +226,16 @@ public JSONResponse getJSONResponse(String key, JSONParser parser) { * @param clazz * @return */ - public T getObject(Class clazz) { - return getObject(clazz == null ? "" : clazz.getSimpleName(), clazz, (JSONParser) DEFAULT_JSON_PARSER); - } - /** - * key = clazz.getSimpleName() - * @param clazz - * @return - */ - public T getObject(Class clazz, JSONParser parser) { - return getObject(clazz == null ? "" : clazz.getSimpleName(), clazz, parser); + default T getObject(Class clazz) { + return getObject(clazz == null ? "" : clazz.getSimpleName(), clazz); } /** * @param key * @param clazz * @return */ - public T getObject(String key, Class clazz) { - return getObject(this, key, clazz, (JSONParser) DEFAULT_JSON_PARSER); - } - /** - * @param key - * @param clazz - * @return - */ - public T getObject(String key, Class clazz, JSONParser parser) { - return getObject(this, key, clazz, parser); + default T getObject(String key, Class clazz) { + return getObject(this, key, clazz); } /** * @param object @@ -269,64 +243,47 @@ public T getObject(String key, Class clazz, JSONParser parser) { * @param clazz * @return */ - public static , L extends List> T getObject( - Map object, String key, Class clazz, JSONParser parser) { - return toObject(object == null ? null : JSON.get(object, formatObjectKey(key)), clazz, parser); + public static T getObject( + Map object, String key, Class clazz) { + return toObject(object == null ? null : JSON.get(object, formatObjectKey(key)), clazz); } /** * @param clazz * @return */ - public T toObject(Class clazz) { - return toObject(clazz, null); - } - /** - * @param clazz - * @return - */ - public T toObject(Class clazz, JSONParser parser) { - return toObject(this, clazz, parser); + default T toObject(Class clazz) { + return toObject(this, clazz); } + /** * @param object * @param clazz * @return */ public static , L extends List> T toObject( - Map object, Class clazz, JSONParser parser) { - return parseObject(object, clazz, parser); + Map object, Class clazz) { + return JSON.parseObject(object, clazz); } - - /** - * key = KEY_ARRAY - * @param clazz - * @return - */ - public List getList(Class clazz, JSONParser> parser) { - return getList(KEY_ARRAY, clazz, parser); - } /** * arrayObject = this * @param key - * @param clazz * @return */ - public List getList(String key, Class clazz, JSONParser> parser) { - return getList(this, key, clazz, parser); + default List getList(String key) { + return JSON.getList(this, key); } /** * key = KEY_ARRAY * @param object - * @param clazz * @return */ - public static > List getList(Map object, Class clazz, JSONParser> parser) { - return getList(object, KEY_ARRAY, clazz, parser); + public static List getList(Map object) { + return JSON.getList(object, KEY_ARRAY); } /** * @param object @@ -334,29 +291,29 @@ public static > List getList(Map> List getList(Map object, String key, Class clazz, JSONParser> parser) { - return object == null ? null : JSON.parseArray(JSON.getString(object, formatArrayKey(key)), clazz, parser); + public static > List getList(Map object, String key, Class clazz) { + return object == null ? null : JSON.parseArray(JSON.getString(object, formatArrayKey(key)), clazz); } /** * key = KEY_ARRAY * @return */ - public JSONArray getArray() { + default > L getArray() { return getArray(KEY_ARRAY); } /** * @param key * @return */ - public JSONArray getArray(String key) { + default > L getArray(String key) { return getArray(this, key); } /** * @param object * @return */ - public static JSONArray getArray(Map object) { + public static > L getArray(Map object) { return getArray(object, KEY_ARRAY); } /** @@ -365,7 +322,7 @@ public static JSONArray getArray(Map object) { * @param key * @return */ - public static JSONArray getArray(Map object, String key) { + public static > L getArray(Map object, String key) { return object == null ? null : JSON.get(object, formatArrayKey(key)); } @@ -373,40 +330,21 @@ public static JSONArray getArray(Map object, String key) { // /** // * @return // */ - // public JSONRequest format() { + // default JSONRequest format() { // return format(this); // } /**格式化key名称 * @param object * @return */ - public static JSONObject format(final Map object) { - // return format(object, JSON.DEFAULT_JSON_CREATOR); - JSONObject obj = new JSONObject(object); - return format(obj, new JSONCreator() { - @Override - public JSONObject createJSONObject() { - return new JSONObject(); - } - - @Override - public JSONArray createJSONArray() { - return new JSONArray(); - } - }); - } - /**格式化key名称 - * @param object - * @return - */ - public static , L extends List> M format(final M object, @NotNull JSONCreator creator) { + public static , L extends List> M format(final M object) { //太长查看不方便,不如debug Log.i(TAG, "format object = \n" + JSON.toJSONString(object)); if (object == null || object.isEmpty()) { Log.i(TAG, "format object == null || object.isEmpty() >> return object;"); return object; } - M formatedObject = creator.createJSONObject(); + M formatedObject = JSON.createJSONObject(); Set set = object.keySet(); if (set != null) { @@ -415,11 +353,11 @@ public static , L extends List> M format(f for (String key : set) { value = object.get(key); - if (value instanceof List) {//JSONArray,遍历来format内部项 - formatedObject.put(formatArrayKey(key), format((L) value, creator)); + if (value instanceof List) {//JSONList,遍历来format内部项 + formatedObject.put(formatArrayKey(key), format((L) value)); } else if (value instanceof Map) {//JSONRequest,往下一级提取 - formatedObject.put(formatObjectKey(key), format((M) value, creator)); + formatedObject.put(formatObjectKey(key), format((M) value)); } else {//其它Object,直接填充 formatedObject.put(formatOtherKey(key), value); @@ -435,45 +373,30 @@ else if (value instanceof Map) {//JSONRequest,往下一级提取 * @param array * @return */ - public static JSONArray format(final List array) { - // return format(array, JSON.DEFAULT_JSON_CREATOR); - JSONArray arr = new JSONArray(array); - return format(arr, new JSONCreator() { - @Override - public JSONObject createJSONObject() { - return new JSONObject(); - } - - @Override - public JSONArray createJSONArray() { - return new JSONArray(); - } - }); - } - public static , L extends List> L format(final L array, @NotNull JSONCreator creator) { + public static , L extends List> L format(final L array) { //太长查看不方便,不如debug Log.i(TAG, "format array = \n" + JSON.toJSONString(array)); if (array == null || array.isEmpty()) { Log.i(TAG, "format array == null || array.isEmpty() >> return array;"); return array; } - L formatedArray = creator.createJSONArray(); + L formattedArray = JSON.createJSONArray(); Object value; for (int i = 0; i < array.size(); i++) { value = array.get(i); - if (value instanceof List) {//JSONArray,遍历来format内部项 - formatedArray.add(format((L) value, creator)); + if (value instanceof List) {//JSONList,遍历来format内部项 + formattedArray.add(format((L) value)); } else if (value instanceof Map) {//JSONRequest,往下一级提取 - formatedArray.add(format((M) value, creator)); + formattedArray.add(format((M) value)); } else {//其它Object,直接填充 - formatedArray.add(value); + formattedArray.add(value); } } - //太长查看不方便,不如debug Log.i(TAG, "format return formatedArray = " + JSON.toJSONString(formatedArray)); - return formatedArray; + //太长查看不方便,不如debug Log.i(TAG, "format return formattedArray = " + JSON.toJSONString(formattedArray)); + return formattedArray; } @@ -492,7 +415,7 @@ public static String getTableName(String fullName) { * @return {@link #formatKey(String, boolean, boolean, boolean, boolean, boolean, Boolean)} formatColon = true, formatAt = true, formatHyphen = true, firstCase = true */ public static String getVariableName(String fullName) { - if (isArrayKey(fullName)) { + if (JSONMap.isArrayKey(fullName)) { fullName = StringUtil.addSuffix(fullName.substring(0, fullName.length() - 2), "list"); } return formatKey(fullName, true, true, true, true, false, true); @@ -503,7 +426,7 @@ public static String getVariableName(String fullName) { * @return {@link #formatKey(String, boolean, boolean, boolean, boolean, boolean, Boolean)} formatColon = false, formatAt = true, formatHyphen = true, firstCase = true */ public static String formatArrayKey(String key) { - if (isArrayKey(key)) { + if (JSONMap.isArrayKey(key)) { key = StringUtil.addSuffix(key.substring(0, key.length() - 2), "list"); } int index = key == null ? -1 : key.indexOf(":"); diff --git a/APIJSONORM/src/main/java/apijson/Log.java b/APIJSONORM/src/main/java/apijson/Log.java index bd091c4e3..ba1a03bd5 100755 --- a/APIJSONORM/src/main/java/apijson/Log.java +++ b/APIJSONORM/src/main/java/apijson/Log.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ @@ -14,7 +14,7 @@ public class Log { public static boolean DEBUG = true; - public static final String VERSION = "8.0.0"; + public static final String VERSION = "8.0.2"; public static final String KEY_SYSTEM_INFO_DIVIDER = "\n---|-----APIJSON SYSTEM INFO-----|---\n"; public static final String OS_NAME; diff --git a/APIJSONORM/src/main/java/apijson/MethodAccess.java b/APIJSONORM/src/main/java/apijson/MethodAccess.java index 31d45843e..1804f7a7b 100755 --- a/APIJSONORM/src/main/java/apijson/MethodAccess.java +++ b/APIJSONORM/src/main/java/apijson/MethodAccess.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. 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 d10a93691..1265ccac7 100755 --- a/APIJSONORM/src/main/java/apijson/NotNull.java +++ b/APIJSONORM/src/main/java/apijson/NotNull.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. 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 875200b7a..27e4cab64 100755 --- a/APIJSONORM/src/main/java/apijson/RequestMethod.java +++ b/APIJSONORM/src/main/java/apijson/RequestMethod.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. 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 110ae3d47..868f0d2aa 100755 --- a/APIJSONORM/src/main/java/apijson/SQL.java +++ b/APIJSONORM/src/main/java/apijson/SQL.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. 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 13b0ff214..179161005 100755 --- a/APIJSONORM/src/main/java/apijson/StringUtil.java +++ b/APIJSONORM/src/main/java/apijson/StringUtil.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java index 76d6a4520..42831775b 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 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ @@ -35,7 +35,7 @@ public abstract class AbstractFunctionParser, L */ public static boolean ENABLE_SCRIPT_FUNCTION = true; - // + // // > public static Map, ? extends List>> SCRIPT_EXECUTOR_MAP; public static Map> FUNCTION_MAP; @@ -234,7 +234,7 @@ public String getArgStr(String path) { return JSON.toJSONString(obj); } - /**根据路径取 JSONObject 值 + /**根据路径取 JSONMap 值 * @param path * @return */ @@ -242,7 +242,7 @@ public Map getArgObj(String path) { return getArgVal(path, Map.class); } - /**根据路径取 JSONArray 值 + /**根据路径取 JSONList 值 * @param path * @return */ @@ -488,7 +488,8 @@ public static , L extends List> Object * @throws Exception */ @SuppressWarnings({"unchecked", "rawtypes"}) - public static , L extends List> Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String methodName + public static , L extends List> Object invoke( + @NotNull AbstractFunctionParser parser, @NotNull String methodName , @NotNull Class[] parameterTypes, @NotNull Object[] args, String returnType , Map current, ScriptExecutor scriptExecutor) throws Exception { if (scriptExecutor != null) { @@ -638,12 +639,12 @@ else if (v instanceof Number) { else if (v instanceof String) { types[i] = String.class; } - else if (v instanceof Map) { // 泛型兼容? // JSONObject + else if (v instanceof Map) { // 泛型兼容? // JSONMap types[i] = Map.class; //性能比较差 //values[i] = TypeUtils.cast(v, Map.class, ParserConfig.getGlobalInstance()); } - else if (v instanceof Collection) { // 泛型兼容? // JSONArray + else if (v instanceof Collection) { // 泛型兼容? // JSONList types[i] = List.class; //性能比较差 List list = new ArrayList<>((Collection) v); @@ -651,14 +652,15 @@ else if (v instanceof Collection) { // 泛型兼容? // JSONArray } else { throw new UnsupportedDataTypeException(keys[i] + ":value 中value不合法!远程函数 key():" - + function + " 中的 arg 对应的值类型只能是 [Boolean, Number, String, JSONObject, JSONArray] 中的一种!"); + + function + " 中的 arg 对应的值类型只能是 [Boolean, Number, String, JSONMap, JSONList] 中的一种!"); } } } else { + Class cls = JSON.createJSONObject().getClass(); types = new Class[length + 1]; //types[0] = Object.class; // 泛型擦除 JSON.JSON_OBJECT_CLASS; - types[0] = JSON.JSON_OBJECT_CLASS; + types[0] = cls; values = new Object[length + 1]; values[0] = request; @@ -725,7 +727,7 @@ public static String extractSchema(String sch, String table) { * @return */ public static String getFunction(String method, String[] keys) { - String f = method + "(JSONObject request"; + String f = method + "(JSONMap request"; if (keys != null) { for (int i = 0; i < keys.length; i++) { @@ -892,7 +894,7 @@ public String toFunctionCallString(boolean useValue, String quote) { * @throws Exception */ public V getArgVal(@NotNull M req, String key, Class clazz) throws Exception { - // Convert to JSONObject for backward compatibility, replace with proper implementation later + // Convert to JSONMap for backward compatibility, replace with proper implementation later return getArgVal(req, key, clazz, false); } @@ -905,7 +907,7 @@ public V getArgVal(@NotNull M req, String key, Class clazz) throws Except * @throws Exception */ public V getArgVal(String key, Class clazz, boolean defaultValue) throws Exception { - Object obj = parser != null && apijson.JSONObject.isArrayKey(key) ? AbstractParser.getValue(request, key.split("\\,")) : request.get(key); + Object obj = parser != null && JSONMap.isArrayKey(key) ? AbstractParser.getValue(request, key.split("\\,")) : request.get(key); if (clazz == null) { return (V) obj; diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java index 9bca5becb..4d56499a0 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 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ @@ -17,9 +17,9 @@ import java.util.Map.Entry; import static apijson.JSON.*; -import static apijson.JSONObject.KEY_COMBINE; -import static apijson.JSONObject.KEY_DROP; -import static apijson.JSONObject.KEY_TRY; +import static apijson.JSONMap.KEY_COMBINE; +import static apijson.JSONMap.KEY_DROP; +import static apijson.JSONMap.KEY_TRY; import static apijson.JSONRequest.*; import static apijson.RequestMethod.POST; import static apijson.RequestMethod.PUT; @@ -79,7 +79,7 @@ public AbstractObjectParser(@NotNull M request, String parentPath, SQLConfig 0; @@ -100,7 +100,7 @@ public AbstractObjectParser(@NotNull M request, String parentPath, SQLConfig parse(String name, boolean isReuse) throws } // Arrays.asList() 返回值不支持 add 方法! whereList = new ArrayList(Arrays.asList(combine != null ? combine : new String[]{})); - whereList.add(apijson.JSONObject.KEY_ID); - whereList.add(apijson.JSONObject.KEY_ID_IN); - // whereList.add(apijson.JSONObject.KEY_USER_ID); - // whereList.add(apijson.JSONObject.KEY_USER_ID_IN); + whereList.add(JSONMap.KEY_ID); + whereList.add(JSONMap.KEY_ID_IN); + // whereList.add(apijson.JSONMap.KEY_USER_ID); + // whereList.add(apijson.JSONMap.KEY_USER_ID_IN); } // 条件>>>>>>>>>>>>>>>>>>> @@ -256,7 +256,10 @@ public AbstractObjectParser parse(String name, boolean isReuse) throws break; } - String key = entry == null ? null : entry.getKey(); + // key 可能为 JSONList,需要进行手动转换(fastjson 为低版本时允许自动转换,如 1.2.21) + // 例如 request json为 "{[]:{"page": 2, "table1":{}}}" + Object field = entry == null ? null : entry.getKey(); + String key = field instanceof Map ? toJSONString(field) : field.toString(); Object value = key == null ? null : entry.getValue(); if (value == null) { continue; @@ -268,7 +271,7 @@ public AbstractObjectParser parse(String name, boolean isReuse) throws Object obj = key.endsWith("@") ? request.get(key) : null; if (obj instanceof Map) { - ((Map) obj).put(apijson.JSONObject.KEY_METHOD, GET); + ((Map) obj).put(JSONMap.KEY_METHOD, GET); } try { @@ -299,7 +302,7 @@ else if (value instanceof Map) { // JSONRequest,往下一级提取 } } else if ((_method == POST || _method == PUT) && value instanceof List - && apijson.JSONObject.isTableArray(key)) { // L,批量新增或修改,往下一级提取 + && JSONMap.isTableArray(key)) { // L,批量新增或修改,往下一级提取 onTableArrayParse(key, (L) value); } else if (_method == PUT && value instanceof List && (whereList == null || whereList.contains(key) == false) @@ -326,38 +329,38 @@ else if (_method == PUT && value instanceof List && (whereList == null || whe String db = parser.getGlobalDatabase(); if (db != null) { - sqlRequest.putIfAbsent(apijson.JSONObject.KEY_DATABASE, db); + sqlRequest.putIfAbsent(JSONMap.KEY_DATABASE, db); } String ds = parser.getGlobalDatasource(); if (ds != null) { - sqlRequest.putIfAbsent(apijson.JSONObject.KEY_DATASOURCE, ds); + sqlRequest.putIfAbsent(JSONMap.KEY_DATASOURCE, ds); } String ns = parser.getGlobalNamespace(); if (ns != null) { - sqlRequest.putIfAbsent(apijson.JSONObject.KEY_NAMESPACE, ns); + sqlRequest.putIfAbsent(JSONMap.KEY_NAMESPACE, ns); } String cl = parser.getGlobalCatalog(); if (cl != null) { - sqlRequest.putIfAbsent(apijson.JSONObject.KEY_CATALOG, cl); + sqlRequest.putIfAbsent(JSONMap.KEY_CATALOG, cl); } String sch = parser.getGlobalSchema(); if (sch != null) { - sqlRequest.putIfAbsent(apijson.JSONObject.KEY_SCHEMA, sch); + sqlRequest.putIfAbsent(JSONMap.KEY_SCHEMA, sch); } if (isSubquery == false) { // 解决 SQL 语法报错,子查询不能 EXPLAIN Boolean exp = parser.getGlobalExplain(); if (sch != null) { - sqlRequest.putIfAbsent(apijson.JSONObject.KEY_EXPLAIN, exp); + sqlRequest.putIfAbsent(JSONMap.KEY_EXPLAIN, exp); } String cache = parser.getGlobalCache(); if (cache != null) { - sqlRequest.putIfAbsent(apijson.JSONObject.KEY_CACHE, cache); + sqlRequest.putIfAbsent(JSONMap.KEY_CACHE, cache); } } } @@ -416,7 +419,7 @@ public boolean onParse(@NotNull String key, @NotNull Object value) throws Except for (Entry e : set) { String k = e == null ? null : e.getKey(); Object v = k == null ? null : e.getValue(); - if (v instanceof Map && apijson.JSONObject.isTableKey(k)) { + if (v instanceof Map && JSONMap.isTableKey(k)) { from = k; arrObj = (M) v; break; @@ -467,9 +470,9 @@ else if (value instanceof String) { // //key{}@ getRealKey, 引用赋值路径 } // 非查询关键词 @key 不影响查询,直接跳过 - if (isTable && (key.startsWith("@") == false || apijson.JSONObject.TABLE_KEY_LIST.contains(key))) { + if (isTable && (key.startsWith("@") == false || JSONMap.TABLE_KEY_LIST.contains(key))) { Log.e(TAG, "onParse isTable && (key.startsWith(@) == false" - + " || apijson.JSONObject.TABLE_KEY_LIST.contains(key)) >> return null;"); + + " || apijson.JSONMap.TABLE_KEY_LIST.contains(key)) >> return null;"); // FIXME getCache() != null 时 return true,解决 RIGHT/OUTER/FOREIGN JOIN 主表无数据导致副表数据也不返回 return false; // 获取不到就不用再做无效的 query 了。不考虑 Table:{Table:{}} 嵌套 } @@ -490,9 +493,9 @@ else if (value instanceof String) { // //key{}@ getRealKey, 引用赋值路径 // Log.d(TAG, "onParse targetPath.equals(target) >>"); // // //非查询关键词 @key 不影响查询,直接跳过 -// if (isTable && (key.startsWith("@") == false || apijson.JSONObject.TABLE_KEY_LIST.contains(key))) { +// if (isTable && (key.startsWith("@") == false || apijson.JSONMap.TABLE_KEY_LIST.contains(key))) { // Log.e(TAG, "onParse isTable && (key.startsWith(@) == false" -// + " || apijson.JSONObject.TABLE_KEY_LIST.contains(key)) >> return null;"); +// + " || apijson.JSONMap.TABLE_KEY_LIST.contains(key)) >> return null;"); // return false;//获取不到就不用再做无效的query了。不考虑 Table:{Table:{}}嵌套 // } else { // Log.d(TAG, "onParse isTable(table) == false >> return true;"); @@ -547,7 +550,7 @@ else if (isPlus) { functionMap.put(type, map); } } - else if (isTable && key.startsWith("@") && apijson.JSONObject.TABLE_KEY_LIST.contains(key) == false) { + else if (isTable && key.startsWith("@") && JSONMap.TABLE_KEY_LIST.contains(key) == false) { customMap.put(key, value); } else { @@ -575,7 +578,7 @@ public Object onChildParse(int index, String key, M value, Object cache) throws Object child; boolean isEmpty; - if (apijson.JSONObject.isArrayKey(key)) { // APIJSON Array + if (JSONMap.isArrayKey(key)) { // APIJSON Array if (isMain) { throw new IllegalArgumentException(parentPath + "/" + key + ":{} 不合法!" + "数组 []:{} 中第一个 key:{} 必须是主表 TableKey:{} !不能为 arrayKey[]:{} !"); @@ -612,7 +615,7 @@ public Object onChildParse(int index, String key, M value, Object cache) throws } } else { //APIJSON Object - boolean isTableKey = apijson.JSONObject.isTableKey(Pair.parseEntry(key, true).getKey()); + boolean isTableKey = JSONMap.isTableKey(Pair.parseEntry(key, true).getKey()); if (type == TYPE_ITEM && isTableKey == false) { throw new IllegalArgumentException(parentPath + "/" + key + ":{} 不合法!" + "数组 []:{} 中每个 key:{} 都必须是表 TableKey:{} 或 数组 arrayKey[]:{} !"); @@ -672,8 +675,8 @@ public void onPUTArrayParse(@NotNull String key, @NotNull L array) throws Except //GET <<<<<<<<<<<<<<<<<<<<<<<<< M rq = JSON.createJSONObject(); - rq.put(apijson.JSONObject.KEY_ID, request.get(apijson.JSONObject.KEY_ID)); - rq.put(apijson.JSONObject.KEY_COLUMN, realKey); + rq.put(JSONMap.KEY_ID, request.get(JSONMap.KEY_ID)); + rq.put(JSONMap.KEY_COLUMN, realKey); M rp = parseResponse(RequestMethod.GET, table, null, rq, null, false); //GET >>>>>>>>>>>>>>>>>>>>>>>>> @@ -682,7 +685,7 @@ public void onPUTArrayParse(@NotNull String key, @NotNull L array) throws Except Object target = rp == null ? null : rp.get(realKey); if (target instanceof String) { try { - target = parseJSON((String) target); + target = JSON.parse(target); } catch (Throwable e) { if (Log.DEBUG) { Log.e(TAG, "try {\n" + @@ -765,7 +768,7 @@ public void onPUTArrayParse(@NotNull String key, @NotNull L array) throws Except @Override public void onTableArrayParse(String key, L valueArray) throws Exception { - String childKey = key.substring(0, key.length() - apijson.JSONObject.KEY_ARRAY.length()); + String childKey = key.substring(0, key.length() - JSONMap.KEY_ARRAY.length()); int allCount = 0; L ids = JSON.createJSONArray(); @@ -804,8 +807,7 @@ public void onTableArrayParse(String key, L valueArray) throws Exception { } Object id = item.get(idKey); - M req = JSON.createJSONObject(); - req.put(childKey, item); + M req = JSON.createJSONObject(childKey, item); M result = null; try { @@ -890,16 +892,17 @@ public void onTableArrayParse(String key, L valueArray) throws Exception { public M parseResponse(RequestMethod method, String table, String alias , M request, List> joinList, boolean isProcedure) throws Exception { SQLConfig config = newSQLConfig(method, table, alias, request, joinList, isProcedure) - .setParser(parser) + .setParser(getParser()) .setObjectParser(this); return parseResponse(config, isProcedure); } @Override public M parseResponse(SQLConfig config, boolean isProcedure) throws Exception { + parser = getParser(); if (parser.getSQLExecutor() == null) { parser.createSQLExecutor(); } - if (parser != null && config.gainParser() == null) { + if (config.gainParser() == null) { config.setParser(parser); } return parser.getSQLExecutor().execute(config, isProcedure); @@ -908,7 +911,7 @@ public M parseResponse(SQLConfig config, boolean isProcedure) throws Ex @Override public SQLConfig newSQLConfig(boolean isProcedure) throws Exception { - String raw = Log.DEBUG == false || sqlRequest == null ? null : getString(sqlRequest, apijson.JSONObject.KEY_RAW); + String raw = Log.DEBUG == false || sqlRequest == null ? null : getString(sqlRequest, JSONMap.KEY_RAW); String[] keys = raw == null ? null : StringUtil.split(raw); if (keys != null && keys.length > 0) { boolean allow = AbstractSQLConfig.ALLOW_MISSING_KEY_4_COMBINE; @@ -926,7 +929,7 @@ public SQLConfig newSQLConfig(boolean isProcedure) throws Exception { } if (parser instanceof AbstractParser) { - ((AbstractParser) parser).putWarnIfNeed(apijson.JSONObject.KEY_RAW, msg); + ((AbstractParser) parser).putWarnIfNeed(JSONMap.KEY_RAW, msg); } break; } @@ -1168,7 +1171,9 @@ else if (isArrayMainTable && position > 0) { // 数组主表使用专门的缓 // APP JOIN 副表时副表返回了这个字段 rawList = (List) result.remove(AbstractSQLExecutor.KEY_RAW_LIST); String arrayPath = parentPath.substring(0, parentPath.lastIndexOf("[]") + 2); - if (isSimpleArray == false) { + if (isSimpleArray) { + parser.putQueryResult(arrayPath, rawList); // 从数组外部引用该数组内值需要 + } else { long startTime = System.currentTimeMillis(); for (int i = 1; i < rawList.size(); i++) { // 从 1 开始,0 已经处理过 @@ -1193,7 +1198,7 @@ else if (isArrayMainTable && position > 0) { // 数组主表使用专门的缓 if (isSubquery == false && result != null) { parser.putQueryResult(path, result); // 解决获取关联数据时requestObject里不存在需要的关联数据 - if (isSimpleArray && rawList != null) { + if (isSimpleArray) { // FIXME 改为从缓存获取,而不是 result 查 result.put(AbstractSQLExecutor.KEY_RAW_LIST, rawList); } } diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java index f2401eeae..cd0b2c7b8 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 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ @@ -28,8 +28,8 @@ import apijson.orm.exception.UnsupportedDataTypeException; import static apijson.JSON.*; -import static apijson.JSONObject.KEY_COMBINE; -import static apijson.JSONObject.KEY_EXPLAIN; +import static apijson.JSONMap.*; +import static apijson.JSONRequest.*; import static apijson.RequestMethod.CRUD; import static apijson.RequestMethod.GET; @@ -37,9 +37,9 @@ * @author Lemon */ public abstract class AbstractParser, L extends List> - implements Parser, ParserCreator, VerifierCreator, SQLCreator { + implements Parser { protected static final String TAG = "AbstractParser"; - + /** * JSON 对象、数组对应的数据源、版本、角色、method等 */ @@ -62,6 +62,12 @@ public abstract class AbstractParser, L extends */ public static boolean IS_PRINT_REQUEST_ENDTIME_LOG = false; + /** + * 可以通过切换该变量来控制返回 trace:stack 字段,如果是 gson 则不设置为 false,避免序列化报错。 + * 与 {@link Log#DEBUG} 任何一个为 true 返回 trace:stack 字段。 + */ + public static boolean IS_RETURN_STACK_TRACE = true; + /** * 分页页码是否从 1 开始,默认为从 0 开始 @@ -411,7 +417,6 @@ public AbstractParser setNeedVerifyContent(boolean needVerifyContent) { return this; } - protected SQLExecutor sqlExecutor; protected Verifier verifier; protected Map queryResultMap;//path-result @@ -420,8 +425,8 @@ public AbstractParser setNeedVerifyContent(boolean needVerifyContent) { public SQLExecutor getSQLExecutor() { if (sqlExecutor == null) { sqlExecutor = createSQLExecutor(); - sqlExecutor.setParser(this); } + sqlExecutor.setParser(this); return sqlExecutor; } @Override @@ -429,9 +434,25 @@ public Verifier getVerifier() { if (verifier == null) { verifier = createVerifier().setVisitor(getVisitor()); } + verifier.setParser(this); return verifier; } + /**解析请求JSONObject + * @param request => URLDecoder.decode(request, UTF_8); + * @return + * @throws Exception + */ + public static > M parseRequest(String request) throws Exception { + try { + M req = JSON.parseObject(request); + Objects.requireNonNull(req); + return req; + } catch (Throwable e) { + throw new UnsupportedEncodingException("JSON格式不合法!" + e.getMessage() + "! " + request); + } + } + /**解析请求json并获取对应结果 * @param request * @return @@ -461,7 +482,7 @@ public M parseResponse(String request) { + requestMethod + "/parseResponse request = \n" + request + "\n\n"); try { - requestObject = (M) JSON.parseObject(request); + requestObject = JSON.parseObject(request); if (requestObject == null) { throw new UnsupportedEncodingException("JSON格式不合法!"); } @@ -488,12 +509,19 @@ public M parseResponse(M request) { requestObject = request; try { - setVersion(getIntValue(requestObject, apijson.JSONRequest.KEY_VERSION)); - requestObject.remove(apijson.JSONRequest.KEY_VERSION); + setGlobalFormat(getBoolean(requestObject, KEY_FORMAT)); + requestObject.remove(KEY_FORMAT); + } catch (Exception e) { + return extendErrorResult(requestObject, e, requestMethod, getRequestURL(), isRoot); + } + + try { + setVersion(getIntValue(requestObject, KEY_VERSION)); + requestObject.remove(KEY_VERSION); if (getMethod() != RequestMethod.CRUD) { - setTag(getString(requestObject, apijson.JSONRequest.KEY_TAG)); - requestObject.remove(apijson.JSONRequest.KEY_TAG); + setTag(getString(requestObject, KEY_TAG)); + requestObject.remove(KEY_TAG); } } catch (Exception e) { return extendErrorResult(requestObject, e, requestMethod, getRequestURL(), isRoot); @@ -517,40 +545,37 @@ public M parseResponse(M request) { //必须在parseCorrectRequest后面,因为parseCorrectRequest可能会添加 @role if (isNeedVerifyRole() && globalRole == null) { try { - setGlobalRole(getString(requestObject, apijson.JSONObject.KEY_ROLE)); - requestObject.remove(apijson.JSONObject.KEY_ROLE); + setGlobalRole(getString(requestObject, KEY_ROLE)); + requestObject.remove(KEY_ROLE); } catch (Exception e) { return extendErrorResult(requestObject, e, requestMethod, getRequestURL(), isRoot); } } try { - setGlobalDatabase(getString(requestObject, apijson.JSONObject.KEY_DATABASE)); - setGlobalDatasource(getString(requestObject, apijson.JSONObject.KEY_DATASOURCE)); - setGlobalNamespace(getString(requestObject, apijson.JSONObject.KEY_NAMESPACE)); - setGlobalCatalog(getString(requestObject, apijson.JSONObject.KEY_CATALOG)); - setGlobalSchema(getString(requestObject, apijson.JSONObject.KEY_SCHEMA)); - - setGlobalExplain(getBoolean(requestObject, apijson.JSONObject.KEY_EXPLAIN)); - setGlobalCache(getString(requestObject, apijson.JSONObject.KEY_CACHE)); - setGlobalFormat(getBoolean(requestObject, apijson.JSONRequest.KEY_FORMAT)); - - requestObject.remove(apijson.JSONObject.KEY_DATABASE); - requestObject.remove(apijson.JSONObject.KEY_DATASOURCE); - requestObject.remove(apijson.JSONObject.KEY_NAMESPACE); - requestObject.remove(apijson.JSONObject.KEY_CATALOG); - requestObject.remove(apijson.JSONObject.KEY_SCHEMA); - - requestObject.remove(apijson.JSONObject.KEY_EXPLAIN); - requestObject.remove(apijson.JSONObject.KEY_CACHE); - requestObject.remove(apijson.JSONRequest.KEY_FORMAT); + setGlobalDatabase(getString(requestObject, KEY_DATABASE)); + setGlobalDatasource(getString(requestObject, KEY_DATASOURCE)); + setGlobalNamespace(getString(requestObject, KEY_NAMESPACE)); + setGlobalCatalog(getString(requestObject, KEY_CATALOG)); + setGlobalSchema(getString(requestObject, KEY_SCHEMA)); + + setGlobalExplain(getBoolean(requestObject, KEY_EXPLAIN)); + setGlobalCache(getString(requestObject, KEY_CACHE)); + + requestObject.remove(KEY_DATABASE); + requestObject.remove(KEY_DATASOURCE); + requestObject.remove(KEY_NAMESPACE); + requestObject.remove(KEY_CATALOG); + requestObject.remove(KEY_SCHEMA); + + requestObject.remove(KEY_EXPLAIN); + requestObject.remove(KEY_CACHE); } catch (Exception e) { return extendErrorResult(requestObject, e, requestMethod, getRequestURL(), isRoot); } final String requestString = JSON.toJSONString(request);//request传进去解析后已经变了 - queryResultMap = new HashMap(); Exception error = null; @@ -575,24 +600,22 @@ public M parseResponse(M request) { requestObject = error == null ? extendSuccessResult(requestObject, warn, isRoot) : extendErrorResult(requestObject, error, requestMethod, getRequestURL(), isRoot); - M res = (globalFormat != null && globalFormat) && JSONResponse.isSuccess(requestObject) ? JSONResponse.format(requestObject, new JSONCreator>() { - @Override - public M createJSONObject() { - return JSON.createJSONObject(); - } + // FIXME 暂时先直接移除,后续排查是在哪里 put 进来 + requestObject.remove(KEY_DATABASE); + requestObject.remove(KEY_DATASOURCE); + requestObject.remove(KEY_NAMESPACE); + requestObject.remove(KEY_CATALOG); + requestObject.remove(KEY_SCHEMA); - @Override - public List createJSONArray() { - return JSON.createJSONArray(); - } - }) : requestObject; + M res = (globalFormat != null && globalFormat) && JSONResponse.isSuccess(requestObject) ? JSONResponse.format(requestObject) : requestObject; long endTime = System.currentTimeMillis(); long duration = endTime - startTime; res.putIfAbsent("time", endTime); if (Log.DEBUG) { - res.put("sql:generate|cache|execute|maxExecute", getSQLExecutor().getGeneratedSQLCount() + "|" + getSQLExecutor().getCachedSQLCount() + "|" + getSQLExecutor().getExecutedSQLCount() + "|" + getMaxSQLCount()); + sqlExecutor = getSQLExecutor(); + res.put("sql:generate|cache|execute|maxExecute", sqlExecutor.getGeneratedSQLCount() + "|" + sqlExecutor.getCachedSQLCount() + "|" + sqlExecutor.getExecutedSQLCount() + "|" + getMaxSQLCount()); res.put("depth:count|max", queryDepth + "|" + getMaxQueryDepth()); executedSQLDuration += sqlExecutor.getExecutedSQLDuration() + sqlExecutor.getSqlResultDuration(); @@ -605,7 +628,19 @@ public List createJSONArray() { // } Throwable t = error instanceof CommonException && error.getCause() != null ? error.getCause() : error; res.put("trace:throw", t.getClass().getName()); - res.put("trace:stack", t.getStackTrace()); + + if (IS_RETURN_STACK_TRACE) { + L list = JSON.createJSONArray(); + + StackTraceElement[] traces = t.getStackTrace(); + if (traces != null) { // && traces.length > 0) { + for (StackTraceElement trace : traces) { + list.add(trace == null ? null : trace.toString()); + } + } + + res.put("trace:stack", list); + } } } @@ -623,6 +658,7 @@ public List createJSONArray() { Log.fd(TAG, requestMethod + "/parseResponse endTime = " + endTime + "; duration = " + duration); Log.sl("", '>', "\n\n\n"); } + return res; } @@ -670,31 +706,31 @@ public M parseCorrectRequest(RequestMethod method, String tag, int version, Stri return batchVerify(method, tag, version, name, request, maxUpdateCount, creator); } - + /**自动根据 tag 是否为 TableKey 及是否被包含在 object 内来决定是否包装一层,改为 { tag: object, "tag": tag } * @param object * @param tag * @return */ - public M wrapRequest(RequestMethod method, String tag, M object, boolean isStructure, JSONCreator creator) { + public M wrapRequest(RequestMethod method, String tag, M object, boolean isStructure) { boolean putTag = ! isStructure; if (object == null || object.containsKey(tag)) { //tag 是 Table 名或 Table[] if (putTag) { if (object == null) { - object = creator.createJSONObject(); + object = JSON.createJSONObject(); } - object.put(apijson.JSONRequest.KEY_TAG, tag); + object.put(KEY_TAG, tag); } return object; } boolean isDiffArrayKey = tag.endsWith(":[]"); - boolean isArrayKey = isDiffArrayKey || apijson.JSONObject.isArrayKey(tag); + boolean isArrayKey = isDiffArrayKey || isArrayKey(tag); String key = isArrayKey ? tag.substring(0, tag.length() - (isDiffArrayKey ? 3 : 2)) : tag; M target = object; - if (apijson.JSONObject.isTableKey(key)) { + if (isTableKey(key)) { if (isDiffArrayKey) { //自动为 tag = Comment:[] 的 { ... } 新增键值对为 { "Comment[]":[], "TYPE": { "Comment[]": "OBJECT[]" } ... } if (isStructure && (method == RequestMethod.POST || method == RequestMethod.PUT)) { String arrKey = key + "[]"; @@ -721,18 +757,18 @@ public M wrapRequest(RequestMethod method, String tag, M object, boolean isStruc } else { //自动为 tag = Comment 的 { ... } 包一层为 { "Comment": { ... } } if (isArrayKey == false || RequestMethod.isGetMethod(method, true)) { - target = creator.createJSONObject(); + target = JSON.createJSONObject(); target.put(tag, object); } else if (target.containsKey(key) == false) { - target = creator.createJSONObject(); + target = JSON.createJSONObject(); target.put(key, object); } } } if (putTag) { - target.put(apijson.JSONRequest.KEY_TAG, tag); + target.put(KEY_TAG, tag); } return target; @@ -991,7 +1027,7 @@ public M newErrorResult(Exception e, boolean isRoot) { // } String msg = CommonException.getMsg(e); - Integer code = CommonException.getCode(e); + int code = CommonException.getCode(e); return newResult(code, msg, null, isRoot); } @@ -1069,18 +1105,19 @@ public M getStructure(@NotNull String table, String method, String tag, int vers // 获取指定的JSON结构 <<<<<<<<<<<<<< SQLConfig config = createSQLConfig().setMethod(GET).setTable(table); + config.setParser(this); config.setPrepared(false); config.setColumn(Arrays.asList("structure")); Map where = new HashMap(); where.put("method", method); - where.put(apijson.JSONRequest.KEY_TAG, tag); + where.put(KEY_TAG, tag); if (version > 0) { - where.put(apijson.JSONRequest.KEY_VERSION + ">=", version); + where.put(KEY_VERSION + ">=", version); } config.setWhere(where); - config.setOrder(apijson.JSONRequest.KEY_VERSION + (version > 0 ? "+" : "-")); + config.setOrder(KEY_VERSION + (version > 0 ? "+" : "-")); config.setCount(1); // too many connections error: 不try-catch,可以让客户端看到是服务器内部异常 @@ -1140,7 +1177,7 @@ public M onObjectParse(final M request, String parentPath, String name String table = entry.getKey(); //Comment // String alias = entry.getValue(); //to - boolean isTable = apijson.JSONObject.isTableKey(table); + boolean isTable = isTableKey(table); boolean isArrayMainTable = isSubquery == false && isTable && type == SQLConfig.TYPE_ITEM_CHILD_0 && arrayConfig != null && RequestMethod.isGetMethod(arrayConfig.getMethod(), true); boolean isReuse = isArrayMainTable && position > 0; @@ -1289,7 +1326,7 @@ public L onArrayParse(M request, String parentPath, String name, boolean isSubqu } //不能允许GETS,否则会被通过"[]":{"@role":"ADMIN"},"Table":{},"tag":"Table"绕过权限并能批量查询 - RequestMethod _method = request.get(apijson.JSONObject.KEY_METHOD) == null ? requestMethod : RequestMethod.valueOf(getString(request, apijson.JSONObject.KEY_METHOD)); + RequestMethod _method = request.get(KEY_METHOD) == null ? requestMethod : RequestMethod.valueOf(getString(request, KEY_METHOD)); if (isSubquery == false && RequestMethod.isGetMethod(_method, true) == false) { throw new UnsupportedOperationException("key[]:{} 只支持 GET, GETS 方法!其它方法不允许传 " + name + ":{} 等这种 key[]:{} 格式!"); } @@ -1373,7 +1410,7 @@ public L onArrayParse(M request, String parentPath, String name, boolean isSubqu if (childKeys == null || childKeys.length <= 0 || request.containsKey(childKeys[0]) == false) { childKeys = null; } - else if (childKeys.length == 1 && apijson.JSONObject.isTableKey(childKeys[0])) { // 可能无需提取,直接返回 rawList 即可 + else if (childKeys.length == 1 && isTableKey(childKeys[0])) { // 可能无需提取,直接返回 rawList 即可 arrTableKey = childKeys[0]; } @@ -1479,26 +1516,26 @@ else if (childKeys.length == 1 && apijson.JSONObject.isTableKey(childKeys[0])) { private static final List JOIN_COPY_KEY_LIST; static { // TODO 不全 JOIN_COPY_KEY_LIST = new ArrayList(); - JOIN_COPY_KEY_LIST.add(apijson.JSONObject.KEY_ROLE); - JOIN_COPY_KEY_LIST.add(apijson.JSONObject.KEY_DATABASE); - JOIN_COPY_KEY_LIST.add(apijson.JSONObject.KEY_NAMESPACE); - JOIN_COPY_KEY_LIST.add(apijson.JSONObject.KEY_CATALOG); - JOIN_COPY_KEY_LIST.add(apijson.JSONObject.KEY_SCHEMA); - JOIN_COPY_KEY_LIST.add(apijson.JSONObject.KEY_DATASOURCE); - JOIN_COPY_KEY_LIST.add(apijson.JSONObject.KEY_COLUMN); - JOIN_COPY_KEY_LIST.add(apijson.JSONObject.KEY_NULL); - JOIN_COPY_KEY_LIST.add(apijson.JSONObject.KEY_CAST); - JOIN_COPY_KEY_LIST.add(apijson.JSONObject.KEY_COMBINE); - JOIN_COPY_KEY_LIST.add(apijson.JSONObject.KEY_GROUP); - JOIN_COPY_KEY_LIST.add(apijson.JSONObject.KEY_HAVING); - JOIN_COPY_KEY_LIST.add(apijson.JSONObject.KEY_HAVING_AND); - JOIN_COPY_KEY_LIST.add(apijson.JSONObject.KEY_SAMPLE); - JOIN_COPY_KEY_LIST.add(apijson.JSONObject.KEY_LATEST); - JOIN_COPY_KEY_LIST.add(apijson.JSONObject.KEY_PARTITION); - JOIN_COPY_KEY_LIST.add(apijson.JSONObject.KEY_FILL); - JOIN_COPY_KEY_LIST.add(apijson.JSONObject.KEY_ORDER); - JOIN_COPY_KEY_LIST.add(apijson.JSONObject.KEY_KEY); - JOIN_COPY_KEY_LIST.add(apijson.JSONObject.KEY_RAW); + JOIN_COPY_KEY_LIST.add(KEY_ROLE); + JOIN_COPY_KEY_LIST.add(KEY_DATABASE); + JOIN_COPY_KEY_LIST.add(KEY_NAMESPACE); + JOIN_COPY_KEY_LIST.add(KEY_CATALOG); + JOIN_COPY_KEY_LIST.add(KEY_SCHEMA); + JOIN_COPY_KEY_LIST.add(KEY_DATASOURCE); + JOIN_COPY_KEY_LIST.add(KEY_COLUMN); + JOIN_COPY_KEY_LIST.add(KEY_NULL); + JOIN_COPY_KEY_LIST.add(KEY_CAST); + JOIN_COPY_KEY_LIST.add(KEY_COMBINE); + JOIN_COPY_KEY_LIST.add(KEY_GROUP); + JOIN_COPY_KEY_LIST.add(KEY_HAVING); + JOIN_COPY_KEY_LIST.add(KEY_HAVING_AND); + JOIN_COPY_KEY_LIST.add(KEY_SAMPLE); + JOIN_COPY_KEY_LIST.add(KEY_LATEST); + JOIN_COPY_KEY_LIST.add(KEY_PARTITION); + JOIN_COPY_KEY_LIST.add(KEY_FILL); + JOIN_COPY_KEY_LIST.add(KEY_ORDER); + JOIN_COPY_KEY_LIST.add(KEY_KEY); + JOIN_COPY_KEY_LIST.add(KEY_RAW); } /**JOIN 多表同时筛选 @@ -1526,7 +1563,39 @@ else if (join != null){ throw new UnsupportedDataTypeException(TAG + ".onJoinParse join 只能是 String 或 Map 类型!"); } - Set> set = joinMap == null ? null : joinMap.entrySet(); + List> slashKeys = new ArrayList<>(); + List> nonSlashKeys = new ArrayList<>(); + Set> entries = joinMap == null ? null : joinMap.entrySet(); + + if (entries == null || entries.isEmpty()) { + Log.e(TAG, "onJoinParse set == null || set.isEmpty() >> return null;"); + return null; + } + for (Entry e : entries) { + String path = e.getKey(); + if (path != null && path.indexOf("/") > 0) { + slashKeys.add(e); // 以 / 开头的 key,例如 whereJoinMap = new LinkedHashMap<>(); + + for (Entry e : nonSlashKeys) { + String tableKey = e.getKey(); // 如 "Location_info" + Object tableObj = e.getValue(); // value 是 Map + + if (request.containsKey(tableKey)) { + whereJoinMap.put(tableKey, tableObj); + } else { + Log.w(TAG, "跳过 join 中 key = " + tableKey + ",因为它不在 request 中"); + } + } + + + Set> set = joinMap == null ? null : new LinkedHashSet<>(slashKeys); + if (set == null || set.isEmpty()) { Log.e(TAG, "onJoinParse set == null || set.isEmpty() >> return null;"); return null; @@ -1559,7 +1628,7 @@ else if (join != null){ String tableKey = index < 0 ? path : path.substring(0, index); // User:owner int index2 = tableKey.lastIndexOf("/"); String arrKey = index2 < 0 ? null : tableKey.substring(0, index2); - if (arrKey != null && apijson.JSONObject.isArrayKey(arrKey) == false) { + if (arrKey != null && isArrayKey(arrKey) == false) { throw new IllegalArgumentException(apijson.JSONRequest.KEY_JOIN + ":'" + e.getKey() + "' 对应的 " + arrKey + " 不是合法的数组 key[] !" + "@ APP JOIN 最多允许跨 1 层,只能是子数组,且数组对象中不能有 join: value 键值对!"); } @@ -1662,7 +1731,7 @@ else if (join != null){ apijson.orm.Entry te = tk == null || p.substring(ind2 + 1).indexOf("/") >= 0 ? null : Pair.parseEntry(tk, true); - if (te != null && apijson.JSONObject.isTableKey(te.getKey()) && request.get(tk) instanceof Map) { + if (te != null && isTableKey(te.getKey()) && request.get(tk) instanceof Map) { if (isAppJoin) { if (refObj.size() >= 1) { throw new IllegalArgumentException(apijson.JSONRequest.KEY_JOIN + ":" + e.getKey() + " 中 " + k + " 不合法!" @@ -1722,9 +1791,15 @@ else if (join != null){ j.setAlias(alias); M outerObj = (M) JSON.createJSONObject((Map) outer); - j.setOuter(outerObj); + j.setOn(outerObj); j.setRequest(requestObj); + if (whereJoinMap.containsKey(table)) { + Object rawOuter = whereJoinMap.get(table); + M outerObj1 = (M) JSON.createJSONObject((Map) rawOuter); + j.setOuter(outerObj1); + } + if (arrKey != null) { Integer count = getInteger(parentPathObj, apijson.JSONRequest.KEY_COUNT); j.setCount(count == null ? getDefaultQueryCount() : count); @@ -1827,24 +1902,32 @@ else if (join != null){ * @param pathKeys * @return */ - public static V getValue(Map parent, String[] pathKeys) { - if (parent == null || pathKeys == null || pathKeys.length <= 0) { + public static V getValue(Object parent, String[] pathKeys) { + int len = parent == null || pathKeys == null ? 0 : pathKeys.length; + if (len <= 0) { Log.w(TAG, "getChild parent == null || pathKeys == null || pathKeys.length <= 0 >> return parent;"); return (V) parent; } - //逐层到达child的直接容器JSONObject parent - int last = pathKeys.length - 1; - for (int i = 0; i < last; i++) {//一步一步到达指定位置 - if (parent == null) {//不存在或路径错误(中间的key对应value不是JSONObject) + // 逐层到达child的直接容器JSONObject parent + Object v = parent; + for (int i = 0; i < len; i++) { // 一步一步到达指定位置 + if (v == null) { // 不存在或路径错误(中间的key对应value不是JSONObject) break; } String k = getDecodedKey(pathKeys[i]); - parent = JSON.get(parent, k); + try { + v = getFromObjOrArr(v, k); + } catch (Throwable e) { + if (IS_PRINT_BIG_LOG) { + e.printStackTrace(); + } + v = null; + } } - return parent == null ? null : (V) parent.get(getDecodedKey(pathKeys[last])); + return (V) v; } @@ -1950,13 +2033,13 @@ public Object getValueByPath(String valuePath) { } //取出key被valuePath包含的result,再从里面获取key对应的value - Map parent = null; + Object parent = null; String[] keys = null; for (Entry entry : queryResultMap.entrySet()){ String path = entry.getKey(); if (valuePath.startsWith(path + "/")) { try { - parent = (M) entry.getValue(); + parent = entry.getValue(); } catch (Exception e) { Log.e(TAG, "getValueByPath try { parent = (Map) queryResultMap.get(path); } catch { " + "\n parent not instanceof Map!"); @@ -1969,39 +2052,13 @@ public Object getValueByPath(String valuePath) { } } - //逐层到达targetKey的直接容器JSONObject parent - int last = keys == null ? -1 : keys.length - 1; - if (last >= 1) { - for (int i = 0; i < last; i++) {//一步一步到达指定位置parentPath - if (parent == null) {//不存在或路径错误(中间的key对应value不是JSONObject) - break; - } - - String k = getDecodedKey(keys[i]); - Object p = parent.get(k); - parent = p instanceof Map ? (Map) p : null; - } - } - - if (parent != null) { - Log.i(TAG, "getValueByPath >> get from queryResultMap >> return parent.get(keys[keys.length - 1]);"); - target = last < 0 ? parent : parent.get(getDecodedKey(keys[last])); //值为null应该报错NotExistExeption,一般都是id关联,不可为null,否则可能绕过安全机制 - if (target != null) { - Log.i(TAG, "getValueByPath >> getValue >> return target = " + target); - return target; - } - } - - - //从requestObject中取值 - target = getValue(requestObject, StringUtil.splitPath(valuePath)); - if (target != null) { - Log.i(TAG, "getValueByPath >> getValue >> return target = " + target); - return target; + target = getValue(parent, keys); // 逐层到达targetKey的直接容器JSONObject parent + if (target == null) { //从requestObject中取值 + target = getValue(requestObject, StringUtil.splitPath(valuePath)); } - Log.i(TAG, "getValueByPath return null;"); - return null; + Log.i(TAG, "getValueByPath >> getValue >> return target = " + target); + return target; } /**解码 引用赋值 路径中的 key,支持把 URL encode 后的值,转为 decode 后的原始值,例如 %2Fuser%2Flist -> /user/list ; %7B%7D -> [] @@ -2089,8 +2146,7 @@ public M executeSQL(SQLConfig config, boolean isSubquery) throws Except } } else { - sqlExecutor = getSQLExecutor(); - result = sqlExecutor.execute(config, false); + result = getSQLExecutor().execute(config, false); // FIXME 改为直接在 sqlExecutor 内加好,最后 Parser 取结果,可以解决并发执行导致内部计算出错 // executedSQLDuration += sqlExecutor.getExecutedSQLDuration() + sqlExecutor.getSqlResultDuration(); } @@ -2213,7 +2269,7 @@ protected void onClose() { } private void setOpMethod(Map request, ObjectParser op, String key) { - String _method = key == null ? null : getString(request, apijson.JSONObject.KEY_METHOD); + String _method = key == null ? null : getString(request, KEY_METHOD); if (_method != null) { RequestMethod method = RequestMethod.valueOf(_method); // 必须精准匹配,避免缓存命中率低 this.setMethod(method); @@ -2237,6 +2293,18 @@ protected M getRequestStructure(RequestMethod method, String tag, int version) t return object; } + public static final Map KEY_METHOD_ENUM_MAP; + static { + KEY_METHOD_ENUM_MAP = new LinkedHashMap<>(); + KEY_METHOD_ENUM_MAP.put(KEY_GET, RequestMethod.GET); + KEY_METHOD_ENUM_MAP.put(KEY_GETS, RequestMethod.GETS); + KEY_METHOD_ENUM_MAP.put(KEY_HEAD, RequestMethod.HEAD); + KEY_METHOD_ENUM_MAP.put(KEY_HEADS, RequestMethod.HEADS); + KEY_METHOD_ENUM_MAP.put(KEY_POST, RequestMethod.POST); + KEY_METHOD_ENUM_MAP.put(KEY_PUT, RequestMethod.PUT); + KEY_METHOD_ENUM_MAP.put(KEY_DELETE, RequestMethod.DELETE); + } + 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等 @@ -2248,14 +2316,14 @@ protected M batchVerify(RequestMethod method, String tag, int version, String na for (String key : reqSet) { // key 重复直接抛错(xxx:alias, xxx:alias[]) - if (correctRequest.containsKey(key) || correctRequest.containsKey(key + apijson.JSONObject.KEY_ARRAY)) { + if (correctRequest.containsKey(key) || correctRequest.containsKey(key + KEY_ARRAY)) { throw new IllegalArgumentException("对象名重复,请添加别名区分 ! 重复对象名为: " + key); } - boolean isPost = apijson.JSONObject.KEY_POST.equals(key); + boolean isPost = KEY_POST.equals(key); // @post、@get 等 RequestMethod try { - RequestMethod keyMethod = isPost ? RequestMethod.POST : apijson.JSONObject.KEY_METHOD_ENUM_MAP.get(key); + RequestMethod keyMethod = isPost ? RequestMethod.POST : KEY_METHOD_ENUM_MAP.get(key); if (keyMethod != null) { // 如果不匹配,异常不处理即可 removeTmpKeys.add(key); @@ -2273,7 +2341,7 @@ protected M batchVerify(RequestMethod method, String tag, int version, String na throw new ConflictException(key + ": value 中 " + tbl + " 已经存在,不能重复!"); } - obj.put(tbl, isPost && apijson.JSONObject.isTableArray(tbl) + obj.put(tbl, isPost && isTableArray(tbl) ? tbl.substring(0, tbl.length() - 2) + ":[]" : ""); } } @@ -2292,14 +2360,14 @@ protected M batchVerify(RequestMethod method, String tag, int version, String na } Map objAttrMap = new HashMap<>(); - objAttrMap.put(apijson.JSONObject.KEY_METHOD, keyMethod); + 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(apijson.JSONRequest.KEY_TAG, "".equals(objVal) ? objKey : objVal); + objAttrMap.put(KEY_TAG, "".equals(objVal) ? objKey : objVal); } else { throw new IllegalArgumentException(key + ": { " + objKey + ": value 中 value 类型错误,只能是 String 或 Map {} !"); @@ -2316,14 +2384,14 @@ protected M batchVerify(RequestMethod method, String tag, int version, String na } switch (objAttrKey) { - case apijson.JSONObject.KEY_DATASOURCE: - case apijson.JSONObject.KEY_SCHEMA: - case apijson.JSONObject.KEY_DATABASE: - case apijson.JSONRequest.KEY_VERSION: - case apijson.JSONObject.KEY_ROLE: + case KEY_DATASOURCE: + case KEY_SCHEMA: + case KEY_DATABASE: + case KEY_VERSION: + case KEY_ROLE: objAttrMap.put(objAttrKey, entry.getValue()); break; - case apijson.JSONRequest.KEY_TAG: + case KEY_TAG: hasTag = true; objAttrMap.put(objAttrKey, entry.getValue()); break; @@ -2333,7 +2401,7 @@ protected M batchVerify(RequestMethod method, String tag, int version, String na } if (hasTag == false) { - objAttrMap.put(apijson.JSONRequest.KEY_TAG, isPost && apijson.JSONObject.isTableArray(objKey) + objAttrMap.put(KEY_TAG, isPost && isTableArray(objKey) ? objKey.substring(0, objKey.length() - 2) + ":[]" : objKey); } } @@ -2352,33 +2420,33 @@ protected M batchVerify(RequestMethod method, String tag, int version, String na if (attrMap == null) { // 数组会解析为对象进行校验,做一下兼容 - if (keyObjectAttributesMap.get(key + apijson.JSONObject.KEY_ARRAY) == null) { + if (keyObjectAttributesMap.get(key + KEY_ARRAY) == null) { if (method == RequestMethod.CRUD || key.endsWith("@")) { - ((Map) obj).put(apijson.JSONObject.KEY_METHOD, GET); + ((Map) obj).put(KEY_METHOD, GET); Map objAttrMap = new HashMap<>(); - objAttrMap.put(apijson.JSONObject.KEY_METHOD, GET); + objAttrMap.put(KEY_METHOD, GET); keyObjectAttributesMap.put(key, objAttrMap); } else { - ((Map) obj).put(apijson.JSONObject.KEY_METHOD, method); + ((Map) obj).put(KEY_METHOD, method); Map objAttrMap = new HashMap<>(); - objAttrMap.put(apijson.JSONObject.KEY_METHOD, method); + objAttrMap.put(KEY_METHOD, method); keyObjectAttributesMap.put(key, objAttrMap); } } else { - setRequestAttribute(key, true, apijson.JSONObject.KEY_METHOD, request); - setRequestAttribute(key, true, apijson.JSONObject.KEY_DATASOURCE, request); - setRequestAttribute(key, true, apijson.JSONObject.KEY_SCHEMA, request); - setRequestAttribute(key, true, apijson.JSONObject.KEY_DATABASE, request); - setRequestAttribute(key, true, apijson.JSONRequest.KEY_VERSION, request); - setRequestAttribute(key, true, apijson.JSONObject.KEY_ROLE, request); + setRequestAttribute(key, true, KEY_METHOD, request); + setRequestAttribute(key, true, KEY_DATASOURCE, request); + setRequestAttribute(key, true, KEY_SCHEMA, request); + setRequestAttribute(key, true, KEY_DATABASE, request); + setRequestAttribute(key, true, KEY_VERSION, request); + setRequestAttribute(key, true, KEY_ROLE, request); } } else { - setRequestAttribute(key, false, apijson.JSONObject.KEY_METHOD, request); - setRequestAttribute(key, false, apijson.JSONObject.KEY_DATASOURCE, request); - setRequestAttribute(key, false, apijson.JSONObject.KEY_SCHEMA, request); - setRequestAttribute(key, false, apijson.JSONObject.KEY_DATABASE, request); - setRequestAttribute(key, false, apijson.JSONRequest.KEY_VERSION, request); - setRequestAttribute(key, false, apijson.JSONObject.KEY_ROLE, request); + setRequestAttribute(key, false, KEY_METHOD, request); + setRequestAttribute(key, false, KEY_DATASOURCE, request); + setRequestAttribute(key, false, KEY_SCHEMA, request); + setRequestAttribute(key, false, KEY_DATABASE, request); + setRequestAttribute(key, false, KEY_VERSION, request); + setRequestAttribute(key, false, KEY_ROLE, request); } } @@ -2391,7 +2459,7 @@ protected M batchVerify(RequestMethod method, String tag, int version, String na RequestMethod _method; if (obj instanceof Map) { Map tblObj = JSON.getMap(request, key); - String mn = tblObj == null ? null : getString(tblObj, apijson.JSONObject.KEY_METHOD); + String mn = tblObj == null ? null : getString(tblObj, KEY_METHOD); _method = mn == null ? null : RequestMethod.valueOf(mn); String combine = _method == null ? null : getString(tblObj, KEY_COMBINE); if (combine != null && RequestMethod.isPublicMethod(_method) == false) { @@ -2404,16 +2472,16 @@ protected M batchVerify(RequestMethod method, String tag, int version, String na if (method == RequestMethod.CRUD) { _method = GET; Map objAttrMap = new HashMap<>(); - objAttrMap.put(apijson.JSONObject.KEY_METHOD, GET); + objAttrMap.put(KEY_METHOD, GET); keyObjectAttributesMap.put(key, objAttrMap); } else { _method = method; Map objAttrMap = new HashMap<>(); - objAttrMap.put(apijson.JSONObject.KEY_METHOD, method); + objAttrMap.put(KEY_METHOD, method); keyObjectAttributesMap.put(key, objAttrMap); } } else { - _method = (RequestMethod) attrMap.get(apijson.JSONObject.KEY_METHOD); + _method = (RequestMethod) attrMap.get(KEY_METHOD); } } @@ -2474,7 +2542,7 @@ public static > E getEnum(final Class enumClass, final Stri } protected void setRequestAttribute(String key, boolean isArray, String attrKey, @NotNull Map request) { - Map attrMap = keyObjectAttributesMap.get(isArray ? key + apijson.JSONObject.KEY_ARRAY : key); + Map attrMap = keyObjectAttributesMap.get(isArray ? key + KEY_ARRAY : key); Object attrVal = attrMap == null ? null : attrMap.get(attrKey); Map obj = attrVal == null ? null : JSON.get(request, key); @@ -2487,7 +2555,7 @@ protected void setRequestAttribute(String key, boolean isArray, String attrKey, protected String buildTag(Map request, String key, RequestMethod method, String tag) { if (method == RequestMethod.CRUD) { Map attrMap = keyObjectAttributesMap.get(key); - Object _tag = attrMap == null ? null : attrMap.get(apijson.JSONRequest.KEY_TAG); + Object _tag = attrMap == null ? null : attrMap.get(KEY_TAG); return _tag != null ? _tag.toString() : StringUtil.isEmpty(tag) ? key : tag; } else { if (StringUtil.isEmpty(tag, true)) { @@ -2501,19 +2569,9 @@ protected String buildTag(Map request, String key, RequestMethod protected M objectVerify(RequestMethod method, String tag, int version, String name, @NotNull M request , int maxUpdateCount, SQLCreator creator, M object) throws Exception { // 获取指定的JSON结构 >>>>>>>>>>>>>> - M target = wrapRequest(method, tag, object, true, new JSONCreator() { - @Override - public M createJSONObject() { - return JSON.createJSONObject(); - } - - @Override - public L createJSONArray() { - return JSON.createJSONArray(); - } - }); + M target = wrapRequest(method, tag, object, true); // Map clone 浅拷贝没用,Structure.parse 会导致 structure 里面被清空,第二次从缓存里取到的就是 {} - return getVerifier().verifyRequest(method, name, target, request, maxUpdateCount, getGlobalDatabase(), getGlobalSchema(), creator); + return getVerifier().setParser(this).verifyRequest(method, name, target, request, maxUpdateCount, getGlobalDatabase(), getGlobalSchema()); } /*** @@ -2525,7 +2583,7 @@ public L createJSONArray() { public RequestMethod getRealMethod(RequestMethod method, String key, Object value) { if (method == CRUD && (value instanceof Map || value instanceof List)) { Map attrMap = keyObjectAttributesMap.get(key); - Object _method = attrMap == null ? null : attrMap.get(apijson.JSONObject.KEY_METHOD); + Object _method = attrMap == null ? null : attrMap.get(KEY_METHOD); if (_method instanceof RequestMethod) { return (RequestMethod) _method; } diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java index cc8d72f81..d9e9eb016 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java @@ -1,46 +1,25 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ package apijson.orm; -import java.util.*; -import java.util.Map.Entry; -import java.util.regex.Pattern; - import apijson.*; import apijson.orm.Join.On; import apijson.orm.exception.NotExistException; import apijson.orm.exception.UnsupportedDataTypeException; -import apijson.orm.model.Access; -import apijson.orm.model.AllColumn; -import apijson.orm.model.AllColumnComment; -import apijson.orm.model.AllTable; -import apijson.orm.model.AllTableComment; -import apijson.orm.model.Column; -import apijson.orm.model.Document; -import apijson.orm.model.ExtendedProperty; -import apijson.orm.model.Function; -import apijson.orm.model.PgAttribute; -import apijson.orm.model.PgClass; -import apijson.orm.model.Request; -import apijson.orm.model.SysColumn; -import apijson.orm.model.SysTable; -import apijson.orm.model.Table; -import apijson.orm.model.TestRecord; +import apijson.orm.model.*; + +import java.util.*; +import java.util.Map.Entry; +import java.util.regex.Pattern; import static apijson.JSON.getBoolean; import static apijson.JSON.getString; -import static apijson.JSONObject.*; -import static apijson.RequestMethod.DELETE; -import static apijson.RequestMethod.GET; -import static apijson.RequestMethod.POST; -import static apijson.RequestMethod.PUT; -import static apijson.SQL.AND; -import static apijson.SQL.NOT; -import static apijson.SQL.ON; -import static apijson.SQL.OR; +import static apijson.JSONMap.*; +import static apijson.RequestMethod.*; +import static apijson.SQL.*; /**config sql for JSON Request * @author Lemon @@ -190,6 +169,7 @@ public abstract class AbstractSQLConfig, L exte DATABASE_LIST.add(DATABASE_QUESTDB); DATABASE_LIST.add(DATABASE_IOTDB); DATABASE_LIST.add(DATABASE_SNOWFLAKE); + DATABASE_LIST.add(DATABASE_DATABEND); DATABASE_LIST.add(DATABASE_DATABRICKS); DATABASE_LIST.add(DATABASE_REDIS); DATABASE_LIST.add(DATABASE_MONGODB); @@ -199,6 +179,7 @@ public abstract class AbstractSQLConfig, L exte DATABASE_LIST.add(DATABASE_DUCKDB); DATABASE_LIST.add(DATABASE_SURREALDB); DATABASE_LIST.add(DATABASE_OPENGAUSS); + DATABASE_LIST.add(DATABASE_DORIS); RAW_MAP = new LinkedHashMap<>(); // 保证顺序,避免配置冲突等意外情况 @@ -298,6 +279,7 @@ public abstract class AbstractSQLConfig, L exte RAW_MAP.put("BY", ""); RAW_MAP.put("DESC", ""); RAW_MAP.put("ASC", ""); + RAW_MAP.put("PRECEDING", ""); // 往前 RAW_MAP.put("FOLLOWING", ""); // 往后 RAW_MAP.put("BETWEEN", ""); RAW_MAP.put("ROWS", ""); @@ -956,7 +938,7 @@ public String getUserIdKey() { private int page; //Table所在页码 private int position; //Table在[]中的位置 private int query; //apijson.JSONRequest.QUERY - private Boolean compat; //apijson.JSONObject.compat query total + private Boolean compat; //apijson.JSONMap.compat query total private int type; //ObjectParser.type private int cache; private boolean explain; @@ -1250,6 +1232,14 @@ public static boolean isSnowflake(String db) { return DATABASE_SNOWFLAKE.equals(db); } + @Override + public boolean isDatabend() { + return isDatabend(gainSQLDatabase()); + } + public static boolean isDatabend(String db) { + return DATABASE_DATABEND.equals(db); + } + @Override public boolean isDatabricks() { return isDatabricks(gainSQLDatabase()); @@ -1379,12 +1369,20 @@ public static boolean isOpenGauss(String db) { return DATABASE_OPENGAUSS.equals(db); } + @Override + public boolean isDoris() { + return isDoris(gainSQLDatabase()); + } + public static boolean isDoris(String db) { + return DATABASE_DORIS.equals(db); + } + @Override public String getQuote() { // MongoDB 同时支持 `tbl` 反引号 和 "col" 双引号 if(isElasticsearch() || isManticore() || isIoTDB() || isSurrealDB()) { return ""; } - return isMySQL() || isMariaDB() || isTiDB() || isClickHouse() || isTDengine() || isMilvus() ? "`" : "\""; + return isMySQL() || isMariaDB() || isTiDB() || isClickHouse() || isTDengine() || isMilvus() || isDoris() ? "`" : "\""; } public String quote(String s) { @@ -1564,7 +1562,7 @@ public String gainGroupString(boolean hasPrefix) { continue; } - SQLConfig ocfg = join.getOuterConfig(); + SQLConfig ocfg = join.getOnConfig(); SQLConfig cfg = (ocfg != null && ocfg.getGroup() != null) || join.isLeftOrRightJoin() ? ocfg : join.getJoinConfig(); if (cfg != null) { @@ -1579,6 +1577,23 @@ public String gainGroupString(boolean hasPrefix) { first = false; } } + + ////先处理左/右关联,内关联忽略 + //SQLConfig outerConfig = join.getOuterConfig(); + //SQLConfig outerConfig2 = (outerConfig != null && outerConfig.getGroup() != null) || join.isLeftOrRightJoin() ? outerConfig : null; + // + //if (outerConfig2 != null) { + // outerConfig2.setMain(false).setKeyPrefix(true); + // //if (StringUtil.isEmpty(cfg.getAlias(), true)) { + // // cfg.setAlias(cfg.getTable()); + // //} + // String c = ((AbstractSQLConfig) outerConfig2).gainGroupString(false); + // + // if (StringUtil.isNotEmpty(c, true)) { + // joinGroup += (first ? "" : ", ") + c; + // first = false; + // } + //} } } @@ -1640,7 +1655,7 @@ public String gainHavingString(boolean hasPrefix) throws Exception { continue; } - SQLConfig ocfg = join.getOuterConfig(); + SQLConfig ocfg = join.getOnConfig(); SQLConfig cfg = (ocfg != null && ocfg.getHaving() != null) || join.isLeftOrRightJoin() ? ocfg : join.getJoinConfig(); if (cfg != null) { @@ -1753,7 +1768,7 @@ public String gainSampleString(boolean hasPrefix) { continue; } - SQLConfig ocfg = join.getOuterConfig(); + SQLConfig ocfg = join.getOnConfig(); SQLConfig cfg = (ocfg != null && ocfg.getSample() != null) || join.isLeftOrRightJoin() ? ocfg : join.getJoinConfig(); if (cfg != null) { @@ -1823,7 +1838,7 @@ public String gainLatestString(boolean hasPrefix) { continue; } - SQLConfig ocfg = join.getOuterConfig(); + SQLConfig ocfg = join.getOnConfig(); SQLConfig cfg = (ocfg != null && ocfg.getLatest() != null) || join.isLeftOrRightJoin() ? ocfg : join.getJoinConfig(); if (cfg != null) { @@ -1888,7 +1903,7 @@ public String gainPartitionString(boolean hasPrefix) { continue; } - SQLConfig ocfg = join.getOuterConfig(); + SQLConfig ocfg = join.getOnConfig(); SQLConfig cfg = (ocfg != null && ocfg.getPartition() != null) || join.isLeftOrRightJoin() ? ocfg : join.getJoinConfig(); if (cfg != null) { @@ -1953,7 +1968,7 @@ public String gainFillString(boolean hasPrefix) { continue; } - SQLConfig ocfg = join.getOuterConfig(); + SQLConfig ocfg = join.getOnConfig(); SQLConfig cfg = (ocfg != null && ocfg.getFill() != null) || join.isLeftOrRightJoin() ? ocfg : join.getJoinConfig(); if (cfg != null) { @@ -2019,6 +2034,7 @@ public AbstractSQLConfig setOrder(String order) { public String gainOrderString(boolean hasPrefix) { //加上子表的 order String joinOrder = ""; + String joinOuterOrder = ""; if (joinList != null) { boolean first = true; for (Join join : joinList) { @@ -2026,7 +2042,7 @@ public String gainOrderString(boolean hasPrefix) { continue; } - SQLConfig ocfg = join.getOuterConfig(); + SQLConfig ocfg = join.getOnConfig(); SQLConfig cfg = (ocfg != null && ocfg.getOrder() != null) || join.isLeftOrRightJoin() ? ocfg : join.getJoinConfig(); if (cfg != null) { @@ -2179,7 +2195,7 @@ public String gainRawSQL(String key, Object value, boolean throwWhenMissing) thr + "对应的 " + key + ":value 中 value 值 " + value + " 未在后端 RAW_MAP 中配置 !"); } - putWarnIfNeed(apijson.JSONObject.KEY_RAW, "@raw:value 的 value 中 " + putWarnIfNeed(JSONMap.KEY_RAW, "@raw:value 的 value 中 " + key + " 不合法!对应的 " + key + ":value 中 value 值 " + value + " 未在后端 RAW_MAP 中配置 !"); } else if (rawSQL.isEmpty()) { @@ -2335,7 +2351,7 @@ public String gainColumnString(boolean inSQLJoin) throws Exception { continue; } - SQLConfig ocfg = join.getOuterConfig(); + SQLConfig ocfg = join.getOnConfig(); boolean isEmpty = ocfg == null || ocfg.getColumn() == null; boolean isLeftOrRightJoin = join.isLeftOrRightJoin(); @@ -2941,28 +2957,28 @@ public AbstractSQLConfig setCache(String cache) { public static int getCache(String cache) { int cache2; if (cache == null) { - cache2 = apijson.JSONObject.CACHE_ALL; + cache2 = JSONMap.CACHE_ALL; } else { // if (isSubquery) { - // throw new IllegalArgumentException("子查询内不支持传 " + apijson.JSONObject.KEY_CACHE + "!"); + // throw new IllegalArgumentException("子查询内不支持传 " + apijson.JSONMap.KEY_CACHE + "!"); // } switch (cache) { case "0": - case apijson.JSONObject.CACHE_ALL_STRING: - cache2 = apijson.JSONObject.CACHE_ALL; + case JSONMap.CACHE_ALL_STRING: + cache2 = JSONMap.CACHE_ALL; break; case "1": - case apijson.JSONObject.CACHE_ROM_STRING: - cache2 = apijson.JSONObject.CACHE_ROM; + case JSONMap.CACHE_ROM_STRING: + cache2 = JSONMap.CACHE_ROM; break; case "2": - case apijson.JSONObject.CACHE_RAM_STRING: - cache2 = apijson.JSONObject.CACHE_RAM; + case JSONMap.CACHE_RAM_STRING: + cache2 = JSONMap.CACHE_RAM; break; default: - throw new IllegalArgumentException(apijson.JSONObject.KEY_CACHE + throw new IllegalArgumentException(JSONMap.KEY_CACHE + ":value 中 value 的值不合法!必须在 [0,1,2] 或 [ALL, ROM, RAM] 内 !"); } } @@ -3719,8 +3735,9 @@ protected String concatJoinWhereString(String whereString) throws Exception { List pvl = new ArrayList<>(getPreparedValueList()); SQLConfig jc; + SQLConfig outerConfig; String js; - + boolean isWsEmpty = StringUtil.isEmpty(ws, true); boolean changed = false; // 各种 JOIN 没办法统一用 & | !连接,只能按优先级,和 @combine 一样? for (Join j : joinList) { @@ -3731,6 +3748,27 @@ protected String concatJoinWhereString(String whereString) throws Exception { case "@": // APP JOIN case "<": // LEFT JOIN case ">": // RIGHT JOIN + outerConfig = j.getOuterConfig(); + if (outerConfig == null){ + break; + } + boolean isMain1 = outerConfig.isMain(); + outerConfig.setMain(false).setPrepared(isPrepared()).setPreparedValueList(new ArrayList()); + String outerWhere = outerConfig.gainWhereString(false); + + int logic1 = Logic.getType(jt); + newWs += " ( " + + gainCondition( + Logic.isNot(logic1), + ws + + ( isWsEmpty ? "" : (Logic.isAnd(logic1) ? AND : OR) ) + + " ( " + outerWhere + " ) " + ) + + " ) "; + newPvl.addAll(pvl); + newPvl.addAll(outerConfig.getPreparedValueList()); + + changed = true; break; case "&": // INNER JOIN: A & B @@ -3751,7 +3789,7 @@ protected String concatJoinWhereString(String whereString) throws Exception { boolean isSideJoin = "^".equals(jt); boolean isAntiJoin = "(".equals(jt); boolean isForeignJoin = ")".equals(jt); - boolean isWsEmpty = StringUtil.isEmpty(ws, true); + //boolean isWsEmpty = StringUtil.isEmpty(ws, true); if (isWsEmpty) { if (isOuterJoin) { // ! OUTER JOIN: ! (A | B) @@ -3991,7 +4029,7 @@ else if (isTest()) { String sqlKey; if (expression == null) { - sqlKey = getSQLKey(key); + sqlKey = gainSQLKey(key); } else { // (name,tag) left(date,4) 等 @@ -4001,7 +4039,7 @@ else if (isTest()) { return lenFun.isEmpty() ? sqlKey : lenFun + "(" + sqlKey + ")"; } - public String getSQLKey(String key) { + public String gainSQLKey(String key) { String q = getQuote(); return (isKeyPrefix() ? q + gainSQLAlias() + q + "." : "") + q + key + q; } @@ -4556,7 +4594,7 @@ public String gainContainString(String key, String column, Object[] childs, int for (int i = 0; i < childs.length; i++) { Object c = childs[i]; if (c instanceof Collection) { - throw new IllegalArgumentException(key + ":value 中 value 类型不能为 [JSONArray, Collection] 中的任何一个 !"); + throw new IllegalArgumentException(key + ":value 中 value 类型不能为 [JSONList, Collection] 中的任何一个 !"); } Object path = ""; @@ -4570,7 +4608,7 @@ public String gainContainString(String key, String column, Object[] childs, int c = ((Map) c).get("value"); if (c instanceof Collection || c instanceof Map) { throw new IllegalArgumentException(key + ":{ path:path, value:value } 中 value 类型" + - "不能为 [JSONObject, JSONArray, Collection, Map] 中的任何一个 !"); + "不能为 [JSONMap, JSONList, Collection, Map] 中的任何一个 !"); } } @@ -4763,7 +4801,7 @@ public static String gainCondition(boolean not, String condition, boolean addOut * @return */ @NotNull - public L newJSONArray(Object obj) { + public static > L newJSONArray(Object obj) { L array = JSON.createJSONArray(); if (obj != null) { if (obj instanceof Collection) { @@ -4774,18 +4812,6 @@ public L newJSONArray(Object obj) { } return array; } - @NotNull - public static , L extends List> L newJSONArray(Object obj, @NotNull JSONCreator creator) { - L array = creator.createJSONArray(); - if (obj != null) { - if (obj instanceof Collection) { - array.addAll((Collection) obj); - } else { - array.add(obj); - } - } - return array; - } //WHERE >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> @@ -4981,16 +5007,16 @@ public static , L extends List> String //When config's database is oracle,Using subquery since Oracle12 below does not support OFFSET FETCH paging syntax. //针对oracle分组后条数的统计 if (StringUtil.isNotEmpty(config.getGroup(),true) && RequestMethod.isHeadMethod(config.getMethod(), true)){ - return explain + "SELECT count(*) FROM (SELECT " + (config.getCache() == apijson.JSONObject.CACHE_RAM + return explain + "SELECT count(*) FROM (SELECT " + (config.getCache() == JSONMap.CACHE_RAM ? "SQL_NO_CACHE " : "") + column + " FROM " + gainConditionString(tablePath, config) + ") " + config.gainLimitString(); } - String sql = "SELECT " + (config.getCache() == apijson.JSONObject.CACHE_RAM + String sql = "SELECT " + (config.getCache() == JSONMap.CACHE_RAM ? "SQL_NO_CACHE " : "") + column + " FROM " + gainConditionString(tablePath, config); return explain + config.gainOraclePageSQL(sql); } - cSql = "SELECT " + (config.getCache() == apijson.JSONObject.CACHE_RAM ? "SQL_NO_CACHE " : "") + cSql = "SELECT " + (config.getCache() == JSONMap.CACHE_RAM ? "SQL_NO_CACHE " : "") + column + " FROM " + gainConditionString(tablePath, config) + config.gainLimitString(); cSql = buildWithAsExprSql(config, cSql); if(config.isElasticsearch()) { // elasticSearch 不支持 explain @@ -5204,7 +5230,7 @@ public String gainJoinString() throws Exception { ); } - SQLConfig oc = j.getOuterConfig(); + SQLConfig oc = j.getOnConfig(); String ow = null; if (oc != null) { oc.setPrepared(isPrepared()); @@ -5922,7 +5948,7 @@ else if (w.startsWith("!")) { if (key.endsWith("<>") == false && value instanceof Map) { // 只允许常规 Object throw new IllegalArgumentException(table + ":{ " + key + ":value } 中 value 类型错误!除了 key<>:{} 外,不允许 " - + key + " 等其它任何 key 对应 value 的类型为 JSONObject {} !"); + + key + " 等其它任何 key 对应 value 的类型为 JSONMap {} !"); } // 兼容 PUT @combine @@ -6077,10 +6103,10 @@ else if (w.startsWith("!")) { else if (newHaving instanceof Map) { if (isHavingAnd) { throw new IllegalArgumentException(table + ":{ " + havingKey + ":value } 里的 value 类型不合法!" - + "@having&:value 中 value 只能是 String,@having:value 中 value 只能是 String 或 JSONObject !"); + + "@having&:value 中 value 只能是 String,@having:value 中 value 只能是 String 或 JSONMap !"); } - JSONObject havingObj = new JSONObject(newHaving); + M havingObj = JSON.createJSONObject((Map) newHaving); Set> havingSet = havingObj.entrySet(); for (Entry entry : havingSet) { String k = entry == null ? null : entry.getKey(); @@ -6110,7 +6136,7 @@ else if (StringUtil.isName(k) == false) { } else if (newHaving != null) { throw new IllegalArgumentException(table + ":{ " + havingKey + ":value } 里的 value 类型不合法!" - + "@having:value 中 value 只能是 String 或 JSONObject,@having&:value 中 value 只能是 String !"); + + "@having:value 中 value 只能是 String 或 JSONMap,@having&:value 中 value 只能是 String !"); } // @having, @haivng& >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> @@ -6132,7 +6158,7 @@ else if (keyMap instanceof String) { } } else if (keyMap != null) { - throw new UnsupportedDataTypeException("@key:value 中 value 错误,只能是 String, JSONObject 中的一种!"); + throw new UnsupportedDataTypeException("@key:value 中 value 错误,只能是 String, JSONMap 中的一种!"); } @@ -6307,13 +6333,22 @@ else if (joinConfig.getDatabase().equals(config.getDatabase()) == false) { joinConfig.setMain(false).setKeyPrefix(true); + if (join.getOn() != null) { + SQLConfig onConfig = newSQLConfig(method, table, alias, join.getOn(), null, false, callback); + onConfig.setMain(false) + .setKeyPrefix(true) + .setDatabase(joinConfig.getDatabase()) + .setSchema(joinConfig.getSchema()); //解决主表 JOIN 副表,引号不一致 + + join.setOnConfig(onConfig); + } + if (join.getOuter() != null) { SQLConfig outerConfig = newSQLConfig(method, table, alias, join.getOuter(), null, false, callback); outerConfig.setMain(false) .setKeyPrefix(true) .setDatabase(joinConfig.getDatabase()) .setSchema(joinConfig.getSchema()); //解决主表 JOIN 副表,引号不一致 - join.setOuterConfig(outerConfig); } } @@ -6324,9 +6359,12 @@ LEFT JOIN ( SELECT count(*) AS count FROM sys.Comment ) AS Comment ON Comment.m if (RequestMethod.isHeadMethod(method, true)) { List onList = join.getOnList(); List column = onList == null ? null : new ArrayList<>(onList.size()); - if (column != null) { + //解决 pg 如果只查询关联键,会报找不到column的错误 + ///* SELECT count(*) AS count FROM sys.Moment AS Moment + // LEFT JOIN ( SELECT * FROM sys.Comment ) AS Comment ON Comment.momentId = Moment.id LIMIT 1 OFFSET 0 */ + if (column != null && joinConfig.isMSQL()) { // 暂时这样兼容 PostgreSQL 等不支持 SELECT 中不包含对应 key 的隐式 ON 关联字段的数据库 for (On on : onList) { - column.add(on.getKey()); + column.add(on.getKey()); // TODO PostgreSQL 等需要找到具体的 targetTable 对应 targetKey 来加到 SELECT,比直接 SELECT * 性能更好 } } @@ -6373,8 +6411,8 @@ public static String gainRealKey(RequestMethod method, String originKey public static String gainRealKey(RequestMethod method, String originKey , boolean isTableKey, boolean saveLogic, boolean verifyName) throws Exception { Log.i(TAG, "getRealKey saveLogic = " + saveLogic + "; originKey = " + originKey); - if (originKey == null || apijson.JSONObject.isArrayKey(originKey)) { - Log.w(TAG, "getRealKey originKey == null || apijson.JSONObject.isArrayKey(originKey) >> return originKey;"); + if (originKey == null || JSONMap.isArrayKey(originKey)) { + Log.w(TAG, "getRealKey originKey == null || apijson.JSONMap.isArrayKey(originKey) >> return originKey;"); return originKey; } diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java index ce64cb3aa..4d6d28c02 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ @@ -127,8 +127,6 @@ public M getCacheItem(List list, int position, SQLConfig config) { - - /**移除缓存 * @param sql key * @param config @@ -175,6 +173,9 @@ public M execute(@NotNull SQLConfig config, boolean unknownType) throws return null; } + Parser parser2 = config.gainParser(); + parser = parser2 != null ? parser2 : getParser();; + boolean isExplain = config.isExplain(); boolean isHead = RequestMethod.isHeadMethod(config.getMethod(), true); @@ -237,7 +238,7 @@ public M execute(@NotNull SQLConfig config, boolean unknownType) throws } // updateCount>0时收集结果。例如更新操作成功时,返回count(affected rows)、id字段 - result = getParser().newSuccessResult(); // TODO 对 APIAuto 及其它现有的前端/客户端影响比较大,暂时还是返回 code 和 msg,5.0 再移除 JSON.createJSONObject(); + result = parser.newSuccessResult(); // TODO 对 APIAuto 及其它现有的前端/客户端影响比较大,暂时还是返回 code 和 msg,5.0 再移除 JSON.createJSONObject(); //id,id{}至少一个会有,一定会返回,不用抛异常来阻止关联写操作时前面错误导致后面无条件执行! result.put(JSONResponse.KEY_COUNT, updateCount);//返回修改的记录数 @@ -293,13 +294,12 @@ public M execute(@NotNull SQLConfig config, boolean unknownType) throws } } - if (isExplain == false && isHead) { if (rs.next() == false) { - return getParser().newErrorResult(new SQLException("数据库错误, rs.next() 失败!")); + return parser.newErrorResult(new SQLException("数据库错误, rs.next() 失败!")); } - result = getParser().newSuccessResult(); + result = parser.newSuccessResult(); // 兼容nosql,比如 elasticSearch-sql if(config.isElasticsearch()) { result.put(JSONResponse.KEY_COUNT, rs.getObject(1)); @@ -1135,7 +1135,7 @@ else if (value instanceof Clob) { //SQL Server TEXT 类型 居然走这个 } if (castToJson) { try { - value = JSON.parseJSON(value); + value = JSON.parse(value); } catch (Exception e) { Log.e(TAG, "getValue try { value = parseJSON((String) value); } catch (Exception e) { \n" + e.getMessage()); } @@ -1213,14 +1213,15 @@ public PreparedStatement getStatement(@NotNull SQLConfig config, String sql = config.gainSQL(config.isPrepared()); } + Connection conn = getConnection(config); PreparedStatement statement; //创建Statement对象 if (config.getMethod() == RequestMethod.POST && config.getId() == null) { //自增id if (config.isOracle()) { // 解决 oracle 使用自增主键 插入获取不到id问题 String[] generatedColumns = {config.getIdKey()}; - statement = getConnection(config).prepareStatement(sql, generatedColumns); + statement = conn.prepareStatement(sql, generatedColumns); } else { - statement = getConnection(config).prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); + statement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); } } else if (RequestMethod.isGetMethod(config.getMethod(), true)) { @@ -1234,13 +1235,13 @@ else if (RequestMethod.isGetMethod(config.getMethod(), true)) { if (config.isMySQL() || config.isTiDB() || config.isMariaDB() || config.isOracle() || config.isSQLServer() || config.isDb2() || config.isPostgreSQL() || config.isCockroachDB() || config.isOpenGauss() || config.isTimescaleDB() || config.isQuestDB() ) { - statement = getConnection(config).prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); + statement = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); } else { - statement = getConnection(config).prepareStatement(sql); + statement = conn.prepareStatement(sql); } } else { - statement = getConnection(config).prepareStatement(sql); + statement = conn.prepareStatement(sql); } List valueList = config.isPrepared() ? config.getPreparedValueList() : null; @@ -1265,7 +1266,7 @@ else if (RequestMethod.isGetMethod(config.getMethod(), true)) { } public PreparedStatement setArgument(@NotNull SQLConfig config, @NotNull PreparedStatement statement, int index, Object value) throws SQLException { - //JSON.isBooleanOrNumberOrString(v) 解决 PostgreSQL: Can't infer the SQL type to use for an instance of com.alibaba.fastjson.JSONArray + //JSON.isBooleanOrNumberOrString(v) 解决 PostgreSQL: Can't infer the SQL type to use for an instance of com.alibaba.fastjson.JSONList if (apijson.JSON.isBoolOrNumOrStr(value)) { statement.setObject(index + 1, value); //PostgreSQL JDBC 不支持隐式类型转换 tinyint = varchar 报错 } @@ -1276,17 +1277,32 @@ public PreparedStatement setArgument(@NotNull SQLConfig config, @NotNul } protected Map connectionMap = new HashMap<>(); + public Map getConnectionMap() { + if (connectionMap == null) { + connectionMap = new HashMap<>(); + } + return connectionMap; + } + protected Connection connection; + @NotNull + public Connection getConnection(String key) throws Exception { + return getConnectionMap().get(key); + } + public Connection putConnection(String key, Connection connection) throws Exception { + return getConnectionMap().put(key, connection); + } + @NotNull @Override public Connection getConnection(@NotNull SQLConfig config) throws Exception { String connectionKey = getConnectionKey(config); - connection = connectionMap.get(connectionKey); + connection = getConnection(connectionKey); if (connection == null || connection.isClosed()) { Log.i(TAG, "select connection " + (connection == null ? " = null" : ("isClosed = " + connection.isClosed()))) ; // PostgreSQL 不允许 cross-database connection = DriverManager.getConnection(config.gainDBUri(), config.gainDBAccount(), config.gainDBPassword()); - connectionMap.put(connectionKey, connection); + putConnection(connectionKey, connection); } // TDengine 驱动内部事务处理方法都是空实现,手动 commit 无效 @@ -1326,7 +1342,7 @@ public void begin(int transactionIsolation) throws SQLException { // } // 将所有连接设置隔离级别,且禁止自动提交,需要以下代码来 commit/rollback - Collection connections = connectionMap.values(); + Collection connections = connectionMap == null ? null : connectionMap.values(); if (connections != null) { for (Connection connection : connections) { try { @@ -1356,7 +1372,7 @@ public void rollback() throws SQLException { // } // 将所有连接进行回滚 - Collection connections = connectionMap.values(); + Collection connections = connectionMap == null ? null : connectionMap.values(); if (connections != null) { for (Connection connection : connections) { try { @@ -1388,7 +1404,7 @@ public void rollback(Savepoint savepoint) throws SQLException { // } // 将所有连接进行回滚 - Collection connections = connectionMap.values(); + Collection connections = connectionMap == null ? null : connectionMap.values(); if (connections != null) { for (Connection connection : connections) { try { @@ -1415,7 +1431,7 @@ public void commit() throws SQLException { // } // 将所有连接进行提交 - Collection connections = connectionMap.values(); + Collection connections = connectionMap == null ? null : connectionMap.values(); if (connections != null) { for (Connection connection : connections) { try { @@ -1444,7 +1460,7 @@ public void close() { cachedSQLCount = 0; executedSQLCount = 0; - if (connectionMap == null) { + if (connectionMap == null || connectionMap.isEmpty()) { return; } diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractVerifier.java b/APIJSONORM/src/main/java/apijson/orm/AbstractVerifier.java index 9bf8e64a2..b10828eea 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractVerifier.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractVerifier.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ @@ -224,11 +224,11 @@ public String getVisitorIdKey(SQLConfig config) { @Override public String getIdKey(String database, String schema, String datasource, String table) { - return apijson.JSONObject.KEY_ID; + return JSONMap.KEY_ID; } @Override public String getUserIdKey(String database, String schema, String datasource, String table) { - return apijson.JSONObject.KEY_USER_ID; + return JSONMap.KEY_USER_ID; } @SuppressWarnings("unchecked") @@ -313,7 +313,7 @@ public void verifyRole(SQLConfig config, String table, RequestMethod me * @param role * @return * @throws Exception - * @see {@link apijson.JSONObject#KEY_ROLE} + * @see {@link JSONMap#KEY_ROLE} */ public void verifyAllowRole(SQLConfig config, String table, RequestMethod method, String role) throws Exception { Log.d(TAG, "verifyAllowRole table = " + table + "; method = " + method + "; role = " + role); @@ -344,7 +344,7 @@ public void verifyAllowRole(SQLConfig config, String table, RequestMeth * @param role * @return * @throws Exception - * @see {@link apijson.JSONObject#KEY_ROLE} + * @see {@link JSONMap#KEY_ROLE} */ public void verifyUseRole(SQLConfig config, String table, RequestMethod method, String role) throws Exception { Log.d(TAG, "verifyUseRole table = " + table + "; method = " + method + "; role = " + role); @@ -533,7 +533,7 @@ public void verifyRepeat(String table, String key, Object value, long exceptId) M tblObj = JSON.createJSONObject(); tblObj.put(key, value); if (exceptId > 0) {//允许修改自己的属性为该属性原来的值 - tblObj.put(apijson.JSONObject.KEY_ID + "!", exceptId); // FIXME 这里 id 写死了,不支持自定义 + tblObj.put(JSONMap.KEY_ID + "!", exceptId); // FIXME 这里 id 写死了,不支持自定义 } M req = JSON.createJSONObject(); @@ -559,14 +559,13 @@ public void verifyRepeat(String table, String key, Object value, long exceptId) * @param maxUpdateCount * @param database * @param schema - * @param creator * @return * @throws Exception */ @Override public M verifyRequest(@NotNull final RequestMethod method, final String name, final M target, final M request, final int maxUpdateCount - , final String database, final String schema, final SQLCreator creator) throws Exception { - return verifyRequest(method, name, target, request, maxUpdateCount, database, schema, this, creator); + , final String database, final String schema) throws Exception { + return verifyRequest(method, name, target, request, maxUpdateCount, database, schema, this, getParser()); } /**从request提取target指定的内容 @@ -574,14 +573,14 @@ public M verifyRequest(@NotNull final RequestMethod method, final String name, f * @param name * @param target * @param request - * @param creator + * @param parser * @return * @throws Exception */ public static , L extends List> M verifyRequest( @NotNull final RequestMethod method, final String name, final M target, final M request - , final SQLCreator creator) throws Exception { - return verifyRequest(method, name, target, request, AbstractParser.MAX_UPDATE_COUNT, creator); + , @NotNull Parser parser) throws Exception { + return verifyRequest(method, name, target, request, AbstractParser.MAX_UPDATE_COUNT, parser); } /**从request提取target指定的内容 * @param method @@ -589,15 +588,15 @@ public static , L extends List> M verif * @param target * @param request * @param maxUpdateCount - * @param creator + * @param parser * @return * @throws Exception */ public static , L extends List> M verifyRequest( @NotNull final RequestMethod method, final String name, final M target, final M request - , final int maxUpdateCount, final SQLCreator creator) throws Exception { + , final int maxUpdateCount, @NotNull Parser parser) throws Exception { - return verifyRequest(method, name, target, request, maxUpdateCount, null, null, null, creator); + return verifyRequest(method, name, target, request, maxUpdateCount, null, null, null, parser); } /**从request提取target指定的内容 @@ -609,17 +608,16 @@ public static , L extends List> M verif * @param database * @param schema * @param idCallback - * @param creator + * @param parser * @return * @param * @throws Exception */ public static , L extends List> M verifyRequest( - @NotNull final RequestMethod method, final String name, final M target, final M request - , final int maxUpdateCount, final String database, final String schema - , final IdCallback idCallback, final SQLCreator creator) throws Exception { + @NotNull RequestMethod method, String name, M target, M request, int maxUpdateCount, String database + , String schema, IdCallback idCallback, @NotNull Parser parser) throws Exception { - return verifyRequest(method, name, target, request, maxUpdateCount, database, schema, null, idCallback, creator); + return verifyRequest(method, name, target, request, maxUpdateCount, database, schema, null, idCallback, parser); } /**从request提取target指定的内容 * @param method @@ -631,7 +629,7 @@ public static , L extends List> M verif * @param schema * @param datasource * @param idCallback - * @param creator + * @param parser * @return * @param * @throws Exception @@ -639,7 +637,7 @@ public static , L extends List> M verif public static , L extends List> M verifyRequest( @NotNull final RequestMethod method, final String name, final M target, final M request , final int maxUpdateCount, final String database, final String schema, final String datasource - , final IdCallback idCallback, final SQLCreator creator) throws Exception { + , final IdCallback idCallback, @NotNull Parser parser) throws Exception { if (ENABLE_VERIFY_CONTENT == false) { throw new UnsupportedOperationException("AbstractVerifier.ENABLE_VERIFY_CONTENT == false" + " 时不支持校验请求传参内容!如需支持则设置 AbstractVerifier.ENABLE_VERIFY_CONTENT = true !"); @@ -655,14 +653,14 @@ public static , L extends List> M verif } //已在 Verifier 中处理 - // if (get(getString(request, apijson.JSONObject.KEY_ROLE)) == ADMIN) { + // if (get(getString(request, apijson.JSONMap.KEY_ROLE)) == ADMIN) { // throw new IllegalArgumentException("角色设置错误!不允许在写操作Request中传 " + name + - // ":{ " + apijson.JSONObject.KEY_ROLE + ":admin } !"); + // ":{ " + apijson.JSONMap.KEY_ROLE + ":admin } !"); // } //解析 - return parse(method, name, target, request, database, schema, idCallback, creator, new OnParseCallback() { + return parse(method, name, target, request, database, schema, idCallback, parser, new OnParseCallback() { @Override public M onParseJSONObject(String key, M tobj, M robj) throws Exception { @@ -672,10 +670,10 @@ public M onParseJSONObject(String key, M tobj, M robj) throws Exception { if (tobj != null) {//不允许不传Target中指定的Table throw new IllegalArgumentException(method + "请求,请在 " + name + " 内传 " + key + ":{} !"); } - } else if (apijson.JSONObject.isTableKey(key)) { - String db = getString(request, apijson.JSONObject.KEY_DATABASE); - String sh = getString(request, apijson.JSONObject.KEY_SCHEMA); - String ds = getString(request, apijson.JSONObject.KEY_DATASOURCE); + } else if (JSONMap.isTableKey(key)) { + String db = getString(request, JSONMap.KEY_DATABASE); + String sh = getString(request, JSONMap.KEY_SCHEMA); + String ds = getString(request, JSONMap.KEY_DATASOURCE); if (StringUtil.isEmpty(db, false)) { db = database; } @@ -687,7 +685,7 @@ public M onParseJSONObject(String key, M tobj, M robj) throws Exception { } String idKey = idCallback == null ? null : idCallback.getIdKey(db, sh, ds, key); - String finalIdKey = StringUtil.isEmpty(idKey, false) ? apijson.JSONObject.KEY_ID : idKey; + String finalIdKey = StringUtil.isEmpty(idKey, false) ? JSONMap.KEY_ID : idKey; if (method == RequestMethod.POST) { if (robj.containsKey(finalIdKey)) { @@ -699,18 +697,18 @@ public M onParseJSONObject(String key, M tobj, M robj) throws Exception { verifyId(method.name(), name, key, robj, finalIdKey, maxUpdateCount, atLeastOne != null ? atLeastOne : IS_UPDATE_MUST_HAVE_ID_CONDITION); String userIdKey = idCallback == null ? null : idCallback.getUserIdKey(db, sh, ds, key); - String finalUserIdKey = StringUtil.isEmpty(userIdKey, false) ? apijson.JSONObject.KEY_USER_ID : userIdKey; + String finalUserIdKey = StringUtil.isEmpty(userIdKey, false) ? JSONMap.KEY_USER_ID : userIdKey; verifyId(method.name(), name, key, robj, finalUserIdKey, maxUpdateCount, false); } } } - return verifyRequest(method, key, tobj, robj, maxUpdateCount, database, schema, idCallback, creator); + return verifyRequest(method, key, tobj, robj, maxUpdateCount, database, schema, idCallback, parser); } @Override protected L onParseJSONArray(String key, L tarray, L rarray) throws Exception { - if ((method == RequestMethod.POST || method == RequestMethod.PUT) && apijson.JSONObject.isArrayKey(key)) { + if ((method == RequestMethod.POST || method == RequestMethod.PUT) && JSONMap.isArrayKey(key)) { if (rarray == null || rarray.isEmpty()) { throw new IllegalArgumentException(method + "请求,请在 " + name + " 内传 " + key + ":[{ ... }] " + ",批量新增 Table[]:value 中 value 必须是包含表对象的非空数组!其中每个子项 { ... } 都是" @@ -805,15 +803,15 @@ else if (o instanceof String) { * @param response * @param database * @param schema - * @param creator + * @param parser * @param callback * @return * @throws Exception */ @Override public M verifyResponse(@NotNull final RequestMethod method, final String name, final M target, final M response - , final String database, final String schema, SQLCreator creator, OnParseCallback callback) throws Exception { - return verifyResponse(method, name, target, response, database, schema, this, creator, callback); + , final String database, final String schema, @NotNull Parser parser, OnParseCallback callback) throws Exception { + return verifyResponse(method, name, target, response, database, schema, this, parser, callback); } /**校验并将response转换为指定的内容和结构 @@ -821,14 +819,14 @@ public M verifyResponse(@NotNull final RequestMethod method, final String name, * @param name * @param target * @param response - * @param creator + * @param parser * @param callback * @return * @throws Exception */ public static , L extends List> M verifyResponse(@NotNull final RequestMethod method, final String name - , final M target, final M response, SQLCreator creator, OnParseCallback callback) throws Exception { - return verifyResponse(method, name, target, response, null, null, null, creator, callback); + , final M target, final M response, @NotNull Parser parser, OnParseCallback callback) throws Exception { + return verifyResponse(method, name, target, response, null, null, null, parser, callback); } /**校验并将response转换为指定的内容和结构 * @param method @@ -838,7 +836,7 @@ public static , L extends List> M verif * @param database * @param schema * @param idKeyCallback - * @param creator + * @param parser * @param callback * @return * @param @@ -846,7 +844,7 @@ public static , L extends List> M verif */ public static , L extends List> M verifyResponse(@NotNull final RequestMethod method , final String name, final M target, final M response, final String database, final String schema - , final IdCallback idKeyCallback, SQLCreator creator, OnParseCallback callback) throws Exception { + , final IdCallback idKeyCallback, @NotNull Parser parser, OnParseCallback callback) throws Exception { Log.i(TAG, "verifyResponse method = " + method + "; name = " + name + "; target = \n" + JSON.toJSONString(target) @@ -859,10 +857,10 @@ public static , L extends List> M veri //解析 return parse(method, name, target, response, database, schema - , idKeyCallback, creator, callback != null ? callback : new OnParseCallback() { + , idKeyCallback, parser, callback != null ? callback : new OnParseCallback() { @Override protected M onParseJSONObject(String key, M tobj, M robj) throws Exception { - return verifyResponse(method, key, tobj, robj, database, schema, idKeyCallback, creator, callback); + return verifyResponse(method, key, tobj, robj, database, schema, idKeyCallback, parser, callback); } }); } @@ -873,14 +871,14 @@ protected M onParseJSONObject(String key, M tobj, M robj) throws Exception { * @param name * @param target * @param real - * @param creator + * @param parser * @param callback * @return * @throws Exception */ public static , L extends List> M parse(@NotNull final RequestMethod method - , String name, M target, M real, SQLCreator creator, @NotNull OnParseCallback callback) throws Exception { - return parse(method, name, target, real, null, null, null, creator, callback); + , String name, M target, M real, @NotNull Parser parser, @NotNull OnParseCallback callback) throws Exception { + return parse(method, name, target, real, null, null, null, parser, callback); } /**对request和response不同的解析用callback返回 * @param method @@ -890,15 +888,15 @@ public static , L extends List> M parse * @param database * @param schema * @param idCallback - * @param creator + * @param parser * @param callback * @return * @throws Exception */ public static , L extends List> M parse( @NotNull final RequestMethod method, String name, M target, M real, final String database, final String schema - , final IdCallback idCallback, SQLCreator creator, @NotNull OnParseCallback callback) throws Exception { - return parse(method, name, target, real, database, schema, null, idCallback, creator, callback); + , final IdCallback idCallback, @NotNull Parser parser, @NotNull OnParseCallback callback) throws Exception { + return parse(method, name, target, real, database, schema, null, idCallback, parser, callback); } /**对request和response不同的解析用callback返回 * @param method @@ -909,14 +907,14 @@ public static , L extends List> M parse * @param schema * @param datasource * @param idCallback - * @param creator + * @param parser * @param callback * @return * @throws Exception */ public static , L extends List> M parse(@NotNull final RequestMethod method , String name, M target, M real, final String database, final String schema, final String datasource - , final IdCallback idCallback, SQLCreator creator, @NotNull OnParseCallback callback) throws Exception { + , final IdCallback idCallback, @NotNull Parser parser, @NotNull OnParseCallback callback) throws Exception { if (target == null) { return null; } @@ -937,7 +935,7 @@ public static , L extends List> M parse Object _if = target.get(IF.name()); boolean ifIsStr = _if instanceof String && StringUtil.isNotEmpty(_if, true); M ifObj = ifIsStr == false && _if instanceof Map ? (M) _if : null; -// : (_if instanceof String ? new apijson.JSONObject((String) _if, "" /* "throw new Error('')" */ ) : null); +// : (_if instanceof String ? new apijson.JSONMap((String) _if, "" /* "throw new Error('')" */ ) : null); if (ifObj == null && _if != null && ifIsStr == false) { // if (_if instanceof List) { // } @@ -1006,7 +1004,7 @@ public static , L extends List> M parse } tvalue = callback.onParseJSONArray(key, (L) tvalue, (L) rvalue); - if ((method == RequestMethod.POST || method == RequestMethod.PUT) && apijson.JSONObject.isArrayKey(key)) { + if ((method == RequestMethod.POST || method == RequestMethod.PUT) && JSONMap.isArrayKey(key)) { objKeySet.add(key); } } else { // 其它Object @@ -1114,7 +1112,7 @@ public static , L extends List> M parse + name + " 里面不允许传 " + rk + ":{} !"); } if ((method == RequestMethod.POST || method == RequestMethod.PUT) - && rv instanceof List && apijson.JSONObject.isArrayKey(rk)) { + && rv instanceof List && JSONMap.isArrayKey(rk)) { throw new UnsupportedOperationException(method + " 请求," + name + " 里面不允许 " + rk + ":[] 等未定义的 Table[]:[{}] 批量操作键值对!"); } @@ -1131,17 +1129,17 @@ public static , L extends List> M parse // 校验与修改Request<<<<<<<<<<<<<<<<< // 在tableKeySet校验后操作,避免 导致put/add进去的Table 被当成原Request的内容 - real = operate(TYPE, type, real, creator); - real = operate(VERIFY, verify, real, creator); - real = operate(INSERT, insert, real, creator); - real = operate(UPDATE, update, real, creator); - real = operate(REPLACE, replace, real, creator); + real = operate(TYPE, type, real, parser); + real = operate(VERIFY, verify, real, parser); + real = operate(INSERT, insert, real, parser); + real = operate(UPDATE, update, real, parser); + real = operate(REPLACE, replace, real, parser); // 校验与修改Request>>>>>>>>>>>>>>>>> - String db = getString(real, apijson.JSONObject.KEY_DATABASE); - String sh = getString(real, apijson.JSONObject.KEY_SCHEMA); - String ds = getString(real, apijson.JSONObject.KEY_DATASOURCE); + String db = getString(real, JSONMap.KEY_DATABASE); + String sh = getString(real, JSONMap.KEY_SCHEMA); + String ds = getString(real, JSONMap.KEY_DATASOURCE); if (StringUtil.isEmpty(db, false)) { db = database; } @@ -1152,7 +1150,7 @@ public static , L extends List> M parse ds = datasource; } String idKey = idCallback == null ? null : idCallback.getIdKey(db, sh, ds, name); - String finalIdKey = StringUtil.isEmpty(idKey, false) ? apijson.JSONObject.KEY_ID : idKey; + String finalIdKey = StringUtil.isEmpty(idKey, false) ? JSONMap.KEY_ID : idKey; // TODO 放在operate前?考虑性能、operate修改后再验证的值是否和原来一样 // 校验存在<<<<<<<<<<<<<<<<<<< @@ -1163,7 +1161,7 @@ public static , L extends List> M parse for (String e : exists) { map.put(e,real.get(e)); } - verifyExist(name, map, exceptId, creator); + verifyExist(name, map, exceptId, parser); } // 校验存在>>>>>>>>>>>>>>>>>>> @@ -1176,7 +1174,7 @@ public static , L extends List> M parse for (String u : uniques) { map.put(u, real.get(u)); } - verifyRepeat(name, map, exceptId, finalIdKey, creator); + verifyRepeat(name, map, exceptId, finalIdKey, parser); } // 校验重复>>>>>>>>>>>>>>>>>>> @@ -1184,7 +1182,7 @@ public static , L extends List> M parse String[] partialFails = StringUtil.split(allowPartialUpdateFail); if (partialFails != null && partialFails.length > 0) { for (String key : partialFails) { - if (apijson.JSONObject.isArrayKey(key) == false) { + if (JSONMap.isArrayKey(key) == false) { throw new IllegalArgumentException("后端 Request 表中 " + ALLOW_PARTIAL_UPDATE_FAIL.name() + ":value 中 " + key + " 不合法!必须以 [] 结尾!"); } @@ -1207,15 +1205,15 @@ public static , L extends List> M parse // 校验并配置允许部分批量增删改失败>>>>>>>>>>>>>>>>>>> - String[] nks = ifObj == null ? null : StringUtil.split(getString(real, apijson.JSONObject.KEY_NULL)); + String[] nks = ifObj == null ? null : StringUtil.split(getString(real, JSONMap.KEY_NULL)); Collection nkl = nks == null || nks.length <= 0 ? new HashSet<>() : Arrays.asList(nks); Set> ifSet = ifObj == null ? null : ifObj.entrySet(); if (ifIsStr || (ifSet != null && ifSet.isEmpty() == false)) { // 没必要限制,都是后端配置的,安全可控,而且可能确实有特殊需求,需要 id, @column 等 -// List condKeys = new ArrayList<>(Arrays.asList(apijson.JSONObject.KEY_ID, apijson.JSONObject.KEY_ID_IN -// , apijson.JSONObject.KEY_USER_ID, apijson.JSONObject.KEY_USER_ID_IN)); -// condKeys.addAll(apijson.JSONObject.TABLE_KEY_LIST); +// List condKeys = new ArrayList<>(Arrays.asList(apijson.JSONMap.KEY_ID, apijson.JSONMap.KEY_ID_IN +// , apijson.JSONMap.KEY_USER_ID, apijson.JSONMap.KEY_USER_ID_IN)); +// condKeys.addAll(apijson.JSONMap.TABLE_KEY_LIST); String preCode = "var curObj = " + JSON.toJSONString(real) + ";"; @@ -1284,7 +1282,7 @@ public static , L extends List> M parse } if (nkl.contains(k) || real.get(k) != null) { - real = parse(method, name, (M) v, real, database, schema, datasource, idCallback, creator, callback); + real = parse(method, name, (M) v, real, database, schema, datasource, idCallback, parser, callback); } } } @@ -1309,12 +1307,12 @@ public static ScriptEngine getScriptEngine(String lang) { * @param opt * @param targetChild * @param real - * @param creator + * @param parser * @return * @throws Exception */ private static , L extends List> M operate(Operation opt, M targetChild - , M real, SQLCreator creator) throws Exception { + , M real, @NotNull Parser parser) throws Exception { if (targetChild == null) { return real; } @@ -1335,7 +1333,7 @@ private static , L extends List> M oper verifyType(tk, tv, real); } else if (opt == VERIFY) { - verifyValue(tk, tv, real, creator); + verifyValue(tk, tv, real, parser); } else if (opt == UPDATE) { real.put(tk, tv); @@ -1409,7 +1407,7 @@ public static void verifyType(@NotNull String tk, @NotNull String tv, Object rv, //这里不抽取 enum,因为 enum 不能满足扩展需求,子类需要可以自定义,而且 URL[] 这种也不符合命名要求,得用 constructor + getter + setter switch (tv) { case "BOOLEAN": //Boolean.parseBoolean(getString(real, tk)); 只会判断null和true - if (rv instanceof Boolean == false) { //apijson.JSONObject.getBoolean 可转换Number类型 + if (rv instanceof Boolean == false) { //apijson.JSONMap.getBoolean 可转换Number类型 throw new UnsupportedDataTypeException(tk + ":value 的value不合法!类型必须是 BOOLEAN" + (isInArray ? "[] !" : " !")); } break; @@ -1429,7 +1427,7 @@ public static void verifyType(@NotNull String tk, @NotNull String tv, Object rv, } break; case "STRING": - if (rv instanceof String == false) { //apijson.JSONObject.getString 可转换任何类型 + if (rv instanceof String == false) { //apijson.JSONMap.getString 可转换任何类型 throw new UnsupportedDataTypeException(tk + ":value 的value不合法!" + "类型必须是 STRING" + (isInArray ? "[] !" : " !")); } @@ -1467,13 +1465,13 @@ public static void verifyType(@NotNull String tk, @NotNull String tv, Object rv, } break; case "OBJECT": - if (rv instanceof Map == false) { //apijson.JSONObject.getJSONObject 可转换String类型 + if (rv instanceof Map == false) { //apijson.JSONMap.getJSONObject 可转换String类型 throw new UnsupportedDataTypeException(tk + ":value 的value不合法!" + "类型必须是 OBJECT" + (isInArray ? "[] !" : " !") + " OBJECT 结构为 {} !"); } break; case "ARRAY": - if (rv instanceof Collection == false) { //apijson.JSONObject.getJSONArray 可转换String类型 + if (rv instanceof Collection == false) { //apijson.JSONMap.getJSONArray 可转换String类型 throw new UnsupportedDataTypeException(tk + ":value 的value不合法!" + "类型必须是 ARRAY" + (isInArray ? "[] !" : " !") + " ARRAY 结构为 [] !"); } @@ -1501,11 +1499,11 @@ public static void verifyType(@NotNull String tk, @NotNull String tv, Object rv, * @param tk * @param tv * @param real - * @param creator + * @param parser * @throws Exception */ private static , L extends List> void verifyValue(@NotNull String tk - , @NotNull Object tv, @NotNull M real, SQLCreator creator) throws Exception { + , @NotNull Object tv, @NotNull M real, @NotNull Parser parser) throws Exception { if (tv == null) { throw new IllegalArgumentException("operate operate == VERIFY " + tk + ":" + tv + " , >> tv == null!!!"); } @@ -1514,7 +1512,7 @@ private static , L extends List> void v Object rv; Logic logic; if (tk.endsWith("$")) { // 模糊搜索 - verifyCondition("$", real, tk, tv, creator); + verifyCondition("$", real, tk, tv, parser); } else if (tk.endsWith("~")) { // 正则匹配 logic = new Logic(tk.substring(0, tk.length() - 1)); @@ -1524,17 +1522,7 @@ else if (tk.endsWith("~")) { // 正则匹配 return; } - L array = AbstractSQLConfig.newJSONArray(tv, new JSONCreator() { - @Override - public M createJSONObject() { - return JSON.createJSONObject(); - } - - @Override - public L createJSONArray() { - return JSON.createJSONArray(); - } - }); + L array = AbstractSQLConfig.newJSONArray(tv); boolean m; boolean isOr = false; @@ -1569,7 +1557,7 @@ public L createJSONArray() { } else if (tk.endsWith("{}")) { //rv符合tv条件或在tv内 if (tv instanceof String) {//TODO >= 0, < 10 - verifyCondition("{}", real, tk, tv, creator); + verifyCondition("{}", real, tk, tv, parser); } else if (tv instanceof List) { logic = new Logic(tk.substring(0, tk.length() - 2)); @@ -1619,17 +1607,7 @@ else if (tk.endsWith("<>")) { //rv包含tv内的值 throw new UnsupportedDataTypeException("服务器Request表verify配置错误!"); } - L array = AbstractSQLConfig.newJSONArray(tv, new JSONCreator, L>() { - @Override - public M createJSONObject() { - return JSON.createJSONObject(); - } - - @Override - public L createJSONArray() { - return JSON.createJSONArray(); - } - }); + L array = AbstractSQLConfig.newJSONArray(tv); boolean isOr = false; for (Object o : array) { @@ -1701,12 +1679,12 @@ private static boolean verifyRV(String rule,String content) throws UnsupportedDa * @param real * @param tk * @param tv - * @param creator + * @param parser * @throws Exception */ private static , L extends List> void verifyCondition( @NotNull String funChar, @NotNull M real, @NotNull String tk, @NotNull Object tv - , @NotNull SQLCreator creator) throws Exception { + , @NotNull Parser parser) throws Exception { //不能用Parser, 0 这种不符合 StringUtil.isName ! Logic logic = new Logic(tk.substring(0, tk.length() - funChar.length())); String rk = logic.getKey(); @@ -1719,7 +1697,7 @@ private static , L extends List> void v throw new IllegalArgumentException(rk + ":value 中value不合法!value 中不允许有单引号 ' !"); } - SQLConfig config = creator.createSQLConfig().setMethod(RequestMethod.GET).setCount(1).setPage(0); + SQLConfig config = parser.createSQLConfig().setMethod(RequestMethod.GET).setCount(1).setPage(0); config.setTest(true); // config.setTable(Test.class.getSimpleName()); // config.setColumn(rv + logic.getChar() + funChar) @@ -1727,15 +1705,16 @@ private static , L extends List> void v config.putWhere(rv + logic.getChar() + funChar, tv, false); config.setCount(1); - SQLExecutor executor = creator.createSQLExecutor(); - M result = null; + SQLExecutor executor = parser.createSQLExecutor(); // close 后复用导致不好修复的 NPE getSQLExecutor(); + executor.setParser(parser); + M result; try { result = executor.execute(config, false); } finally { executor.close(); } - if (result != null && JSONResponse.isExist(getIntValue(result, JSONResponse.KEY_COUNT)) == false) { + if (result != null && JSONResponse.isExist(result) == false) { throw new IllegalArgumentException(rk + ":value 中value不合法!必须匹配 '" + tk + "': '" + tv + "' !"); } } @@ -1748,7 +1727,7 @@ private static , L extends List> void v * @throws Exception */ public static , L extends List>void verifyExist(String table, String key - , Object value, long exceptId, @NotNull SQLCreator creator) throws Exception { + , Object value, long exceptId, @NotNull Parser parser) throws Exception { if (key == null || value == null) { Log.e(TAG, "verifyExist key == null || value == null >> return;"); return; @@ -1758,7 +1737,7 @@ public static , L extends List>void ver } Map map = new HashMap<>(); map.put(key,value); - verifyExist(table,map,exceptId,creator); + verifyExist(table,map,exceptId,parser); } /**验证是否存在 @@ -1767,17 +1746,17 @@ public static , L extends List>void ver * @throws Exception */ public static , L extends List> void verifyExist(String table - , Map param, long exceptId, @NotNull SQLCreator creator) throws Exception { + , Map param, long exceptId, @NotNull Parser parser) throws Exception { if (param.isEmpty()) { Log.e(TAG, "verifyExist is empty >> return;"); return; } - SQLConfig config = creator.createSQLConfig().setMethod(RequestMethod.HEAD).setCount(1).setPage(0); + SQLConfig config = parser.createSQLConfig().setMethod(RequestMethod.HEAD).setCount(1).setPage(0); config.setTable(table); param.forEach((key,value) -> config.putWhere(key, value, false)); - SQLExecutor executor = creator.createSQLExecutor(); + SQLExecutor executor = parser.getSQLExecutor(); try { M result = executor.execute(config, false); if (result == null) { @@ -1800,8 +1779,8 @@ public static , L extends List> void ve * @throws Exception */ public static , L extends List> void verifyRepeat(String table, String key - , Object value, @NotNull SQLCreator creator) throws Exception { - verifyRepeat(table, key, value, 0, creator); + , Object value, @NotNull Parser parser) throws Exception { + verifyRepeat(table, key, value, 0, parser); } /**验证是否重复 @@ -1812,8 +1791,8 @@ public static , L extends List> void ve * @throws Exception */ public static , L extends List> void verifyRepeat(String table, String key - , Object value, long exceptId, @NotNull SQLCreator creator) throws Exception { - verifyRepeat(table, key, value, exceptId, null, creator); + , Object value, long exceptId, @NotNull Parser parser) throws Exception { + verifyRepeat(table, key, value, exceptId, null, parser); } /**验证是否重复 @@ -1823,11 +1802,11 @@ public static , L extends List> void ve * @param value * @param exceptId 不包含id * @param idKey - * @param creator + * @param parser * @throws Exception */ public static , L extends List>void verifyRepeat(String table, String key - , Object value, long exceptId, String idKey, @NotNull SQLCreator creator) throws Exception { + , Object value, long exceptId, String idKey, @NotNull Parser parser) throws Exception { if (key == null || value == null) { Log.e(TAG, "verifyRepeat key == null || value == null >> return;"); return; @@ -1837,7 +1816,7 @@ public static , L extends List>void ver } Map map = new HashMap<>(); map.put(key,value); - verifyRepeat(table,map,exceptId,idKey,creator); + verifyRepeat(table, map, exceptId, idKey, parser); } /**验证是否重复 @@ -1846,26 +1825,26 @@ public static , L extends List>void ver * @param param * @param exceptId 不包含id * @param idKey - * @param creator + * @param parser * @throws Exception */ public static , L extends List> void verifyRepeat(String table - , Map param, long exceptId, String idKey, @NotNull SQLCreator creator) throws Exception { + , Map param, long exceptId, String idKey, @NotNull Parser parser) throws Exception { if (param.isEmpty()) { Log.e(TAG, "verifyRepeat is empty >> return;"); return; } - String finalIdKey = StringUtil.isEmpty(idKey, false) ? apijson.JSONObject.KEY_ID : idKey; + String finalIdKey = StringUtil.isEmpty(idKey, false) ? JSONMap.KEY_ID : idKey; - SQLConfig config = creator.createSQLConfig().setMethod(RequestMethod.HEAD).setCount(1).setPage(0); + SQLConfig config = parser.createSQLConfig().setMethod(RequestMethod.HEAD).setCount(1).setPage(0); config.setTable(table); if (exceptId > 0) { //允许修改自己的属性为该属性原来的值 config.putWhere(finalIdKey + "!", exceptId, false); } param.forEach((key,value) -> config.putWhere(key,value, false)); - SQLExecutor executor = creator.createSQLExecutor(); + SQLExecutor executor = parser.getSQLExecutor(); try { M result = executor.execute(config, false); if (result == null) { diff --git a/APIJSONORM/src/main/java/apijson/orm/Entry.java b/APIJSONORM/src/main/java/apijson/orm/Entry.java index a8aaf7bfd..3e010435b 100755 --- a/APIJSONORM/src/main/java/apijson/orm/Entry.java +++ b/APIJSONORM/src/main/java/apijson/orm/Entry.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/FunctionParser.java b/APIJSONORM/src/main/java/apijson/orm/FunctionParser.java index 155d80fae..8af029234 100644 --- a/APIJSONORM/src/main/java/apijson/orm/FunctionParser.java +++ b/APIJSONORM/src/main/java/apijson/orm/FunctionParser.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/JSONRequest.java b/APIJSONORM/src/main/java/apijson/orm/JSONRequest.java index ddc22365c..40bfa147a 100755 --- a/APIJSONORM/src/main/java/apijson/orm/JSONRequest.java +++ b/APIJSONORM/src/main/java/apijson/orm/JSONRequest.java @@ -1,23 +1,23 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ package apijson.orm; -import java.util.Map; +import java.util.*; import apijson.JSON; import apijson.StringUtil; -/**JSONRequest for Server to replace apijson.JSONObject, - * put JSON.parseObject(value) and not encode in default cases +/**JSONRequest for Server to replace apijson.JSONMap, + * put JSON.parseObject(value) and not encode in public cases * @author Lemon * @see #put(String, Object) */ -public class JSONRequest extends apijson.JSONRequest { - private static final long serialVersionUID = 1L; - +public class JSONRequest implements apijson.JSONRequest, ArrayList> { + + protected Map map = new LinkedHashMap<>(); public JSONRequest() { super(); } @@ -27,21 +27,40 @@ public JSONRequest() { * @param object */ public JSONRequest(Object object) { - super(object); + super(); + put(object); } /** * @param name * @param object */ public JSONRequest(String name, Object object) { - super(name, object); + super(); + put(name, object); } - - + ///**create a parent JSONMap named KEY_ARRAY + // * @param count + // * @param page + // * @return {@link #toArray(int, int)} + // */ + //public LinkedHashMap toArray(int count, int page) { + // return toArray(count, page, null); + //} + // + ///**create a parent JSONMap named name+KEY_ARRAY. + // * @param count + // * @param page + // * @param name + // * @return {name+KEY_ARRAY : this}. if needs to be put, use {@link #putsAll(Map)} instead + // */ + //public LinkedHashMap toArray(int count, int page, String name) { + // return new JSONRequest(StringUtil.get(name) + KEY_ARRAY, this.setCount(count).setPage(page)); + //} + @Override - public JSONRequest putsAll(Map map) { - super.putsAll(map); + public JSONRequest putsAll(Map m) { + putAll(m); return this; } @@ -51,7 +70,8 @@ public JSONRequest putsAll(Map map) { */ @Override public JSONRequest puts(Object value) { - return puts(null, value); + put(value); + return this; } /** * @param key @@ -65,14 +85,7 @@ public JSONRequest puts(String key, Object value) { return this; } - /** - * @param value - * @return {@link #put(String, Object)} - */ - @Override - public Object put(Object value) { - return put(null, value); - } + /**自定义类型必须转为JSONObject或JSONArray,否则RequestParser解析不了 */ @Override @@ -83,15 +96,77 @@ public Object put(String key, Object value) { Object target = null; try { - target = JSON.parseJSON(value); + target = JSON.parse(value); } catch (Exception e) { - throw new RuntimeException(e); + // nothing + e.printStackTrace(); } // if (target == null) { // "tag":"User" 报错 // return null; // } - return super.put(StringUtil.isNotEmpty(key, true) ? key : value.getClass().getSimpleName() //must handle key here + return map.put(StringUtil.isNotEmpty(key, true) ? key : value.getClass().getSimpleName() //must handle key here , target == null ? value : target); } + + @Override + public int size() { + return map.size(); + } + + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return map.containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return map.containsValue(value); + } + + @Override + public Object get(Object key) { + return map.get(key); + } + + @Override + public Object remove(Object key) { + return map.remove(key); + } + + + @Override + public void clear() { + map.clear(); + } + + @Override + public Set keySet() { + return map.keySet(); + } + + @Override + public Collection values() { + return map.values(); + } + + @Override + public Set> entrySet() { + return map.entrySet(); + } + + @Override + public String toString() { + return JSON.toJSONString(map); + } + + public String toJSONString() { + return JSON.toJSONString(map); + } + } diff --git a/APIJSONORM/src/main/java/apijson/orm/Join.java b/APIJSONORM/src/main/java/apijson/orm/Join.java index 39ca09a61..96d5e2ec7 100644 --- a/APIJSONORM/src/main/java/apijson/orm/Join.java +++ b/APIJSONORM/src/main/java/apijson/orm/Join.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ @@ -25,12 +25,14 @@ public class Join, L extends List> { private List onList; // ON User.id = Moment.userId AND ... private M request; // { "id@":"/Moment/userId" } - private M outer; // "join": { " joinConfig; private SQLConfig cacheConfig; - private SQLConfig outerConfig; + private SQLConfig onConfig; + private SQLConfig outerConfig; public String getPath() { return path; @@ -78,13 +80,29 @@ public M getRequest() { public void setRequest(M request) { this.request = request; } - public M getOuter() { - return outer; + public M getOn() { + return on; + } + public void setOn(M on) { + this.on = on; } + public void setOuter(M outer) { this.outer = outer; } + public M getOuter() { + return outer; + } + + public SQLConfig getOuterConfig() { + return outerConfig; + } + + public void setOuterConfig(SQLConfig outerConfig) { + this.outerConfig = outerConfig; + } + public SQLConfig getJoinConfig() { return joinConfig; } @@ -97,11 +115,11 @@ public SQLConfig getCacheConfig() { public void setCacheConfig(SQLConfig cacheConfig) { this.cacheConfig = cacheConfig; } - public SQLConfig getOuterConfig() { - return outerConfig; + public SQLConfig getOnConfig() { + return onConfig; } - public void setOuterConfig(SQLConfig outerConfig) { - this.outerConfig = outerConfig; + public void setOnConfig(SQLConfig onConfig) { + this.onConfig = onConfig; } public boolean isOne2One() { diff --git a/APIJSONORM/src/main/java/apijson/orm/Logic.java b/APIJSONORM/src/main/java/apijson/orm/Logic.java index bb8e806e6..f860aa9a4 100755 --- a/APIJSONORM/src/main/java/apijson/orm/Logic.java +++ b/APIJSONORM/src/main/java/apijson/orm/Logic.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/ObjectParser.java b/APIJSONORM/src/main/java/apijson/orm/ObjectParser.java index 8817886d1..5d207f41a 100755 --- a/APIJSONORM/src/main/java/apijson/orm/ObjectParser.java +++ b/APIJSONORM/src/main/java/apijson/orm/ObjectParser.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/OnParseCallback.java b/APIJSONORM/src/main/java/apijson/orm/OnParseCallback.java index 243acf048..e02fd90f8 100755 --- a/APIJSONORM/src/main/java/apijson/orm/OnParseCallback.java +++ b/APIJSONORM/src/main/java/apijson/orm/OnParseCallback.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/Operation.java b/APIJSONORM/src/main/java/apijson/orm/Operation.java index 2976d09b0..1c4f2dc5f 100755 --- a/APIJSONORM/src/main/java/apijson/orm/Operation.java +++ b/APIJSONORM/src/main/java/apijson/orm/Operation.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/Pair.java b/APIJSONORM/src/main/java/apijson/orm/Pair.java index a4bb22030..7661d07b5 100755 --- a/APIJSONORM/src/main/java/apijson/orm/Pair.java +++ b/APIJSONORM/src/main/java/apijson/orm/Pair.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ @@ -34,8 +34,8 @@ public class Pair extends Entry { CLASS_MAP.put(String.class.getSimpleName(), String.class); CLASS_MAP.put(Collection.class.getSimpleName(), Collection.class);//不允许指定 CLASS_MAP.put(Map.class.getSimpleName(), Map.class);//不允许指定 -// CLASS_MAP.put(JSONObject.class.getSimpleName(), JSONObject.class);//必须有,Map中没有getLongValue等方法 -// CLASS_MAP.put(JSONArray.class.getSimpleName(), JSONArray.class);//必须有,Collection中没有getJSONObject等方法 +// CLASS_MAP.put(JSONMap.class.getSimpleName(), JSONMap.class);//必须有,Map中没有getLongValue等方法 +// CLASS_MAP.put(JSONList.class.getSimpleName(), JSONList.class);//必须有,Collection中没有getJSONObject等方法 } diff --git a/APIJSONORM/src/main/java/apijson/orm/Parser.java b/APIJSONORM/src/main/java/apijson/orm/Parser.java index dd7a21276..1492dfc11 100755 --- a/APIJSONORM/src/main/java/apijson/orm/Parser.java +++ b/APIJSONORM/src/main/java/apijson/orm/Parser.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ @@ -15,7 +15,8 @@ /**解析器 * @author Lemon */ -public interface Parser, L extends List> { +public interface Parser, L extends List> + extends ParserCreator, VerifierCreator, SQLCreator { @NotNull Visitor getVisitor(); diff --git a/APIJSONORM/src/main/java/apijson/orm/ParserCreator.java b/APIJSONORM/src/main/java/apijson/orm/ParserCreator.java index d6eb1c7db..f3f8d375b 100755 --- a/APIJSONORM/src/main/java/apijson/orm/ParserCreator.java +++ b/APIJSONORM/src/main/java/apijson/orm/ParserCreator.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java index 44d4264be..5386d160e 100755 --- a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java +++ b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ @@ -33,7 +33,9 @@ public interface SQLConfig, L extends List, L extends List, L extends List, L extends List config, String table, RequestMethod method, String role) throws Exception; @@ -76,7 +76,7 @@ public interface Verifier, L extends List creator) throws Exception; + int maxUpdateCount, String globalDatabase, String globalSchema) throws Exception; /**验证返回结果的数据和结构 * @param method @@ -92,13 +92,16 @@ M verifyRequest(RequestMethod method, String name, M target, M request, */ M verifyResponse( RequestMethod method, String name, M target, M response, - String database, String schema, SQLCreator creator, OnParseCallback callback + String database, String schema, @NotNull Parser parser, OnParseCallback callback ) throws Exception; @NotNull Parser createParser(); + Parser getParser(); + Verifier setParser(AbstractParser parser); + @NotNull Visitor getVisitor(); Verifier setVisitor(@NotNull Visitor visitor); diff --git a/APIJSONORM/src/main/java/apijson/orm/VerifierCreator.java b/APIJSONORM/src/main/java/apijson/orm/VerifierCreator.java index a3c51694a..374290989 100644 --- a/APIJSONORM/src/main/java/apijson/orm/VerifierCreator.java +++ b/APIJSONORM/src/main/java/apijson/orm/VerifierCreator.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/Visitor.java b/APIJSONORM/src/main/java/apijson/orm/Visitor.java index f474bd91e..5d1b6063d 100755 --- a/APIJSONORM/src/main/java/apijson/orm/Visitor.java +++ b/APIJSONORM/src/main/java/apijson/orm/Visitor.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/exception/CommonException.java b/APIJSONORM/src/main/java/apijson/orm/exception/CommonException.java index 565cef453..7e2884ef7 100755 --- a/APIJSONORM/src/main/java/apijson/orm/exception/CommonException.java +++ b/APIJSONORM/src/main/java/apijson/orm/exception/CommonException.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ @@ -247,9 +247,15 @@ else if (config.isPresto()) { else if (config.isTrino()) { db = SQLConfig.DATABASE_TRINO + " " + dbVersion; } + else if (config.isDoris()) { + db = SQLConfig.DATABASE_DORIS + " " + dbVersion; + } else if (config.isSnowflake()) { db = SQLConfig.DATABASE_SNOWFLAKE + " " + dbVersion; } + else if (config.isDatabend()) { + db = SQLConfig.DATABASE_DATABEND + " " + dbVersion; + } else if (config.isDatabricks()) { db = SQLConfig.DATABASE_DATABRICKS + " " + dbVersion; } diff --git a/APIJSONORM/src/main/java/apijson/orm/exception/ConditionErrorException.java b/APIJSONORM/src/main/java/apijson/orm/exception/ConditionErrorException.java index fe2ccd761..44c43a29f 100755 --- a/APIJSONORM/src/main/java/apijson/orm/exception/ConditionErrorException.java +++ b/APIJSONORM/src/main/java/apijson/orm/exception/ConditionErrorException.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/exception/ConflictException.java b/APIJSONORM/src/main/java/apijson/orm/exception/ConflictException.java index ee258eee9..a39d88d3b 100755 --- a/APIJSONORM/src/main/java/apijson/orm/exception/ConflictException.java +++ b/APIJSONORM/src/main/java/apijson/orm/exception/ConflictException.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/exception/NotExistException.java b/APIJSONORM/src/main/java/apijson/orm/exception/NotExistException.java index 5c5a42bc8..69e34a809 100755 --- a/APIJSONORM/src/main/java/apijson/orm/exception/NotExistException.java +++ b/APIJSONORM/src/main/java/apijson/orm/exception/NotExistException.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/exception/NotLoggedInException.java b/APIJSONORM/src/main/java/apijson/orm/exception/NotLoggedInException.java index 2fbbb89ba..1e16b5796 100755 --- a/APIJSONORM/src/main/java/apijson/orm/exception/NotLoggedInException.java +++ b/APIJSONORM/src/main/java/apijson/orm/exception/NotLoggedInException.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/exception/OutOfRangeException.java b/APIJSONORM/src/main/java/apijson/orm/exception/OutOfRangeException.java index bde6fa42c..043ba5a65 100755 --- a/APIJSONORM/src/main/java/apijson/orm/exception/OutOfRangeException.java +++ b/APIJSONORM/src/main/java/apijson/orm/exception/OutOfRangeException.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/exception/UnsupportedDataTypeException.java b/APIJSONORM/src/main/java/apijson/orm/exception/UnsupportedDataTypeException.java index e272141c9..1c7d7c27a 100644 --- a/APIJSONORM/src/main/java/apijson/orm/exception/UnsupportedDataTypeException.java +++ b/APIJSONORM/src/main/java/apijson/orm/exception/UnsupportedDataTypeException.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/exception/package-info.java b/APIJSONORM/src/main/java/apijson/orm/exception/package-info.java index 70d3bb96e..073c6bdac 100755 --- a/APIJSONORM/src/main/java/apijson/orm/exception/package-info.java +++ b/APIJSONORM/src/main/java/apijson/orm/exception/package-info.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/model/Access.java b/APIJSONORM/src/main/java/apijson/orm/model/Access.java index e114f5654..ab44f8664 100644 --- a/APIJSONORM/src/main/java/apijson/orm/model/Access.java +++ b/APIJSONORM/src/main/java/apijson/orm/model/Access.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/model/AllColumn.java b/APIJSONORM/src/main/java/apijson/orm/model/AllColumn.java index 90da2664e..02906c6ec 100644 --- a/APIJSONORM/src/main/java/apijson/orm/model/AllColumn.java +++ b/APIJSONORM/src/main/java/apijson/orm/model/AllColumn.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/model/AllColumnComment.java b/APIJSONORM/src/main/java/apijson/orm/model/AllColumnComment.java index fe98fa51d..81e2c9fe9 100644 --- a/APIJSONORM/src/main/java/apijson/orm/model/AllColumnComment.java +++ b/APIJSONORM/src/main/java/apijson/orm/model/AllColumnComment.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/model/AllTable.java b/APIJSONORM/src/main/java/apijson/orm/model/AllTable.java index 215fde316..2934ad0ba 100644 --- a/APIJSONORM/src/main/java/apijson/orm/model/AllTable.java +++ b/APIJSONORM/src/main/java/apijson/orm/model/AllTable.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/model/AllTableComment.java b/APIJSONORM/src/main/java/apijson/orm/model/AllTableComment.java index 5dd4b0a4d..49a4dee3a 100644 --- a/APIJSONORM/src/main/java/apijson/orm/model/AllTableComment.java +++ b/APIJSONORM/src/main/java/apijson/orm/model/AllTableComment.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/model/Column.java b/APIJSONORM/src/main/java/apijson/orm/model/Column.java index d38d4fda3..573ab7fc4 100755 --- a/APIJSONORM/src/main/java/apijson/orm/model/Column.java +++ b/APIJSONORM/src/main/java/apijson/orm/model/Column.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/model/Document.java b/APIJSONORM/src/main/java/apijson/orm/model/Document.java index 6f2a8bba2..2e8db19c2 100755 --- a/APIJSONORM/src/main/java/apijson/orm/model/Document.java +++ b/APIJSONORM/src/main/java/apijson/orm/model/Document.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/model/ExtendedProperty.java b/APIJSONORM/src/main/java/apijson/orm/model/ExtendedProperty.java index 81227eb13..393a7e0d1 100644 --- a/APIJSONORM/src/main/java/apijson/orm/model/ExtendedProperty.java +++ b/APIJSONORM/src/main/java/apijson/orm/model/ExtendedProperty.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/model/Function.java b/APIJSONORM/src/main/java/apijson/orm/model/Function.java index b02175f4a..da6c3f53e 100644 --- a/APIJSONORM/src/main/java/apijson/orm/model/Function.java +++ b/APIJSONORM/src/main/java/apijson/orm/model/Function.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/model/PgAttribute.java b/APIJSONORM/src/main/java/apijson/orm/model/PgAttribute.java index 7c85f9f42..dbd4b4b69 100644 --- a/APIJSONORM/src/main/java/apijson/orm/model/PgAttribute.java +++ b/APIJSONORM/src/main/java/apijson/orm/model/PgAttribute.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/model/PgClass.java b/APIJSONORM/src/main/java/apijson/orm/model/PgClass.java index 3a47b2791..199a7ef86 100644 --- a/APIJSONORM/src/main/java/apijson/orm/model/PgClass.java +++ b/APIJSONORM/src/main/java/apijson/orm/model/PgClass.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/model/Request.java b/APIJSONORM/src/main/java/apijson/orm/model/Request.java index 8e83a2707..5d0d04092 100755 --- a/APIJSONORM/src/main/java/apijson/orm/model/Request.java +++ b/APIJSONORM/src/main/java/apijson/orm/model/Request.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/model/Script.java b/APIJSONORM/src/main/java/apijson/orm/model/Script.java index ddb608432..53cda4323 100644 --- a/APIJSONORM/src/main/java/apijson/orm/model/Script.java +++ b/APIJSONORM/src/main/java/apijson/orm/model/Script.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/model/SysColumn.java b/APIJSONORM/src/main/java/apijson/orm/model/SysColumn.java index 3e2c5c2b0..a4d7ca881 100644 --- a/APIJSONORM/src/main/java/apijson/orm/model/SysColumn.java +++ b/APIJSONORM/src/main/java/apijson/orm/model/SysColumn.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/model/SysTable.java b/APIJSONORM/src/main/java/apijson/orm/model/SysTable.java index 221807c48..bb6142310 100644 --- a/APIJSONORM/src/main/java/apijson/orm/model/SysTable.java +++ b/APIJSONORM/src/main/java/apijson/orm/model/SysTable.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/model/Table.java b/APIJSONORM/src/main/java/apijson/orm/model/Table.java index 0135fd947..1ab004cce 100755 --- a/APIJSONORM/src/main/java/apijson/orm/model/Table.java +++ b/APIJSONORM/src/main/java/apijson/orm/model/Table.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/model/TestRecord.java b/APIJSONORM/src/main/java/apijson/orm/model/TestRecord.java index b1ceaa77c..32ad98f9e 100644 --- a/APIJSONORM/src/main/java/apijson/orm/model/TestRecord.java +++ b/APIJSONORM/src/main/java/apijson/orm/model/TestRecord.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/model/package-info.java b/APIJSONORM/src/main/java/apijson/orm/model/package-info.java index af556632a..a0b5641c9 100755 --- a/APIJSONORM/src/main/java/apijson/orm/model/package-info.java +++ b/APIJSONORM/src/main/java/apijson/orm/model/package-info.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/package-info.java b/APIJSONORM/src/main/java/apijson/orm/package-info.java index e0f9a3d51..76569c93d 100755 --- a/APIJSONORM/src/main/java/apijson/orm/package-info.java +++ b/APIJSONORM/src/main/java/apijson/orm/package-info.java @@ -1,4 +1,4 @@ -/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +/*Copyright (C) 2020 Tencent. All rights reserved. This source code is licensed under the Apache License Version 2.0.*/ diff --git a/APIJSONORM/src/main/java/apijson/orm/script/JSR223ScriptExecutor.java b/APIJSONORM/src/main/java/apijson/orm/script/JSR223ScriptExecutor.java index 59dba0117..6a3a6c4f4 100644 --- a/APIJSONORM/src/main/java/apijson/orm/script/JSR223ScriptExecutor.java +++ b/APIJSONORM/src/main/java/apijson/orm/script/JSR223ScriptExecutor.java @@ -55,7 +55,7 @@ public Object execute(AbstractFunctionParser parser, Map cloudAndMonkey 提交的 11 个 Commits, 对 APIJSON 做出了 1,496 增加和 845 处删减(截止 2022/12/15 日);
diff --git a/Document-English.md b/Document-English.md index c9a4f2948..62f40b0a0 100644 --- a/Document-English.md +++ b/Document-English.md @@ -324,7 +324,7 @@ Response: Fuzzy matching | `"key$":"SQL search expressions"` => `"key$":["SQL search expressions"]`
Any SQL search expressions.Eg.%key%(include key), key%(start with key),%k%e%y%(include k, e, y). % means any characters. | ["name$":"%m%"](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"name$":"%2525m%2525"}}})
In SQL, it's
`name LIKE '%m%'`,
meaning that get User with ‘m’ in name. Regular Expression| `"key~":"regular expression"` => `"key~":["regular expression"]`
It can be any regular expressions.Eg. ^[0-9]+$ ,*~ not case sensitive, advanced search is applicable.| ["name~":"^[0-9]+$"](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"name~":"^[0-9]%252B$"}}})
In SQL, it's
`name REGEXP '^[0-9]+$'`. Get data in a range| `"key%":"start,end"` => `"key%":["start,end"]`
The data type of start and end can only be either Boolean, Number or String. Eg. "2017-01-01,2019-01-01" ,["1,90000", "82001,100000"]. It's used for getting data from a specific time range. | ["date%":"2017-10-01,2018-10-01"](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"date%2525":"2017-10-01,2018-10-01"}}})
In SQL, it's
`date BETWEEN '2017-10-01' AND '2018-10-01'`,
meaning to get User data that registered between 2017-10-01 and 2018-10-01. - Make an alias | `"name:alias"`
this changes name to alias in returning results. It’s applicable to column, tableName, SQL Functions, etc. but only in GET, HEAD requests. | ["@column":"toId:parentId"](http://apijson.cn:8080/get/{"Comment":{"@column":"id,toId:parentId","id":51}})
In SQL, it's
`toId AS parentId`.
It'll return `parentId` instead of `toId`. + Make an alias | `"name:alias"`
this changes name to alias in returning results. It’s applicable to column, tableName, SQL Functions, etc. but only in GET, HEAD requests. | ["@column":"toId:parentId"](http://apijson.cn:8080/get/{"Comment":{"@column":"id,toId:parentId","id":51}})
In SQL, it's
`toId AS parentId`.
It'll return `parentId` instead of `toId`.

For @key format like "lc_wai6b3vk2:(lc_wai6b3vk)", it means renaming field lc_wai6b3vk2 to lc_wai6b3vk, commonly used for field renaming scenarios. Example:
{
  "lc_sinan_ba074fbb": {
    "lc_wai6b3vk": "11",
    "lc_wai6b3vk2": "22",
    "@combine": "lc_wai6b3vk \\| lc_wai6b3vk2",
    "@key": "lc_wai6b3vk2:(lc_wai6b3vk)"
  }
}
corresponds to SQL `(lc_wai6b3vk = '11' OR lc_wai6b3vk2 = '22')`, but the lc_wai6b3vk2 field will be renamed and displayed as lc_wai6b3vk in the returned result Add / expand an item | `"key+":Object`
The type of Object is decided by *key*. Types can be Number, String, JSONArray. Froms are 82001,"apijson",["url0","url1"] respectively. It’s only applicable to PUT request.| "praiseUserIdList+":[82001]. In SQL, it's
`json_insert(praiseUserIdList,82001)`.
Add an *id* that praised the Moment. Delete / decrease an item | `"Key-":Object`
It’s the contrary of "key+" | "balance-":100.00. In SQL, it's
`balance = balance - 100.00`,
meaning there's 100 less in balance. Operations | &, \|, !
They're used in logic operations. It’s the same as AND, OR, NOT in SQL respectively.
By default, for the same key, it’s ‘\|’ (OR)operation among conditions; for different keys, the default operation among conditions is ‘&’(AND).
| ① ["id&{}":">80000,<=90000"](http://apijson.cn:8080/head/{"User":{"id&{}":">80000,<=90000"}})
In SQL, it's
`id>80000 AND id<=90000`,
meaning *id* needs to be id>80000 & id<=90000

② ["id\|{}":">90000,<=80000"](http://apijson.cn:8080/head/{"User":{"id\|{}":">90000,<=80000"}})
It's the same as "id{}":">90000,<=80000".
In SQL, it's
`id>80000 OR id<=90000`,
meaning that *id* needs to be id>90000 \| id<=80000

③ ["id!{}":[82001,38710]](http://apijson.cn:8080/head/{"User":{"id!{}":[82001,38710]}})
In SQL, it's
`id NOT IN(82001,38710)`,
meaning id needs to be ! (id=82001 \| id=38710). diff --git a/Document.md b/Document.md index a97f7b823..11db6fe86 100644 --- a/Document.md +++ b/Document.md @@ -408,19 +408,19 @@ DELETE:
删除数据 | base_url/delete/ | {
   TableName:{< 匹配条件范围 | "key{}":"条件0,条件1...",条件为 SQL 表达式字符串,可进行数字比较运算等 | ["id{}":"<=80000,\>90000"](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"id{}":"<=80000,\>90000"}}}),对应 SQL 是`id<=80000 OR id>90000`,查询 id 符合 id\<=80000 \| id>90000 的一个 User 数组 包含选项范围 | "key<\>":value => "key<\>":[value],key 对应值的类型必须为 JSONArray,value 值类型只能为 Boolean, Number, String 中的一种 | ["contactIdList<\>":38710](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"contactIdList<\>":38710}}}),对应SQL是`json_contains(contactIdList,38710)`,查询 contactIdList 包含 38710 的一个 User 数组 判断是否存在 | "key}{@":{
   "from":"Table",
   "Table":{ ... }
}
其中:
}{ 表示 EXISTS;
key 用来标识是哪个判断;
@ 后面是 子查询 对象,具体见下方 子查询 的说明。 | ["id}{@":{
   "from":"Comment",
   "Comment":{
      "momentId":15
   }
}](http://apijson.cn:8080/get/{"User":{"id}{@":{"from":"Comment","Comment":{"momentId":15}}}})
WHERE EXISTS(SELECT * FROM Comment WHERE momentId=15) - 远程调用函数 | "key()":"函数表达式",函数表达式为 function(key0,key1...),会调用后端对应的函数 function(JSONObject request, String key0, String key1...),实现 参数校验、数值计算、数据同步、消息推送、字段拼接、结构变换 等特定的业务逻辑处理,
可使用 - 和 + 表示优先级,解析 key-() > 解析当前对象 > 解析 key() > 解析子对象 > 解析 key+() | ["isPraised()":"isContain(praiseUserIdList,userId)"](http://apijson.cn:8080/get/{"Moment":{"id":301,"isPraised()":"isContain(praiseUserIdList,userId)"}}),会调用远程函数 [boolean isContain(JSONObject request, String array, String value)](https://github.com/APIJSON/apijson-framework/blob/master/src/main/java/apijson/framework/APIJSONFunctionParser.java#L361-L374) ,然后变为 "isPraised":true 这种(假设点赞用户 id 列表包含了 userId,即这个 User 点了赞) - 存储过程 | "@key()":"SQL函数表达式",函数表达式为
function(key0,key1...)
会调用后端数据库对应的存储过程 SQL 函数
function(String key0, String key1...)
除了参数会提前赋值,其它和 远程函数 一致 | ["@limit":10,
"@offset":0,
"@procedure()":"getCommentByUserId(id,@limit,@offset)"](http://apijson.cn:8080/get/{"User":{"@limit":10,"@offset":0,"@procedure()":"getCommentByUserId(id,@limit,@offset)"}})
会转为
`getCommentByUserId(38710,10,0)`
来调用存储过程 SQL 函数
`getCommentByUserId(IN id bigint, IN limit int, IN offset int)`
然后变为
"procedure":{
   "count":-1,
   "update":false,
   "list":[]
}
其中 count 是指写操作影响记录行数,-1 表示不是写操作;update 是指是否为写操作(增删改);list 为返回结果集 - 引用赋值 | "key@":"key0/key1/.../refKey",引用路径为用 / 分隔的字符串。以 / 开头的是缺省引用路径,从声明 key 所处容器的父容器路径开始;其它是完整引用路径,从最外层开始。
被引用的 refKey 必须在声明 key 的上面。如果对 refKey 的容器指定了返回字段,则被引用的 refKey 必须写在 @column 对应的值内,例如 "@column":"refKey,key1,..." | ["Moment":{
   "userId":38710
},
"User":{
   "id@":"/Moment/userId"
}](http://apijson.cn:8080/get/{"Moment":{"userId":38710},"User":{"id@":"%252FMoment%252FuserId"}})
User 内的 id 引用了与 User 同级的 Moment 内的 userId,
即 User.id = Moment.userId,请求完成后
"id@":"/Moment/userId" 会变成 "id":38710 - 子查询 | "key@":{
   "range":"ALL",
   "from":"Table", // 可省略,默认为首个表对象 key 名
   "Table":{ ... }
}
其中:
range 可为 ALL,ANY;
from 为目标表 Table 的名称;
@ 后面的对象类似数组对象,可使用 count 和 join 等功能。 | ["id@":{
   "from":"Comment", // 可省略
   "Comment":{
      "@column":"min(userId)"
   }
}](http://apijson.cn:8080/get/{"User":{"id@":{"from":"Comment","Comment":{"@column":"min(userId)"}}}})
WHERE id=(SELECT min(userId) FROM Comment) - 模糊搜索 | `"key$":"SQL搜索表达式"` => `"key$":["SQL搜索表达式"]`,任意 SQL 搜索表达式字符串,如 %key%(包含 key), key%(以 key 开始), %k%e%y%(包含字母 k,e,y) 等,% 表示任意字符 | ["name$":"%m%"](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"name$":"%2525m%2525"}}}),对应 SQL 是`name LIKE '%m%'`,查询 name 包含 "m" 的一个 User 数组 - 正则匹配 | "key~":"正则表达式" => "key~":["正则表达式"],任意正则表达式字符串,如 ^[0-9]+$ ,*~ 忽略大小写,可用于高级搜索 | ["name~":"^[0-9]+$"](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"name~":"^[0-9]%252B$"}}}),对应 SQL 是`name REGEXP '^[0-9]+$'`,查询 name 中字符全为数字的一个 User 数组 - 连续范围 | "key%":"start,end" => "key%":["start,end"],其中 start 和 end 都只能为 Number, String 中的一种,如 "2017-01-01,2019-01-01" ,["1,90000", "82001,100000"] ,可用于连续范围内的筛选 | ["date%":"2017-10-01,2018-10-01"](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"date%2525":"2017-10-01,2018-10-01"}}}),对应SQL是`date BETWEEN '2017-10-01' AND '2018-10-01'`,查询在2017-10-01和2018-10-01期间注册的用户的一个User数组 - 新建别名 | "name:alias",name 映射为 alias,用 alias 替代 name。可用于 column,Table,SQL 函数 等。只用于 GET 类型、HEAD 类型的请求 | ["@column":"toId:parentId"](http://apijson.cn:8080/get/{"Comment":{"@column":"id,toId:parentId","id":51}}),对应 SQL 是`toId AS parentId`,将查询的字段 toId 变为 parentId 返回 - 增加 或 扩展 | "key+":Object,Object的类型由key指定,且类型为 Number,String,JSONArray 中的一种。如 82001,"apijson",["url0","url1"] 等。只用于 PUT 请求 | "praiseUserIdList+":[82001],对应 SQL 是`json_insert(praiseUserIdList,82001)`,添加一个点赞用户 id,即这个用户点了赞 + 远程调用函数 | "key()":"函数表达式",函数表达式为 function(key0,key1...),会调用后端对应的函数 function(JSONObject request, String key0, String key1...),实现 参数校验、数值计算、数据同步、消息推送、字段拼接、结构变换 等特定的业务逻辑处理,
可使用 - 和 + 表示优先级,解析 key-() > 解析当前对象 > 解析 key() > 解析子对象 > 解析 key+() | ["isPraised()":"isContain(praiseUserIdList,userId)"](http://apijson.cn:8080/get/{"Moment":{"id":301,"isPraised()":"isContain(praiseUserIdList,userId)"}}),会调用远程函数 [boolean isContain(JSONObject request, String array, String value)](https://github.com/APIJSON/apijson-framework/blob/master/src/main/java/apijson/framework/APIJSONFunctionParser.java#L361-L374) ,然后变为 "isPraised":true 这种(假设点赞用户id列表包含了userId,即这个User点了赞) + 存储过程 | "@key()":"SQL函数表达式",函数表达式为
function(key0,key1...)
会调用后端数据库对应的存储过程 SQL函数
function(String key0, String key1...)
除了参数会提前赋值,其它和 远程函数 一致 | ["@limit":10,
"@offset":0,
"@procedure()":"getCommentByUserId(id,@limit,@offset)"](http://apijson.cn:8080/get/{"User":{"@limit":10,"@offset":0,"@procedure()":"getCommentByUserId(id,@limit,@offset)"}})
会转为
`getCommentByUserId(38710,10,0)`
来调用存储过程 SQL 函数
`getCommentByUserId(IN id bigint, IN limit int, IN offset int)`
然后变为
"procedure":{
   "count":-1,
   "update":false,
   "list":[]
}
其中 count 是指写操作影响记录行数,-1 表示不是写操作;update 是指是否为写操作(增删改);list 为返回结果集 + 引用赋值 | "key@":"key0/key1/.../refKey",引用路径为用/分隔的字符串。以/开头的是缺省引用路径,从声明key所处容器的父容器路径开始;其它是完整引用路径,从最外层开始。
被引用的refKey必须在声明key的上面。如果对refKey的容器指定了返回字段,则被引用的refKey必须写在@column对应的值内,例如 "@column":"refKey,key1,..." | ["Moment":{
   "userId":38710
},
"User":{
   "id@":"/Moment/userId"
}](http://apijson.cn:8080/get/{"Moment":{"userId":38710},"User":{"id@":"%252FMoment%252FuserId"}})
User内的id引用了与User同级的Moment内的userId,
即User.id = Moment.userId,请求完成后
"id@":"/Moment/userId" 会变成 "id":38710 + 子查询 | "key@":{
   "range":"ALL",
   "from":"Table",
   "Table":{ ... }
}
其中:
range 可为 ALL,ANY;
from 为目标表 Table 的名称;
@ 后面的对象类似数组对象,可使用 count 和 join 等功能。 | ["id@":{
   "from":"Comment",
   "Comment":{
      "@column":"min(userId)"
   }
}](http://apijson.cn:8080/get/{"User":{"id@":{"from":"Comment","Comment":{"@column":"min(userId)"}}}})
WHERE id=(SELECT min(userId) FROM Comment) + 模糊搜索 | `"key$":"SQL搜索表达式"` => `"key$":["SQL搜索表达式"]`,任意SQL搜索表达式字符串,如 %key%(包含key), key%(以key开始), %k%e%y%(包含字母k,e,y) 等,%表示任意字符 | ["name$":"%m%"](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"name$":"%2525m%2525"}}}),对应SQL是`name LIKE '%m%'`,查询name包含"m"的一个User数组 + 正则匹配 | "key~":"正则表达式" => "key~":["正则表达式"],任意正则表达式字符串,如 ^[0-9]+$ ,*~ 忽略大小写,可用于高级搜索 | ["name~":"^[0-9]+$"](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"name~":"^[0-9]%252B$"}}}),对应SQL是`name REGEXP '^[0-9]+$'`,查询name中字符全为数字的一个User数组 + 连续范围 | "key%":"start,end" => "key%":["start,end"],其中 start 和 end 都只能为 Boolean, Number, String 中的一种,如 "2017-01-01,2019-01-01" ,["1,90000", "82001,100000"] ,可用于连续范围内的筛选 | ["date%":"2017-10-01,2018-10-01"](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"date%2525":"2017-10-01,2018-10-01"}}}),对应SQL是`date BETWEEN '2017-10-01' AND '2018-10-01'`,查询在2017-10-01和2018-10-01期间注册的用户的一个User数组 + 新建别名 | ① "name:alias",name 映射为 alias,用 alias 替代 name,可用于 column,Table,SQL 函数 等,只用于 GET 类型、HEAD 类型的请求

② 函数调用映射
"@key": "fun:avg(id);keyA:(keyB)",
"fun>": 1,
"keyA": 1
其中 fun:fun(arg) 把 SQL 函数调用 fun(arg) 作为左侧表达式替代 fun,即 fun(arg) > 1;
keyA:(keyB) 表示将字段 keyA 重命名为 keyB,即实际 SQL 中为 keyB = 1,常用于重命名冲突的多条件同名字段。 | ① ["@column":"toId:parentId"](http://apijson.cn:8080/get/{"Comment":{"@column":"id,toId:parentId","id":51}}),对应 SQL 是 `toId AS parentId`,将查询的字段 toId 变为 parentId 返回

② ["@key": "len:length(content);mid:(momentId)",
"len<=": 10,
"mid": 12,
"momentId": 15,
"@combine": "(len<= \\| mid) & momentId"](http://apijson.cn/api?type=JSON&json={%22Comment%22:{%22@key%22:%22len%3Alength(content)%3Bmid%3A(momentId)%22,%22len%3C=%22:10,%22mid%22:12,%22momentId%22:15,%22@combine%22:%22(len%3C%3D%20%7C%20mid)%20%26%20momentId%22}})
对应 SQL 是 `(length(content) <= 10 OR momentId = 12) AND momentId = 15` + 增加 或 扩展 | "key+":Object,Object的类型由key指定,且类型为Number,String,JSONArray中的一种。如 82001,"apijson",["url0","url1"] 等。只用于PUT请求 | "praiseUserIdList+":[82001],对应SQL是`json_insert(praiseUserIdList,82001)`,添加一个点赞用户id,即这个用户点了赞 减少 或 去除 | "key-":Object,与"key+"相反 | "balance-":100.00,对应SQL是`balance = balance - 100.00`,余额减少100.00,即花费了100元 比较运算 | >, <, >=, <= 比较运算符,用于
① 提供 "id{}":"<=90000" 这种条件范围的简化写法

② 实现子查询相关比较运算

不支持 "key=":Object 和 "key!=":Object 这两种写法,直接用更简单的 "key":Object 和 "key!":Object 替代。 | ① ["id<=":90000](http://apijson.cn:8080/get/{"[]":{"User":{"id<=":90000}}}),对应 SQL 是`id<=90000`,查询符合id<=90000的一个User数组

② ["id>@":{
   "from":"Comment",
   "Comment":{
      "@column":"min(userId)"
   }
}](http://apijson.cn:8080/get/{"User":{"id>@":{"from":"Comment","Comment":{"@column":"min(userId)"}}}})
WHERE id>(SELECT min(userId) FROM Comment) 逻辑运算 | &, \|, ! 逻辑运算符,对应数据库 SQL 中的 AND, OR, NOT。
横或纵与:同一键值对的值内条件默认 \| 或连接,可以在 key 后加逻辑运算符来具体指定;不同键值对的条件默认 & 与连接,可以用下面说明的对象关键词 @combine 来具体指定。

① & 可用于 "key&{}":"条件"等

② \| 可用于 "key\|{}":"条件", "key\|{}":[]等,一般可省略

③ ! 可单独使用,如 "key!":Object,也可像 &,\| 一样配合其他功能符使用
"key!":null 无效,null 值会导致整个键值对被忽略解析,可以用 "key{}":"!=null" 替代,
"key":null 同理,用 "key{}":"=null" 替代。 | ① ["id&{}":">80000,<=90000"](http://apijson.cn:8080/head/{"User":{"id&{}":">80000,<=90000"}}),对应SQL是`id>80000 AND id<=90000`,即id满足id>80000 & id<=90000

② ["id\|{}":">90000,<=80000"](http://apijson.cn:8080/head/{"User":{"id\|{}":">90000,<=80000"}}),同 "id{}":">90000,<=80000",对应 SQL 是`id>90000 OR id<=80000`,即 id 满足 id>90000 \| id<=80000

③ ["id!{}":[82001,38710]](http://apijson.cn:8080/head/{"User":{"id!{}":[82001,38710]}}),对应 SQL 是`id NOT IN(82001,38710)`,即 id 满足 ! (id=82001 \| id=38710),可过滤黑名单的消息 - 数组关键词,可自定义 | "key":Object,key为 "[]":{} 中 {} 内的关键词,Object 的类型由 key 指定

① "count":5,查询数量,0 表示最大值,默认值为 10,默认最大值为 100

② "page":1,查询页码,从 0 开始,默认值为 0,默认最大值为 100,一般和 count 一起用

③ "query":2,查询内容
0-对象,1-总数和分页详情,2-数据、总数和分页详情
总数关键词为 total,分页详情关键词为 info,
它们都和 query 同级,通过引用赋值得到自定义 key:value 键值对,不传则返回默认键值对,例如
"total@":"/[]/total", "info@":"/[]/info"
这里query及total仅为GET类型的请求提供方便,
一般可直接用HEAD类型的请求获取总数

④ "join":"&/Table0,\"join":{
   "&/Table0":{}, // 支持 ON 多个字段关联,
   "\      "key0":value0, // 其它ON条件
     "key2":value2,
     ...
     "@combine":"...", // 其它ON条件的组合方式
     "@column":"...", // 外层 SELECT
     "@group":"...", // 外层 GROUP BY
     "@having":"..." // 外层 HAVING
   }
}
多表连接方式:
"@" - APP JOIN
"\<" - LEFT JOIN
">" - RIGHT JOIN
"&" - INNER JOIN
"\|" - FULL JOIN
"!" - OUTER JOIN
"*" - CROSS JOIN
"^" - SIDE JOIN
"(" - ANTI JOIN
")" - FOREIGN JOIN
其中 @ APP JOIN 为应用层连表,会从已查出的主表里取得所有副表 key@ 关联的主表内的 refKey 作为一个数组 refKeys: [value0, value1...],然后把原来副表 count 次查询 key=$refKey 的 SQL 用 key IN($refKeys) 的方式合并为一条 SQL 来优化性能;
其它 JOIN 都是 SQL JOIN,具体功能和 MySQL,PostgreSQL 等数据库的 JOIN 一一对应
`"join":"`"MainTable":{},`
`"ViceTable":{"key@":"/MainTable/refKey"}`
会对应生成
`MainTable LEFT JOIN ViceTable`
`ON ViceTable.key=MainTable.refKey` AND 其它ON条件
除了 = 等价关联,也支持 ! 不等关联、\> \< \>= \<= 等比较关联和 $ ~ {} <> 等其它复杂关联方式

⑤ "otherKey":Object,自定义关键词,名称和以上系统关键词不一样,且原样返回上传的值 | ① 查询User数组,最多5个:
["count":5](http://apijson.cn:8080/get/{"[]":{"count":5,"User":{}}})
对应 SQL 是`LIMIT 5`

② 查询第3页的User数组,每页5个:
["count":5,
"page":3](http://apijson.cn:8080/get/{"[]":{"count":5,"page":3,"User":{}}})
对应 SQL 是`LIMIT 5 OFFSET 15`

③ 查询User数组和对应的User总数:
["[]":{
   "query":2,
   "User":{}
},
"total@":"/[]/total", // 可省略
"info@":"/[]/info" // 可省略](http://apijson.cn:8080/get/{"[]":{"query":2,"count":5,"User":{}},"total@":"%252F[]%252Ftotal","info@":"%252F[]%252Finfo"})
返回的数据中,总数及分页详情结构为:
"total":139, // 总数
"info":{ // 分页详情
   "total":139, // 总数
   "count":5, // 每页数量
   "page":0, // 当前页码
   "max":27, // 最大页码
   "more":true, // 是否还有更多
   "first":true, // 是否为首页
   "last":false // 是否为尾页
}

④ Moment INNER JOIN User LEFT JOIN Comment:
["[]":{
   "join":"&/User/id@,\    "Moment":{
     "@group":"id" // 主副表不是一对一,要去除重复数据
   },
   "User":{
     "name~":"t",
     "id@":"/Moment/userId"
   },
   "Comment":{
     "momentId@":"/Moment/id"
   }
}](http://apijson.cn/api/?type=JSON&url=http://apijson.cn:8080/get&json=%7B%22%5B%5D%22:%7B%22count%22:5,%22join%22:%22%26%2FUser%2Fid@,%3C%2FComment%22,%22Moment%22:%7B%22@column%22:%22id,userId,content%22,%22@group%22:%22id%22%7D,%22User%22:%7B%22name~%22:%22t%22,%22id@%22:%22%2FMoment%2FuserId%22,%22@column%22:%22id,name,head%22%7D,%22Comment%22:%7B%22momentId@%22:%22%2FMoment%2Fid%22,%22@column%22:%22id,momentId,content%22%7D%7D%7D)

⑤ 每一层都加当前用户名:
["User":{},
"[]":{
   "name@":"User/name", // 自定义关键词
   "Moment":{}
}](http://apijson.cn:8080/get/{"User":{},"[]":{"name@":"User%252Fname","Moment":{}}}) + 数组关键词,可自定义 | "key":Object,key为 "[]":{} 中 {} 内的关键词,Object 的类型由 key 指定

① "count":5,查询数量,0 表示最大值,默认值为 10,默认最大值为 100

② "page":1,查询页码,从 0 开始,默认值为 0,默认最大值为 100,一般和 count 一起用

③ "query":2,查询内容
0-对象,1-总数和分页详情,2-数据、总数和分页详情
总数关键词为 total,分页详情关键词为 info,
它们都和 query 同级,通过引用赋值得到自定义 key:value 键值对,不传则返回默认键值对,例如
"total@":"/[]/total", "info@":"/[]/info"
这里query及total仅为GET类型的请求提供方便,
一般可直接用HEAD类型的请求获取总数

④ "compat": true
处理最外层查询字段有特殊处理的情况下 "query":2 返回查询总数不准确的问题:如DISTINCT去重、Aggregate 函数等

⑤ "join":"&/Table0,\"join":{
   "&/Table0":{}, // 支持 ON 多个字段关联,
   "\      "key0":value0, // 其它ON条件
     "key2":value2,
     ...
     "@combine":"...", // 其它ON条件的组合方式
     "@column":"...", // 外层 SELECT
     "@group":"...", // 外层 GROUP BY
     "@having":"..." // 外层 HAVING
   }
}
多表连接方式:
"@" - APP JOIN
"\<" - LEFT JOIN
">" - RIGHT JOIN
"&" - INNER JOIN
"\|" - FULL JOIN
"!" - OUTER JOIN
"*" - CROSS JOIN
"^" - SIDE JOIN
"(" - ANTI JOIN
")" - FOREIGN JOIN
其中 @ APP JOIN 为应用层连表,会从已查出的主表里取得所有副表 key@ 关联的主表内的 refKey 作为一个数组 refKeys: [value0, value1...],然后把原来副表 count 次查询 key=$refKey 的 SQL 用 key IN($refKeys) 的方式合并为一条 SQL 来优化性能;
其它 JOIN 都是 SQL JOIN,具体功能和 MySQL,PostgreSQL 等数据库的 JOIN 一一对应
`"join":"`"MainTable":{},`
`"ViceTable":{"key@":"/MainTable/refKey"}`
会对应生成
`MainTable LEFT JOIN ViceTable`
`ON ViceTable.key=MainTable.refKey` AND 其它ON条件
除了 = 等价关联,也支持 ! 不等关联、\> \< \>= \<= 等比较关联和 $ ~ {} <> 等其它复杂关联方式

⑥ "otherKey":Object,自定义关键词,名称和以上系统关键词不一样,且原样返回上传的值 | ① 查询User数组,最多5个:
["count":5](http://apijson.cn:8080/get/{"[]":{"count":5,"User":{}}})
对应 SQL 是`LIMIT 5`

② 查询第3页的User数组,每页5个:
["count":5,
"page":3](http://apijson.cn:8080/get/{"[]":{"count":5,"page":3,"User":{}}})
对应 SQL 是`LIMIT 5 OFFSET 15`

③ 查询User数组和对应的User总数:
["[]":{
   "query":2,
   "User":{}
},
"total@":"/[]/total", // 可省略
"info@":"/[]/info" // 可省略](http://apijson.cn:8080/get/{"[]":{"query":2,"count":5,"User":{}},"total@":"%252F[]%252Ftotal","info@":"%252F[]%252Finfo"})
返回的数据中,总数及分页详情结构为:
"total":139, // 总数
"info":{ // 分页详情
   "total":139, // 总数
   "count":5, // 每页数量
   "page":0, // 当前页码
   "max":27, // 最大页码
   "more":true, // 是否还有更多
   "first":true, // 是否为首页
   "last":false // 是否为尾页
}

④查询User数组ID唯一情况下的User总数:
["[]":{
   "query":2,
   "compat":"true",
   "User":{
     "@column":"DISTINCT id"
   }
}](http://apijson.cn:8080/get/{"[]":{"query":2,"count":5,"User":{}}})
返回的数据和结构同上

⑤ Moment INNER JOIN User LEFT JOIN Comment:
["[]":{
   "join":"&/User/id@,\    "Moment":{
     "@group":"id" // 主副表不是一对一,要去除重复数据
   },
   "User":{
     "name~":"t",
     "id@":"/Moment/userId"
   },
   "Comment":{
     "momentId@":"/Moment/id"
   }
}](http://apijson.cn/api/?type=JSON&url=http://apijson.cn:8080/get&json=%7B%22%5B%5D%22:%7B%22count%22:5,%22join%22:%22%26%2FUser%2Fid@,%3C%2FComment%22,%22Moment%22:%7B%22@column%22:%22id,userId,content%22,%22@group%22:%22id%22%7D,%22User%22:%7B%22name~%22:%22t%22,%22id@%22:%22%2FMoment%2FuserId%22,%22@column%22:%22id,name,head%22%7D,%22Comment%22:%7B%22momentId@%22:%22%2FMoment%2Fid%22,%22@column%22:%22id,momentId,content%22%7D%7D%7D)

⑥ 每一层都加当前用户名:
["User":{},
"[]":{
   "name@":"User/name", // 自定义关键词
   "Moment":{}
}](http://apijson.cn:8080/get/{"User":{},"[]":{"name@":"User%252Fname","Moment":{}}}) 对象关键词,可自定义 | "@key":Object,@key 为 Table:{} 中 {} 内的关键词,Object 的类型由 @key 指定

① "@combine":"key0 \| (key1 & (key2 \| !key3))...",条件组合方式,最终按
(其它key条件 AND 连接) AND (key0条件 OR (key1条件 AND (key2条件 OR (NOT key3条件))))
这种方式连接,其中 "其它key" 是指与 @combine 在同一对象,且未被它声明的条件 key,默认都是 & 连接。注意不要缺少或多余任何一个空格。

② "@column":"column;function(arg)...",返回字段

③ "@order":"column0+,column1-...",排序方式

④ "@group":"column0,column1...",分组方式。如果 @column 里声明了 Table 的 id,则 id 也必须在 @group 中声明;其它情况下必须满足至少一个条件:
1.分组的 key 在 @column 里声明
2.Table 主键在 @group 中声明

⑤ "@having":"function0(...)?value0;function1(...)?value1;function2(...)?value2..." // OR 连接,或
"@having&":"function0(...)?value0;function1(...)?value1;function2(...)?value2..." // AND 连接,或
"@having":{
   "h0":"function0(...)?value0",
   "h1":function1(...)?value1",
   "h2":function2(...)?value2...",
   "@combine":"h0 & (h1 \| !h2)" // 任意组合,非必传
}
SQL 函数条件,一般和 @group 一起用,函数一般在 @column 里声明

⑥ "@schema":"sys",集合空间(数据库名/模式),非默认的值可通过它来指定,可以在最外层作为全局默认配置

⑦ "@database":"POSTGRESQL",数据库类型,非默认的值可通过它来指定,可以在最外层作为全局默认配置

⑧ "@datasource":"DRUID",跨数据源,非默认的值可通过它来指定,可以在最外层作为全局默认配置

⑨ "@json":"key0,key1...",转为 JSON 格式返回,符合 JSONObject 则转为 {...},符合 JSONArray 则转为 \[...]

⑩ "@role":"OWNER",来访角色,包括
UNKNOWN,LOGIN,CONTACT,CIRCLE,OWNER,ADMIN,
可以在最外层作为全局默认配置,
可自定义其它角色并重写 Verifier.verify 等相关方法来自定义校验

⑪ "@explain":true,性能分析,可以在最外层作为全局默认配置

⑫ "@raw":"key0,key1...",其中 key0, key1 都对应有键值对
"key0":"SQL片段或SQL片段的别名",
"key1":"SQL片段或SQL片段的别名"
自定义原始SQL片段,可扩展嵌套SQL函数等复杂语句,必须是后端已配置的,只有其它功能符都做不到才考虑,谨慎使用,注意防 SQL 注入

⑬ "@null":"key1,key2...",空值键值对,自动插入 key1:null, key2:null ... 并作为有效键值对执行,作为条件时对应 SQL 是 `WHERE tag IS NULL`,作为值时对应 SQL 是 `SET tag = NULL`

⑭ "@otherKey":Object,自定义关键词,名称和以上系统关键词不一样,且原样返回上传的值 | ① 搜索 name 或 tag 任何一个字段包含字符 a 的 User 列表:
["name~":"a",
"tag~":"a",
"@combine":"name~ \| tag~"](http://apijson.cn:8080/get/{"User[]":{"count":10,"User":{"@column":"id,name,tag","name~":"a","tag~":"a","@combine":"name~%20%7C%20tag~"}}})
对应SQL是`name REGEXP 'a' OR tag REGEXP 'a'`

② 只查询 id,sex,name 这几列并且请求结果也按照这个顺序:
["@column":"id,sex,name"](http://apijson.cn:8080/get/{"User":{"@column":"id,sex,name","id":38710}})
对应 SQL 是`SELECT id,sex,name`

③ 查询按 name 降序、id 默认顺序 排序的 User 数组:
["@order":"name-,id"](http://apijson.cn:8080/get/{"[]":{"count":10,"User":{"@column":"name,id","@order":"name-,id"}}})
对应 SQL 是`ORDER BY name DESC,id`

④ 查询按 userId 分组的 Moment 数组:
["@group":"userId,id"](http://apijson.cn:8080/get/{"[]":{"count":10,"Moment":%7B"@column":"userId,id","@group":"userId,id"}}})
对应 SQL 是`GROUP BY userId,id`

⑤ 查询 按 userId 分组、id 最大值>=100 的 Moment 数组:
["@column":"userId;max(id)",
"@group":"userId",
"@having":"max(id)>=100"](http://apijson.cn:8080/get/{"[]":{"count":10,"Moment":{"@column":"userId%253Bmax(id)","@group":"userId","@having":"max(id)>=100"}}})
对应 SQL 是`SELECT userId,max(id) ... GROUP BY userId HAVING max(id)>=100`
还可以指定函数返回名:
["@column":"userId;max(id):maxId",
"@group":"userId",
"@having":"(maxId)>=100"](http://apijson.cn:8080/get/{"[]":{"count":10,"Moment":{"@column":"userId%253Bmax(id):maxId","@group":"userId","@having":"(maxId)>=100"}}})
对应 SQL 是`SELECT userId,max(id) AS maxId ... GROUP BY userId HAVING (maxId)>=100`

⑥ 查询 sys 内的 User 表:
["@schema":"sys"](http://apijson.cn:8080/get/{"User":{"@schema":"sys"}})
对应 SQL 是`FROM sys.User`

⑦ 查询 PostgreSQL 数据库的 User 表:
["@database":"POSTGRESQL"](http://apijson.cn:8080/get/{"User":{"@database":"POSTGRESQL","@explain":true}})

⑧ 使用 Druid 连接池查询 User 表:
["@datasource":"DRUID"](http://apijson.cn:8080/get/{"User":{"@datasource":"DRUID"}})

⑨ 将 VARCHAR 字符串字段 get 转为 JSONArray 返回:
["@json":"get"](http://apijson.cn:8080/get/{"Access":{"@json":"get"}})

⑩ 查询当前用户的动态:
["@role":"OWNER"](http://apijson.cn:8080/get/{"[]":{"Moment":{"@role":"OWNER"}}})

⑪ 开启性能分析:
["@explain":true](http://apijson.cn:8080/get/{"[]":{"Moment":{"@explain":true}}})
对应 SQL 是`EXPLAIN`

⑫ 统计最近一周偶数 userId 的数量
["@column":"date;left(date,10):day;sum(if(userId%2=0,1,0))",
"@group":"day",
"@having":"to_days(now())-to_days(\`date\`)<=7",
"@raw":"@column,@having"](http://apijson.cn:8080/get/{"[]":{"Moment":{"@column":"date%3bleft(date,10):day%3bsum(if(userId%252=0,1,0))","@group":"day","@having":"to_days(now())-to_days(\`date\`)<=7","@raw":"@column,@having"}}})
对应 SQL 是``SELECT date, left(date,10) AS day, sum(if(userId%2=0,1,0)) ... GROUP BY day HAVING to_days(now())-to_days(`date`)<=7``

⑬ 把用户的标签设置为空
["@null":"tag"](http://apijson.cn/api/?type=JSON&url=http://apijson.cn:8080/put/User&json={%22id%22:82001,%22@null%22:%22tag%22,%22@explain%22:true})

⑭ 从pictureList 获取第 0 张图片:
["@position":0, // 自定义关键词
"firstPicture()":"getFromArray(pictureList,@position)"](http://apijson.cn:8080/get/{"User":{"id":38710,"@position":0,"firstPicture()":"getFromArray(pictureList,@position)"}}) 全局关键词 | 为最外层对象 {} 内的关键词。其中 @database,@schema, @datasource, @role, @explain 基本同对象关键词,见上方说明,区别是全局关键词会每个表对象中没有时自动放入,作为默认值。

① "tag":"Table",后面的 tag 是非 GET、HEAD 请求中匹配请求的 JSON 结构的标识,一般是要查询的 Table 的名称或该名称对应的数组 Table[] 或 Table:[],由后端 Request 表中指定。

② "version":1,接口版本,version 不传、为 null 或 <=0 都会使用最高版本,传了其它有效值则会使用最接近它的最低版本,由后端 Request 表中指定。

③ "format":true,格式化返回 Response JSON 的 key,一般是将 TableName 转为 tableName, TableName[] 转为 tableNameList, Table:alias 转为 alias, TableName-key[] 转为 tableNameKeyList 等小驼峰格式。 | ① 查隐私信息:
[{"tag":"Privacy","Privacy":{"id":82001}}](http://apijson.cn/api?url=http%3A%2F%2Fapijson.cn%3A8080%2Fgets&type=JSON&json={%22tag%22:%22Privacy%22,%22Privacy%22:{%22id%22:82001}})

② 使用第 1 版接口查隐私信息:
[{"version":1,"tag":"Privacy","Privacy":{"id":82001}}](http://apijson.cn/api?url=http%3A%2F%2Fapijson.cn%3A8080%2Fgets&type=JSON&json={%22version%22:1,%22tag%22:%22Privacy%22,%22Privacy%22:{%22id%22:82001}})

③ 格式化朋友圈接口返回 JSON 中的 key:
[{
   "format":true,
   "[]":{
     "page":0,
     "count":3,
     "Moment":{},
     "User":{
       "id@":"/Moment/userId"
     },
     "Comment[]":{
       "count":3,
       "Comment":{
         "momentId@":"[]/Moment/id"
       }
     }
   }
}](http://apijson.cn:8080/get/{"format":true,"[]":{"page":0,"count":3,"Moment":{},"User":{"id@":"%252FMoment%252FuserId"},"Comment[]":{"count":3,"Comment":{"momentId@":"[]%252FMoment%252Fid"}}}})
diff --git a/LICENSE b/LICENSE index 1a71560c8..9743dd5aa 100644 --- a/LICENSE +++ b/LICENSE @@ -1,18 +1,18 @@ Tencent is pleased to support the open source community by making APIJSON available. -Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +Copyright (C) 2020 Tencent. All rights reserved. APIJSON is licensed under the Apache License Version 2.0. A copy of the Apache License Version 2.0 is included in this file. +The copyright notice pertaining to the Tencent code in this repo was previously in the name of “THL A29 Limited.” +That entity has now been de-registered. +You should treat all previously distributed copies of the code as if the copyright notice was in the name of “Tencent.” Other dependencies and licenses: Open Source Software Licensed under the Apache License Version 2.0: -------------------------------------------------------------------- -1. fastjson -Copyright 1999-2019 Alibaba Group Holding Ltd. - Terms of Apache License Version 2.0 diff --git a/README-English.md b/README-English.md index beea69d6c..ccafb9850 100644 --- a/README-English.md +++ b/README-English.md @@ -1,5 +1,5 @@ Tencent is pleased to support the open source community by making APIJSON available.
-Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
+Copyright (C) 2020 Tencent. All rights reserved.
This source code is licensed under the Apache License Version 2.0

@@ -14,6 +14,7 @@ This source code is licensed under the Apache License Version 2.0
 Document   Video   Test  + Ask AI

diff --git a/README-extend.md b/README-extend.md index 09301ddca..98b60ac2c 100644 --- a/README-extend.md +++ b/README-extend.md @@ -6,13 +6,23 @@ https://github.com/Tencent/APIJSON/issues/468 #### 使用说明 -json支持多种方式定义method +json 支持多种方式定义 method -第一种: +#### 第一种: - "@post","@put","@delete","@head","@get","@gets","@head","@heads" +"@post","@put","@delete","@head","@get","@gets","@head","@heads" -"@post": ["Moment","Comment[]"] , 值为数组格式, 每个value = key +"@post": "Moment,Comment[]" , 值为 String 或 JSONObject 格式, 为 String 时每个 value = key,为 JSONObject 时: +```json +"@post": { + "Moment": "Moment", // 只指定 tag,为 "" 则和 key 一致 + "Comment[]": { // 同时指定多个全局关键词 + "tag": "Comment[]", + "version": 2 + // 其它全局关键词 + } +} +``` 需要保证每个key唯一, 唯一判断标准: @@ -24,7 +34,7 @@ key= Moment[] ``` { - "@post": ["Moment","Comment:cArray[]","User:u"], // 分发到 POST 请求对应的解析处理 + "@post": "Moment,Comment:cArray[],User:u", // 分发到 POST 请求对应的解析处理 "Moment": { // TODO 其它字段 }, @@ -33,7 +43,7 @@ key= Moment[] // TODO 其它字段 } ], - "@get": ["User"], // 分发到 GET 请求对应的解析处理 + "@get": "User", // 分发到 GET 请求对应的解析处理 "User:u": { // TODO 其它字段 }, @@ -46,19 +56,19 @@ key= Moment[] ``` -第二种: +#### 第二种: @Deprecated 即将弃用,请使用第一种 对象内定义"@method": "GET", value大写 ``` { - "sql@": { + "sql@": { "@method": "GET", "with": true, "from": "Sys_role", "Sys_role": { - "@column": "id", - "role_name": "角色1" + "@column": "id", + "role_name": "角色1" } }, "Sys_user_role:sur[]": { @@ -152,14 +162,14 @@ Comment:cArray[] 并将method 添加到 json对象属性中. -``` +```json "Sys_role": { - "@method": "PUT", - "id": "6aedce0d-2a29-4fbe-aeed-0ba935ca6b41", - "id{}@": "sql", - "role_code": "code-subrange-4", - "role_name": "角色-subrange-4" - } + "@method": "PUT", + "id": "6aedce0d-2a29-4fbe-aeed-0ba935ca6b41", + "id{}@": "sql", + "role_code": "code-subrange-4", + "role_name": "角色-subrange-4" +} ``` 2、对象解析 @@ -741,6 +751,7 @@ AbstractVerifier.IS_UPDATE_MUST_HAVE_ID_CONDITION = true; // true: 必须有 ``` // 条件删除 +```json { "User:del": { "username": "test3" @@ -748,8 +759,10 @@ AbstractVerifier.IS_UPDATE_MUST_HAVE_ID_CONDITION = true; // true: 必须有 "tag": "User", "explain": true } +``` // 引用id{}@删除 +```json { "sql@": { "@method": "GET", @@ -766,8 +779,11 @@ AbstractVerifier.IS_UPDATE_MUST_HAVE_ID_CONDITION = true; // true: 必须有 }, "explan": true } +``` + // 子查询条件删除 http://localhost:8675/lowCodePlatform/forms/api/delete +```json { "sql@": { "@method": "GET", @@ -783,8 +799,10 @@ http://localhost:8675/lowCodePlatform/forms/api/delete }, "explan": true } +``` 第二种写法: +```json { "@get": ["sql@"], "sql@": { @@ -800,23 +818,21 @@ http://localhost:8675/lowCodePlatform/forms/api/delete }, "explan": true } - - ``` 开启id删除, 删除失败: -``` +```json { - "@get": ["sql@"], - "sql@": { + "@get": ["sql@"], + "sql@": { "with": true, "from": "User", "User": { - "@column": "username", - "username": "test4" + "@column": "username", + "username": "test4" } }, "User": { @@ -830,7 +846,7 @@ http://localhost:8675/lowCodePlatform/forms/api/delete 开启id删除、id引用 删除成功 -``` +```json { "sql@": { "@method": "GET", @@ -848,19 +864,20 @@ http://localhost:8675/lowCodePlatform/forms/api/delete "explan": true } ``` + ![image](https://user-images.githubusercontent.com/12228225/204080050-e6f04fe6-319e-45b7-b1b2-bf4cda4ab2db.png) PUT 子查询 修改 -``` +```json { "sql@": { - "@method": "GET", + "@method": "GET", "with": true, "from": "Sys_role_permission", "Sys_role_permission": { - "@column": "role_id", - "id{}": ["ba2634f8-0bdc-4b50-9c5e-47786b1536ef"] + "@column": "role_id", + "id{}": ["ba2634f8-0bdc-4b50-9c5e-47786b1536ef"] } }, "Sys_role": { @@ -892,15 +909,15 @@ WHERE ( (`username` IN (SELECT * FROM (SELECT `username` FROM `housekeeping`.`Us ### must、refuses判断、delete、PUT支持 ref -``` +```json { - "sql@": { - "@method": "GET", + "sql@": { + "@method": "GET", "with": true, "from": "Sys_role_permission", "Sys_role_permission": { - "@column": "id", - "role_id{}": ["94f79f0b-331b-4cc5-bfc0-ebfc47d00f13"] + "@column": "id", + "role_id{}": ["94f79f0b-331b-4cc5-bfc0-ebfc47d00f13"] } }, "Sys_role_permission": { diff --git a/README.md b/README.md index 67610d168..99d0f7272 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ Tencent is pleased to support the open source community by making APIJSON available.
-Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
+Copyright (C) 2020 Tencent. All rights reserved.
This source code is licensed under the Apache License Version 2.0

@@ -13,6 +13,7 @@ This source code is licensed under the Apache License Version 2.0
通用文档 视频教程 测试用例 + AI 问答

@@ -191,7 +192,7 @@ https://github.com/Tencent/APIJSON/wiki * **开发提速很大** (CRUD 零代码热更新全自动,APIJSONBoot 对比 SSM、SSH 等保守估计可提速 20 倍以上) * **腾讯官方开源** (使用 GitHub、Gitee、工蜂 等平台的官方账号开源,微信公众号、腾讯云+社区 等官方公告) * **社区影响力大** (GitHub 17K+ Star 在 400W Java 项目排名前 100,远超 FLAG, BAT 等国内外绝大部分开源项目) -* **各项荣誉成就** (腾讯内外 5 个奖项、腾讯开源前六、腾讯后端 Star 第一、Trending 日周月榜大满贯 等) +* **各项荣誉成就** (腾讯内外 5 个奖项、腾讯开源前五、腾讯后端 Star 第一、Trending 日周月榜大满贯 等) * **多样用户案例** (腾讯内有互娱、音乐、微信、云与智慧,外部有华为、华能、百度、快手、中兴、圆通、传音等) * **适用场景广泛** (社交聊天、阅读资讯、影音娱乐、办公学习 等各种 App、网站、小程序、公众号 等非金融类项目) * **周边生态丰富** (Android, iOS, Web 等各种 Demo、继承 JSON 的海量生态、零代码 接口测试 和 单元测试 工具等) @@ -558,7 +559,7 @@ Issue/问卷 一般解答顺序:贡献者 > 帮助他人的用户 > 提供任 [3步创建APIJSON后端新表及配置](https://my.oschina.net/tommylemon/blog/889074) -[APIJSON对接分布式HTAP数据库TiDB](https://asktug.com/t/htap-tidb/395) +[APIJSON对接分布式HTAP数据库TiDB](https://my.oschina.net/tommylemon/blog/3081913) [APIJSON教程(一):上手apijson项目,学习apijson语法,并实现持久层配置](https://zhuanlan.zhihu.com/p/375681893) @@ -571,13 +572,7 @@ Issue/问卷 一般解答顺序:贡献者 > 帮助他人的用户 > 提供任 [学习自动化接口APIJSON](https://www.jianshu.com/p/981a2a630c7b) [APIJSON 接口调试实践](https://github.com/Tencent/APIJSON/issues/189) - -[关于APIJSON远程函数](https://mp.weixin.qq.com/s?__biz=Mzg3NTc1NDUyNA==&mid=2247483950&idx=1&sn=b11e70bdf083c55d72238e107449ae2e&chksm=cf3de75df84a6e4b3a4acd0846531b0bd12bc90379523fbaf6b4f900fc3cdc1b1ce3eff97fd9&scene=178&cur_album_id=2548737392338354178#rd) - -[APIJSON新增方法实例](https://cloud.tencent.com/developer/article/2098890) - -[APIJSON-APIJSON的那些事儿](https://cloud.tencent.com/developer/article/2098888) - + [APIJSON-零代码接口和文档 JSON 协议 与 ORM 库](https://cloud.tencent.com/developer/article/2077042) [APIJSON使用例子总结](https://blog.csdn.net/weixin_41077841/article/details/110518007) @@ -588,8 +583,6 @@ Issue/问卷 一般解答顺序:贡献者 > 帮助他人的用户 > 提供任 [APIJSON复杂业务深入实践(类似12306订票系统)](https://blog.csdn.net/aa330233789/article/details/105309571) -[全国行政区划数据抓取与处理](https://www.xlongwei.com/detail/21032616) - [新手搭建 APIJSON 项目指北](https://github.com/jerrylususu/apijson_todo_demo/blob/master/FULLTEXT.md) [使用APIJSON写低代码Crud接口](https://blog.csdn.net/weixin_42375862/article/details/121654264) @@ -622,6 +615,20 @@ Issue/问卷 一般解答顺序:贡献者 > 帮助他人的用户 > 提供任 [wend看源码-ORM-APIJSON](https://itwend.blog.csdn.net/article/details/143980281) +[APIJSON – The No-Code API Revolution That Puts Developers in the Fast Lane](https://medevel.com/apijson) + +[APIJSON:17.4k Star!腾讯开源的零代码接口与文档协议及ORM库](https://mp.weixin.qq.com/s/gr84DmWKs4O6lcoT-iaV5w) + +[APIJSON腾讯开源的后端开发神器!!!](https://cloud.tencent.com/developer/article/2372220) + +[apijson 快速上手](https://blog.csdn.net/qq_16381291/article/details/147110737) + +[APIJSON快速入门-零后端代码,接口所见即所得](https://www.toutiao.com/article/7503844050689376783) + +[腾讯开源!零代码,全自动万能API接口](https://mp.weixin.qq.com/s/WWndAa68BqBfflWgL5592A) + +[APIJSON项目实战教程:零代码实现高效JSON接口开发](https://blog.csdn.net/gitblog_00682/article/details/148375065) + ### 生态项目 [APIJSON-Demo](https://github.com/APIJSON/APIJSON-Demo) APIJSON 各种语言、各种框架 的 使用示例项目、上手文档、测试数据 SQL 文件 等 @@ -633,6 +640,10 @@ Issue/问卷 一般解答顺序:贡献者 > 帮助他人的用户 > 提供任 [apijson-column](https://github.com/APIJSON/apijson-column) APIJSON 的字段插件,支持 字段名映射 和 !key 反选字段 +[apijson-gson](https://github.com/APIJSON/apijson-gson) APIJSON 的 gson 插件,简化使用 + +[apijson-fastjson2](https://github.com/APIJSON/apijson-fastjson2) APIJSON 的 fastjson2 插件,简化使用 + [apijson-milvus](https://github.com/APIJSON/apijson-milvus) APIJSON 的 Milvus AI 向量数据库插件 [apijson-influxdb](https://github.com/APIJSON/apijson-influxdb) APIJSON 的 InfluxDB 物联网时序数据库插件 @@ -641,13 +652,15 @@ Issue/问卷 一般解答顺序:贡献者 > 帮助他人的用户 > 提供任 [apijson-cassandra](https://github.com/APIJSON/apijson-cassandra) APIJSON 的 Cassandra NoSQL 数据库插件 -[APIAuto](https://github.com/TommyLemon/APIAuto) 敏捷开发最强大易用的接口工具,机器学习零代码测试、生成代码与静态检查、生成文档与光标悬浮注释 +[APIAuto](https://github.com/TommyLemon/APIAuto) ☔ 敏捷开发最强大易用的接口工具,零代码测试与 AI 问答、生成代码与静态检查、生成文档与光标悬浮注释,腾讯、SHEIN、传音 等使用 + +[CVAuto](https://github.com/TommyLemon/CVAuto) 👁 零代码零标注 CV AI 自动化测试平台 🚀 免除大量人工画框和打标签等,直接快速测试 CV 计算机视觉 AI 图像识别算法 [UnitAuto](https://github.com/TommyLemon/UnitAuto) 最先进、最省事、ROI 最高的单元测试,机器学习 零代码、全方位、自动化 测试 方法/函数,用户包含腾讯、快手、某 500 强巨头等 -[SQLAuto](https://github.com/TommyLemon/SQLAuto) 智能零代码自动化测试 SQL 语句执行结果的数据库工具,一键批量生成参数组合、快速构造大量测试数据 +[SQLAuto](https://github.com/TommyLemon/SQLAuto) 智能零代码自动化测试 SQL 数据库工具,任意增删改查、任意 SQL 模板变量、一键批量生成参数组合、快速构造大量测试数据 -[UIGO](https://github.com/TommyLemon/UIGO) 📱 零代码快准稳 UI 智能录制回放平台 🚀 自动兼容任意宽高比分辨率屏幕、自动精准等待网络请求,录制回放快、准、稳! +[UIGO](https://github.com/TommyLemon/UIGO) 📱 零代码快准稳 UI 智能录制回放平台 🚀 3 像素内自动精准定位,2 毫秒内自动精准等待,用户包含腾讯,微信团队邀请分享 [apijson-doc](https://github.com/vincentCheng/apijson-doc) APIJSON 官方文档,提供排版清晰、搜索方便的文档内容展示,包括设计规范、图文教程等 @@ -693,7 +706,7 @@ Issue/问卷 一般解答顺序:贡献者 > 帮助他人的用户 > 提供任 [apijson-examples](https://gitee.com/drone/apijson-examples) APIJSON 的前端、业务后端、管理后端 Demo -[apijson-ruoyi](https://gitee.com/yxiedd/apijson-ruoyi) APIJSON 和 RuoYi 框架整合,实现零代码生成页面模板接口,在线维护 APIJSON 数据库配置等 +[apijson-ruoyi](https://github.com/daodol/apijson-ruoyi) APIJSON 和 RuoYi 框架整合,实现零代码生成页面模板接口,在线维护 APIJSON 数据库配置等 [light4j](https://github.com/xlongwei/light4j) 整合 APIJSON 和微服务框架 light-4j 的 Demo,同时接入了 Redis @@ -732,7 +745,9 @@ Issue/问卷 一般解答顺序:贡献者 > 帮助他人的用户 > 提供任 [review_plan](https://gitee.com/PPXcodeTry/review_plan) 复习提醒Web版(Java技术练习项目) [apijson-nutz](https://github.com/vincent109/apijson-nutz) APIJSON + Nutz 框架 + NutzBoot 的 Demo - + +[apijson-spring-boot](https://gitee.com/yunjiao-source/apijson-spring-boot) Springboot3 for APIJSON,用 YAML 简化代码配置 + 感谢热心的作者们的贡献,点 ⭐Star 支持下他们吧~