From d17907a9cbac966dbd9ca9a18575cdc4ab309547 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Thu, 25 May 2023 20:54:49 +0800 Subject: [PATCH 01/54] AutoBeanDeserializer --- .../qdbp/json/JsonServiceForFastjson.java | 20 +- .../json/fastjson/AutoBeanDeserializer.java | 349 ++++++++++++++++++ .../json/fastjson/MapFillToBeanHandler.java | 43 +++ 3 files changed, 393 insertions(+), 19 deletions(-) create mode 100644 json/src/main/java/com/gitee/qdbp/json/fastjson/AutoBeanDeserializer.java create mode 100644 json/src/main/java/com/gitee/qdbp/json/fastjson/MapFillToBeanHandler.java diff --git a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForFastjson.java b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForFastjson.java index 0473bf0..a178ed5 100644 --- a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForFastjson.java +++ b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForFastjson.java @@ -1,7 +1,6 @@ package com.gitee.qdbp.json; import java.lang.reflect.Array; -import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -20,7 +19,6 @@ import com.alibaba.fastjson.parser.Feature; import com.alibaba.fastjson.parser.JSONLexer; import com.alibaba.fastjson.parser.JSONToken; import com.alibaba.fastjson.parser.ParserConfig; -import com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer; import com.alibaba.fastjson.serializer.DoubleSerializer; import com.alibaba.fastjson.serializer.JSONSerializable; import com.alibaba.fastjson.serializer.JSONSerializer; @@ -33,6 +31,7 @@ import com.alibaba.fastjson.serializer.SimpleDateFormatSerializer; import com.alibaba.fastjson.util.TypeUtils; import com.gitee.qdbp.able.exception.ServiceException; import com.gitee.qdbp.able.result.ResultCode; +import com.gitee.qdbp.json.fastjson.MapFillToBeanHandler; import com.gitee.qdbp.tools.utils.MapTools; import com.gitee.qdbp.tools.utils.ReflectTools; import com.gitee.qdbp.tools.utils.VerifyTools; @@ -551,21 +550,4 @@ public class JsonServiceForFastjson extends JsonServiceForBase { supportNonStringKeyAsString = existField(Feature.class, "NonStringKeyAsString"); serializerHasGetJsonType = existField(JavaBeanSerializer.class, "getJSONType"); } - - private static class MapFillToBeanHandler extends JavaBeanDeserializer { - private final Object bean; - - public MapFillToBeanHandler(Object bean, ParserConfig config) { - super(config, bean.getClass()); - this.bean = bean; - } - - @Override - public Object createInstance(DefaultJSONParser parser, Type type) { - // 调用此方法时: JavaBeanDeserializer.createInstance(Map map, ParserConfig config) - // 会调用本方法: createInstance(DefaultJSONParser parser, Type type) - // 这里直接返回构造方法中传入的bean, 达到将map赋值给已知对象的目的 - return bean; - } - } } diff --git a/json/src/main/java/com/gitee/qdbp/json/fastjson/AutoBeanDeserializer.java b/json/src/main/java/com/gitee/qdbp/json/fastjson/AutoBeanDeserializer.java new file mode 100644 index 0000000..c0c8833 --- /dev/null +++ b/json/src/main/java/com/gitee/qdbp/json/fastjson/AutoBeanDeserializer.java @@ -0,0 +1,349 @@ +package com.gitee.qdbp.json.fastjson; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONException; +import com.alibaba.fastjson.JSONValidator; +import com.alibaba.fastjson.annotation.JSONField; +import com.alibaba.fastjson.parser.DefaultJSONParser; +import com.alibaba.fastjson.parser.ParserConfig; +import com.alibaba.fastjson.parser.deserializer.FieldDeserializer; +import com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer; +import com.alibaba.fastjson.parser.deserializer.Jdk8DateCodec; +import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer; +import com.alibaba.fastjson.util.FieldInfo; +import com.alibaba.fastjson.util.JavaBeanInfo; +import com.alibaba.fastjson.util.TypeUtils; +import com.gitee.qdbp.tools.utils.MapTools; + +/** + * 反序列化处理类优化, 解决自定义的JavaBeanDeserializer在map转对象时不生效的问题 (V1.2.83)
+ * 重写JavaBeanDeserializer.createInstance(Map, ParserConfig), 增加了deserializeFieldValue处理逻辑 + * + * @author zhaohuihua + * @version 20230521 + */ +public class AutoBeanDeserializer extends JavaBeanDeserializer { + + public AutoBeanDeserializer(ParserConfig config, Class clazz) { + super(config, clazz, clazz); + } + + public AutoBeanDeserializer(ParserConfig config, Class clazz, Type type){ + super(config, clazz, type); + } + + public AutoBeanDeserializer(ParserConfig config, JavaBeanInfo beanInfo){ + super(config, beanInfo); + } + + protected static boolean deserializeFieldValue(Object object, Object fieldValue, FieldDeserializer fieldDeserializer, + ParserConfig config) throws IllegalAccessException, InvocationTargetException { + // 增加判断, 如果值是map, 调用createInstance(Map map, ParserConfig config) + // 从JavaBeanDeserializer.createInstance(Map, ParserConfig), 增加了这一段逻辑 + // 这样自定义的JavaBeanDeserializer在map转对象时才能生效; 如果不加, map会转换为字符串再调DefaultJSONParser处理, 就不会生效 + FieldInfo fieldInfo = fieldDeserializer.fieldInfo; + Field field = fieldDeserializer.fieldInfo.field; + Class fieldType = field.getType(); + if (fieldValue instanceof Map) { + ObjectDeserializer deserializer = config.getDeserializer(fieldInfo); + if (deserializer instanceof JavaBeanDeserializer) { + JavaBeanDeserializer fieldBeanDeserializer = (JavaBeanDeserializer) deserializer; + Map valueMaps = MapTools.toJsonMap((Map) fieldValue); + Object fieldBean = fieldBeanDeserializer.createInstance(valueMaps, config); + fieldDeserializer.setValue(object, fieldBean); + return true; + } + } else if (fieldValue instanceof Collection && Collection.class.isAssignableFrom(fieldType)) { + Collection values = (Collection) fieldValue; + boolean isAllMapItems = true; + for (Object o : values) { + if (o != null && !(o instanceof Map)) { + isAllMapItems = false; + break; + } + } + if (isAllMapItems) { + Class ctualClass = getFirstActualClass(field); + ObjectDeserializer deserializer = config.getDeserializer(ctualClass); + if (deserializer instanceof JavaBeanDeserializer) { + JavaBeanDeserializer fieldBeanDeserializer = (JavaBeanDeserializer) deserializer; + List list = new ArrayList<>(); + for (Object o : values) { + if (o == null) { + list.add(null); + } else { + Map valueMaps = MapTools.toJsonMap((Map) o); + Object fieldBean = fieldBeanDeserializer.createInstance(valueMaps, config); + list.add(fieldBean); + } + } + Object fieldBean = TypeUtils.cast(list, fieldType, config); + fieldDeserializer.setValue(object, fieldBean); + return true; + } + } + } + return false; + } + + private static Class getFirstActualClass(Field field) { + Type genericType = field.getGenericType(); + if (genericType instanceof ParameterizedType) { + ParameterizedType parameterizedType = (ParameterizedType) genericType; + Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); + if (actualTypeArguments.length == 1) { + return (Class) actualTypeArguments[0]; + } + } + return null; + } + + @Override + public Object createInstance(Map map, ParserConfig config) + throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + Object object = null; + + if (beanInfo.creatorConstructor == null && beanInfo.factoryMethod == null) { + object = createInstance(null, clazz); + + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + + FieldDeserializer fieldDeser = smartMatch(key); + if (fieldDeser == null) { + continue; + } + + final FieldInfo fieldInfo = fieldDeser.fieldInfo; + Field field = fieldDeser.fieldInfo.field; + Type paramType = fieldInfo.fieldType; + + // 增加判断, 如果值是Map或List, 调用createInstance(Map map, ParserConfig config) + if (deserializeFieldValue(object, value, fieldDeser, config)) { + continue; + } + + Class fieldClass = fieldInfo.fieldClass; + JSONField fieldAnnotation = fieldInfo.getAnnotation(); + + if (fieldInfo.declaringClass != null + && ((!fieldClass.isInstance(value)) + || (fieldAnnotation != null && fieldAnnotation.deserializeUsing() != Void.class)) + ) { + String input; + if (value instanceof String && JSONValidator.from(((String) value)).validate()) { + input = (String) value; + } else { + input = JSON.toJSONString(value); + } + + DefaultJSONParser parser = new DefaultJSONParser(input); + fieldDeser.parseField(parser, object, paramType, null); + continue; + } + + if (field != null && fieldInfo.method == null) { + Class fieldType = field.getType(); + if (fieldType == boolean.class) { + if (value == Boolean.FALSE) { + field.setBoolean(object, false); + continue; + } + + if (value == Boolean.TRUE) { + field.setBoolean(object, true); + continue; + } + } else if (fieldType == int.class) { + if (value instanceof Number) { + field.setInt(object, ((Number) value).intValue()); + continue; + } + } else if (fieldType == long.class) { + if (value instanceof Number) { + field.setLong(object, ((Number) value).longValue()); + continue; + } + } else if (fieldType == float.class) { + if (value instanceof Number) { + field.setFloat(object, ((Number) value).floatValue()); + continue; + } else if (value instanceof String) { + String strVal = (String) value; + float floatValue; + if (strVal.length() <= 10) { + floatValue = TypeUtils.parseFloat(strVal); + } else { + floatValue = Float.parseFloat(strVal); + } + + field.setFloat(object, floatValue); + continue; + } + } else if (fieldType == double.class) { + if (value instanceof Number) { + field.setDouble(object, ((Number) value).doubleValue()); + continue; + } else if (value instanceof String) { + String strVal = (String) value; + double doubleValue; + if (strVal.length() <= 10) { + doubleValue = TypeUtils.parseDouble(strVal); + } else { + doubleValue = Double.parseDouble(strVal); + } + + field.setDouble(object, doubleValue); + continue; + } + } else if (value != null && paramType == value.getClass()) { + field.set(object, value); + continue; + } + } + + String format = fieldInfo.format; + if (format != null && paramType == Date.class) { + value = TypeUtils.castToDate(value, format); + } else if (format != null && (paramType instanceof Class) + && (((Class) paramType).getName().equals("java.time.LocalDateTime"))) { + value = Jdk8DateCodec.castToLocalDateTime(value, format); + } else { + if (paramType instanceof ParameterizedType) { + value = TypeUtils.cast(value, (ParameterizedType) paramType, config); + } else { + value = TypeUtils.cast(value, paramType, config); + } + } + + fieldDeser.setValue(object, value); + } + + if (beanInfo.buildMethod != null) { + Object builtObj; + try { + builtObj = beanInfo.buildMethod.invoke(object); + } catch (Exception e) { + throw new JSONException("build object error", e); + } + + return builtObj; + } + + return object; + } + + + FieldInfo[] fieldInfoList = beanInfo.fields; + int size = fieldInfoList.length; + Object[] params = new Object[size]; + Map missFields = null; + for (int i = 0; i < size; ++i) { + FieldInfo fieldInfo = fieldInfoList[i]; + Object param = map.get(fieldInfo.name); + + if (param == null) { + Class fieldClass = fieldInfo.fieldClass; + if (fieldClass == int.class) { + param = 0; + } else if (fieldClass == long.class) { + param = 0L; + } else if (fieldClass == short.class) { + param = (short) 0; + } else if (fieldClass == byte.class) { + param = (byte) 0; + } else if (fieldClass == float.class) { + param = (float) 0; + } else if (fieldClass == double.class) { + param = (double) 0; + } else if (fieldClass == char.class) { + param = '0'; + } else if (fieldClass == boolean.class) { + param = false; + } + if (missFields == null) { + missFields = new HashMap(); + } + missFields.put(fieldInfo.name, i); + } + params[i] = param; + } + + if (missFields != null) { + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + + FieldDeserializer fieldDeser = smartMatch(key); + if (fieldDeser != null) { + Integer index = missFields.get(fieldDeser.fieldInfo.name); + if (index != null) { + params[index] = value; + } + } + } + } + + if (beanInfo.creatorConstructor != null) { + boolean hasNull = false; + if (beanInfo.kotlin) { + for (int i = 0; i < params.length; i++) { + Object param = params[i]; + if (param == null) { + if (i < beanInfo.fields.length) { + FieldInfo fieldInfo = beanInfo.fields[i]; + if (fieldInfo.fieldClass == String.class) { + hasNull = true; + } + } + } else if (param.getClass() != beanInfo.fields[i].fieldClass){ + params[i] = TypeUtils.cast(param, beanInfo.fields[i].fieldClass, config); + } + } + } + + if (hasNull && beanInfo.kotlinDefaultConstructor != null) { + try { + object = beanInfo.kotlinDefaultConstructor.newInstance(); + + for (int i = 0; i < params.length; i++) { + final Object param = params[i]; + if (param != null && i < beanInfo.fields.length) { + FieldInfo fieldInfo = beanInfo.fields[i]; + fieldInfo.set(object, param); + } + } + } catch (Exception e) { + throw new JSONException("create instance error, " + + beanInfo.creatorConstructor.toGenericString(), e); + } + } else { + try { + object = beanInfo.creatorConstructor.newInstance(params); + } catch (Exception e) { + throw new JSONException("create instance error, " + + beanInfo.creatorConstructor.toGenericString(), e); + } + } + } else if (beanInfo.factoryMethod != null) { + try { + object = beanInfo.factoryMethod.invoke(null, params); + } catch (Exception e) { + throw new JSONException("create factory method error, " + beanInfo.factoryMethod.toString(), e); + } + } + + return object; + } +} diff --git a/json/src/main/java/com/gitee/qdbp/json/fastjson/MapFillToBeanHandler.java b/json/src/main/java/com/gitee/qdbp/json/fastjson/MapFillToBeanHandler.java new file mode 100644 index 0000000..b29d651 --- /dev/null +++ b/json/src/main/java/com/gitee/qdbp/json/fastjson/MapFillToBeanHandler.java @@ -0,0 +1,43 @@ +package com.gitee.qdbp.json.fastjson; + +import java.lang.reflect.Type; +import java.util.Map; +import com.alibaba.fastjson.parser.DefaultJSONParser; +import com.alibaba.fastjson.parser.ParserConfig; +import com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer; + +/** + * 将Map填充至实体类的处理器 + * + * @author zhaohuihua + * @version 20211207 + */ +public class MapFillToBeanHandler extends JavaBeanDeserializer { + private final Object bean; + + private final ParserConfig config; + + public MapFillToBeanHandler(Object bean, ParserConfig config) { + super(config, bean.getClass()); + this.bean = bean; + this.config = config; + } + + @Override + public Object createInstance(DefaultJSONParser parser, Type type) { + // 调用此方法时: JavaBeanDeserializer.createInstance(Map map, ParserConfig config) + // 会调用本方法: createInstance(DefaultJSONParser parser, Type type) + // 这里直接返回构造方法中传入的bean, 达到将map赋值给已知对象的目的 + return bean; + } + + public Object createInstance(Map map) { + try { + return createInstance(map, config); + } catch (IllegalArgumentException e) { + throw e; + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + } +} \ No newline at end of file -- Gitee From 86f7cde5b50ec1216b6ac95cced46f804124fb9e Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 28 May 2023 23:23:58 +0800 Subject: [PATCH 02/54] =?UTF-8?q?test=E5=B7=A5=E7=A8=8B=E8=B7=B3=E8=BF=87?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E9=98=B6=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/pom.xml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/pom.xml b/test/pom.xml index 5941e7e..e0c3828 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -26,4 +26,25 @@ qdbp-json-test-jackson qdbp-tools-test-jdk7 + + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + true + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.8 + + true + + + + -- Gitee From ba033870824348aea24c5d699f1058c284a70505 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 28 May 2023 23:25:52 +0800 Subject: [PATCH 03/54] =?UTF-8?q?=E9=87=8D=E6=9E=84MapTools.each/ReflectTo?= =?UTF-8?q?ols.findDepthValues?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/able/beans/DepthMap.java | 1 - .../qdbp/able/model/entry/BaseEntryItem.java | 60 ++++ .../qdbp/able/model/entry/EachEntry.java | 38 +++ .../qdbp/able/model/entry/EntryItem.java | 35 +++ .../qdbp/able/model/entry/ListEachEntry.java | 54 ++++ .../qdbp/able/model/entry/ListEntryItem.java | 44 +++ .../qdbp/able/model/entry/MapEachEntry.java | 54 ++++ .../qdbp/able/model/entry/MapEntryItem.java | 33 ++ .../able/model/entry/ObjectEntryItem.java | 38 +++ .../able/model/entry/ObjectsEntryItem.java | 33 ++ .../able/model/entry/ReadonlyEntryItem.java | 33 ++ .../gitee/qdbp/able/result/ResultCode.java | 2 +- .../gitee/qdbp/tools/parse/StringParser.java | 19 +- .../com/gitee/qdbp/tools/utils/MapTools.java | 279 +++++------------ .../gitee/qdbp/tools/utils/ReflectTools.java | 294 ++++++++++-------- 15 files changed, 688 insertions(+), 329 deletions(-) create mode 100644 able/src/main/java/com/gitee/qdbp/able/model/entry/BaseEntryItem.java create mode 100644 able/src/main/java/com/gitee/qdbp/able/model/entry/EachEntry.java create mode 100644 able/src/main/java/com/gitee/qdbp/able/model/entry/EntryItem.java create mode 100644 able/src/main/java/com/gitee/qdbp/able/model/entry/ListEachEntry.java create mode 100644 able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java create mode 100644 able/src/main/java/com/gitee/qdbp/able/model/entry/MapEachEntry.java create mode 100644 able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java create mode 100644 able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java create mode 100644 able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java create mode 100644 able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java diff --git a/able/src/main/java/com/gitee/qdbp/able/beans/DepthMap.java b/able/src/main/java/com/gitee/qdbp/able/beans/DepthMap.java index 42f9509..1682db5 100644 --- a/able/src/main/java/com/gitee/qdbp/able/beans/DepthMap.java +++ b/able/src/main/java/com/gitee/qdbp/able/beans/DepthMap.java @@ -50,7 +50,6 @@ public class DepthMap implements Copyable, Serializable { this.map = map; } - @SuppressWarnings("unchecked") public DepthMap put(String key, Object value) { MapTools.putValue(map, key, value); return this; diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/BaseEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/BaseEntryItem.java new file mode 100644 index 0000000..603c4f8 --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/BaseEntryItem.java @@ -0,0 +1,60 @@ +package com.gitee.qdbp.able.model.entry; + +import java.util.regex.Pattern; + +/** + * 基础字段项变量 + * + * @author zhaohuihua + * @version 20230527 + * @since 5.6.0 + */ +abstract class BaseEntryItem implements EntryItem, EntryItem.Resetable { + + private static final Pattern CLEAR_NUMBER_INDEX = Pattern.compile("(^\\[[+-]?\\d+]\\.|\\[[+-]?\\d+])"); + + protected String key; + protected String name; + protected Object value; + protected boolean handled; + + protected BaseEntryItem init(String key, String name, Object value) { + this.key = key; + this.name = name; + this.value = value; + this.handled = false; + return this; + } + + @Override + public String getKey() { + return key; + } + + @Override + public String getFields() { + return key == null ? null : CLEAR_NUMBER_INDEX.matcher(key).replaceAll(""); + } + + @Override + public String getName() { + return name; + } + + @Override + public Object getValue() { + return value; + } + + @Override + public void setValue(Object value) { + this.resetValue(value); + this.handled = true; + } + + @Override + public boolean handled() { + return this.handled; + } + +} \ No newline at end of file diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/EachEntry.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/EachEntry.java new file mode 100644 index 0000000..9948c8a --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/EachEntry.java @@ -0,0 +1,38 @@ +package com.gitee.qdbp.able.model.entry; + +/** + * 用于遍历的字段项变量 + * + * @author zhaohuihua + * @version 20230527 + * @since 5.6.0 + */ +public interface EachEntry extends EntryItem { + + /** 跳过所有, 立即停止 **/ + void skipAll(); + + /** 跳过后续节点 **/ + void skipAfter(); + + /** 跳过进入容器 (只在值为容器时有效) **/ + void skipEnter(); + + /** + * 可中断的遍历字段项变量 + * + * @author zhaohuihua + * @version 20230527 + */ + interface Breakable { + + /** 是否跳过所有, 立即停止 **/ + boolean isSkipAll(); + + /** 是否跳过后续节点 **/ + boolean isSkipAfter(); + + /** 是否跳过进入容器 (只在值为容器时有效) **/ + boolean isSkipEnter(); + } +} diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/EntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/EntryItem.java new file mode 100644 index 0000000..ae742bb --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/EntryItem.java @@ -0,0 +1,35 @@ +package com.gitee.qdbp.able.model.entry; + +/** + * 字段项变量 + * + * @author zhaohuihua + * @version 20230527 + * @since 5.6.0 + */ +public interface EntryItem { + + /** KEY, 如 xxx.yyy[0].zzz[1] **/ + String getKey(); + + /** 字段路径, 如 xxx.yyy.zzz **/ + String getFields(); + + /** 名称, path的最后一段, 如 [1] **/ + String getName(); + + /** 值 **/ + Object getValue(); + + /** 修改值 **/ + void setValue(Object value); + + /** 是否已处理 (是否调用了setValue方法, 用于遍历后判断有没有被处理过) **/ + boolean handled(); + + interface Resetable { + + /** 修改值, 但不改变handled **/ + void resetValue(Object value); + } +} \ No newline at end of file diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEachEntry.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEachEntry.java new file mode 100644 index 0000000..90ed1fd --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEachEntry.java @@ -0,0 +1,54 @@ +package com.gitee.qdbp.able.model.entry; + +import java.util.Collection; + +/** + * 父容器为List的遍历字段项变量 + * + * @author zhaohuihua + * @version 20230527 + * @since 5.6.0 + */ +public class ListEachEntry extends ListEntryItem implements EachEntry, EachEntry.Breakable { + + private boolean skipAll; + private boolean skipAfter; + private boolean skipEnter; + + public ListEachEntry(Collection list) { + super(list); + } + + @Override + public ListEachEntry init(String path, String name, int index, Object value) { + super.init(path, name, index, value); + this.skipAll = false; + this.skipAfter = false; + this.skipEnter = false; + return this; + } + + public void skipAll() { + this.skipAll = true; + } + + public void skipAfter() { + this.skipAfter = true; + } + + public void skipEnter() { + this.skipEnter = true; + } + + public boolean isSkipAll() { + return skipAll; + } + + public boolean isSkipAfter() { + return skipAfter; + } + + public boolean isSkipEnter() { + return skipEnter; + } +} \ No newline at end of file diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java new file mode 100644 index 0000000..64f9cd8 --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java @@ -0,0 +1,44 @@ +package com.gitee.qdbp.able.model.entry; + +import java.util.Collection; +import java.util.List; +import com.gitee.qdbp.able.exception.ServiceException; +import com.gitee.qdbp.able.result.ResultCode; + +/** + * 父容器为List的字段项变量 + * + * @author zhaohuihua + * @version 20230527 + * @since 5.6.0 + */ +public class ListEntryItem extends BaseEntryItem { + + private final Collection list; + private int index; + + public ListEntryItem(Collection list) { + this.list = list; + } + + public ListEntryItem init(String path, String name, int index, Object value) { + super.init(path, name, value); + this.index = index; + return this; + } + + @Override + public void resetValue(Object value) { + if (this.list instanceof List) { + int i = this.index >= 0 ? this.index : this.list.size() + this.index; + @SuppressWarnings("unchecked") + List objects = (List) this.list; + objects.set(i, value); + this.value = value; + } else { + throw new ServiceException(ResultCode.UNSUPPORTED_OPERATION) + .setDetails("Cannot set value, collection real type is " + list.getClass() + ", --> " + key); + } + } + +} \ No newline at end of file diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEachEntry.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEachEntry.java new file mode 100644 index 0000000..8857ae9 --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEachEntry.java @@ -0,0 +1,54 @@ +package com.gitee.qdbp.able.model.entry; + +import java.util.Map; + +/** + * 父容器为Map的遍历字段项变量 + * + * @author zhaohuihua + * @version 20230527 + * @since 5.6.0 + */ +public class MapEachEntry extends MapEntryItem implements EachEntry, EachEntry.Breakable { + + private boolean skipAll; + private boolean skipAfter; + private boolean skipEnter; + + public MapEachEntry(Map map) { + super(map); + } + + @Override + public MapEachEntry init(String key, String name, Object value) { + super.init(key, name, value); + this.skipAll = false; + this.skipAfter = false; + this.skipEnter = false; + return this; + } + + public void skipAll() { + this.skipAll = true; + } + + public void skipAfter() { + this.skipAfter = true; + } + + public void skipEnter() { + this.skipEnter = true; + } + + public boolean isSkipAll() { + return skipAll; + } + + public boolean isSkipAfter() { + return skipAfter; + } + + public boolean isSkipEnter() { + return skipEnter; + } +} \ No newline at end of file diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java new file mode 100644 index 0000000..05df397 --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java @@ -0,0 +1,33 @@ +package com.gitee.qdbp.able.model.entry; + +import java.util.Map; + +/** + * 父容器为Map的字段项变量 + * + * @author zhaohuihua + * @version 20230527 + * @since 5.6.0 + */ +public class MapEntryItem extends BaseEntryItem { + + private final Map map; + + public MapEntryItem(Map map) { + this.map = map; + } + + public MapEntryItem init(String key, String name, Object value) { + super.init(key, name, value); + return this; + } + + @Override + public void resetValue(Object value) { + @SuppressWarnings("unchecked") + Map map = (Map) this.map; + map.put(this.name, value); + this.value = value; + } + +} \ No newline at end of file diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java new file mode 100644 index 0000000..f495dee --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java @@ -0,0 +1,38 @@ +package com.gitee.qdbp.able.model.entry; + +import com.gitee.qdbp.able.exception.ServiceException; +import com.gitee.qdbp.able.result.ResultCode; +import com.gitee.qdbp.tools.utils.ReflectTools; + +/** + * 父容器为Object的字段项变量 + * + * @author zhaohuihua + * @version 20230527 + * @since 5.6.0 + */ +public class ObjectEntryItem extends BaseEntryItem { + + private final Object object; + + public ObjectEntryItem(Object object) { + this.object = object; + } + + public ObjectEntryItem init(String key, String name, Object value) { + super.init(key, name, value); + return this; + } + + @Override + public void resetValue(Object value) { + if (object != null) { + ReflectTools.setFieldValue(object, name, value); + this.value = value; + } else { + throw new ServiceException(ResultCode.UNSUPPORTED_OPERATION) + .setDetails("Cannot set field value for null, --> " + key); + } + } + +} \ No newline at end of file diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java new file mode 100644 index 0000000..32fe937 --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java @@ -0,0 +1,33 @@ +package com.gitee.qdbp.able.model.entry; + +import java.lang.reflect.Array; + +/** + * 父容器为Object[]的字段项变量 + * + * @author zhaohuihua + * @version 20230527 + * @since 5.6.0 + */ +public class ObjectsEntryItem extends BaseEntryItem { + + private final Object object; + private int index; + + public ObjectsEntryItem(Object object) { + this.object = object; + } + + public ObjectsEntryItem init(String path, String name, int index, Object value) { + super.init(path, name, value); + this.index = index; + return this; + } + + @Override + public void resetValue(Object value) { + int i = index >= 0 ? index : Array.getLength(object) + index; + Array.set(object, i, value); + this.value = value; + } +} \ No newline at end of file diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java new file mode 100644 index 0000000..232e158 --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java @@ -0,0 +1,33 @@ +package com.gitee.qdbp.able.model.entry; + +import com.gitee.qdbp.able.exception.ServiceException; +import com.gitee.qdbp.able.result.ResultCode; + +/** + * 父容器不可修改的字段项变量 + * + * @author zhaohuihua + * @version 20230527 + * @since 5.6.0 + */ +public class ReadonlyEntryItem extends BaseEntryItem { + + private final Object object; + + public ReadonlyEntryItem(Object object) { + this.object = object; + } + + public ReadonlyEntryItem init(String key, String name, Object value) { + super.init(key, name, value); + return this; + } + + @Override + public void resetValue(Object value) { + String className = (object == null ? null : object.getClass().getSimpleName()); + throw new ServiceException(ResultCode.UNSUPPORTED_OPERATION) + .setDetails("Cannot set field value for " + className + ", --> " + key); + } + +} \ No newline at end of file diff --git a/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java b/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java index a1bf697..d9e6dbb 100644 --- a/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java +++ b/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java @@ -70,7 +70,7 @@ public enum ResultCode implements IResultMessage { /** 系统配置错误 **/ SYSTEM_CONFIG_ERROR, - /** 暂不支持该操作 **/ + /** 不支持该操作 **/ UNSUPPORTED_OPERATION; /** {@inheritDoc} **/ diff --git a/able/src/main/java/com/gitee/qdbp/tools/parse/StringParser.java b/able/src/main/java/com/gitee/qdbp/tools/parse/StringParser.java index a51f137..d260aa9 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/parse/StringParser.java +++ b/able/src/main/java/com/gitee/qdbp/tools/parse/StringParser.java @@ -1,6 +1,8 @@ package com.gitee.qdbp.tools.parse; +import java.util.Iterator; import java.util.List; +import com.gitee.qdbp.tools.utils.VerifyTools; /** * 字符串解析 @@ -73,7 +75,22 @@ public class StringParser { * @return 字段名数组 */ public static List splitsFields(String fields) { - return SplitFields.split(fields); + List fieldNames = SplitFields.split(fields); + // 清除空值和this + clearFieldNames(fieldNames); + return fieldNames; + } + + @SuppressWarnings("all") + private static void clearFieldNames(List fieldNames) { + // 清除空值和this + Iterator iterator = fieldNames.iterator(); + while (iterator.hasNext()) { + String next = iterator.next(); + if (VerifyTools.isBlank(next) || next.equals("this")) { + iterator.remove(); + } + } } /** diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java index 7124c3e..2a9d216 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java @@ -14,9 +14,12 @@ import java.util.Set; import com.gitee.qdbp.able.beans.DepthMap; import com.gitee.qdbp.able.beans.LinkedListMap; import com.gitee.qdbp.able.exception.ServiceException; +import com.gitee.qdbp.able.model.entry.EachEntry; +import com.gitee.qdbp.able.model.entry.EntryItem; +import com.gitee.qdbp.able.model.entry.ListEachEntry; +import com.gitee.qdbp.able.model.entry.MapEachEntry; import com.gitee.qdbp.able.model.reusable.ExpressionMap; import com.gitee.qdbp.able.result.ResultCode; -import com.gitee.qdbp.tools.beans.MapPlus; /** * Map工具类
@@ -877,25 +880,12 @@ public class MapTools { * @param list 根Map对象数组 * @param interceptor 拦截处理器 */ - @SuppressWarnings("all") - public static void each(List> list, EachInterceptor interceptor) { - // new ListEntry(list) jdk7语法检查报错 - List objects = new ArrayList<>(); - objects.addAll(list); - ListEntry listEntry = new ListEntry(objects); - for (int i = 0; i < list.size(); i++) { - String childName = "[" + i + "]"; - Object childValue = list.get(i); - listEntry.init(childName, childName, i, childValue); - interceptor.intercept(listEntry); - if (listEntry.enter && listEntry.fieldValue != null) { - doEachHandleEntry(listEntry, interceptor); - } - } + public static void each(List list, EachInterceptor interceptor) { + doEachList(null, list, interceptor); } - private static void doEachMap(String parentPath, Map map, EachInterceptor interceptor) { - MapEntry mapEntry = new MapEntry(map); + private static boolean doEachMap(String parentPath, Map map, EachInterceptor interceptor) { + MapEachEntry mapEntry = new MapEachEntry(map); for (Map.Entry item : map.entrySet()) { if (item.getKey() == null || item.getKey().trim().length() == 0) { continue; @@ -904,43 +894,91 @@ public class MapTools { String fieldPath = StringTools.concat('.', parentPath, fieldName); Object fieldValue = item.getValue(); mapEntry.init(fieldPath, fieldName, fieldValue); + // 调用拦截函数 interceptor.intercept(mapEntry); - if (mapEntry.enter && mapEntry.fieldValue != null) { - doEachHandleEntry(mapEntry, interceptor); + if (mapEntry.isSkipAll()) { + // 跳过全部 + return false; + } + if (mapEntry.isSkipAfter()) { + // 跳过当前容器中的后续字段 + break; + } + if (!mapEntry.isSkipEnter() && mapEntry.getValue() != null) { + // 递归进入字段内部 + boolean isContinue = doEnterEntryValue(mapEntry, interceptor); + if (!isContinue) { + return false; + } + } + } + return true; + } + + private static boolean doEachList(String parentPath, List list, EachInterceptor interceptor) { + ListEachEntry listEntry = new ListEachEntry(list); + for (int i = 0; i < list.size(); i++) { + String childName = "[" + i + "]"; + String childPath = ReflectTools.concatFieldPaths(parentPath, childName); + Object childValue = list.get(i); + listEntry.init(childPath, childName, i, childValue); + // 调用拦截函数 + interceptor.intercept(listEntry); + if (listEntry.isSkipAll()) { + // 跳过全部 + return false; + } + if (listEntry.isSkipAfter()) { + // 跳过当前容器中的后续字段 + break; + } + if (!listEntry.isSkipEnter() && listEntry.getValue() != null) { + boolean isContinue = doEnterEntryValue(listEntry, interceptor); + if (!isContinue) { + return false; + } } } + return true; } - private static void doEachHandleEntry(FieldEntry mapEntry, EachInterceptor interceptor) { - String fieldPath = mapEntry.getFieldPath(); - String fieldName = mapEntry.getFieldName(); - Object fieldValue = mapEntry.getFieldValue(); + private static boolean doEnterEntryValue(EachEntry entry, EachInterceptor interceptor) { + String fieldPath = entry.getKey(); + Object fieldValue = entry.getValue(); List list = ConvertTools.parseList(fieldValue); if (list.size() == 1 && list.get(0) == fieldValue) { // 不是数组 if (fieldValue instanceof Map) { Map child = MapTools.toJsonMap((Map) fieldValue); - doEachMap(fieldPath, child, interceptor); + boolean isContinue = doEachMap(fieldPath, child, interceptor); + if (!isContinue) { + return false; + } } else if (!ReflectTools.isPrimitive(fieldValue.getClass(), false)) { + // 将Java对象转换为Map对象, 需要覆盖设置到容器中去 Map child = JsonTools.beanToMap(fieldValue, true, false); - mapEntry.setValue(child); - doEachMap(fieldPath, child, interceptor); + if (entry instanceof EntryItem.Resetable) { + ((EntryItem.Resetable) entry).resetValue(child); + } + boolean isContinue = doEachMap(fieldPath, child, interceptor); + if (!isContinue) { + return false; + } } } else { - mapEntry.setValue(list); - ListEntry listEntry = new ListEntry(list); - for (int i = 0; i < list.size(); i++) { - String suffix = "[" + i + "]"; - String childName = fieldName + suffix; - String childPath = fieldPath + suffix; - Object childValue = list.get(i); - listEntry.init(childPath, childName, i, childValue); - interceptor.intercept(listEntry); - if (listEntry.enter && listEntry.fieldValue != null) { - doEachHandleEntry(listEntry, interceptor); - } + // 遍历过程中ConvertTools.parseList改变了fieldValue结构 + // 例如Collection对象会转换为List对象 + // 需要覆盖设置到容器中去, 否则对List内容的修改无法变量入参对象 + if (entry instanceof EntryItem.Resetable) { + ((EntryItem.Resetable) entry).resetValue(list); + } + // 遍历list内容 + boolean isContinue = doEachList(fieldPath, list, interceptor); + if (!isContinue) { + return false; } } + return true; } /** 遍历Map的拦截处理器 **/ @@ -951,168 +989,7 @@ public class MapTools { * * @param entry 当前值 */ - void intercept(FieldEntry entry); + void intercept(EachEntry entry); } - /** 遍历Map的字段项变量 **/ - public interface FieldEntry { - - String getFieldPath(); - - String getFieldName(); - - Object getFieldValue(); - - void setValue(Object value); - - /** 设置额外的参数 (如果父对象是数组, 则该操作无效) **/ - void putExtraValue(String key, Object value); - - /** 获取额外的参数 **/ - MapPlus getExtraValues(); - - /** 是否已处理 (只要调用了setValue/putExtraValue就是已处理) **/ - boolean isHandled(); - - /** 是否进入容器, 如果设置为false则不继续处理容器内容 (只在容器值时有效) **/ - void setEnter(boolean enter); - } - - private static class MapEntry implements FieldEntry { - - private final Map map; - private String fieldPath; - private String fieldName; - private Object fieldValue; - private final MapPlus extras = new MapPlus(); - /** 是否已处理 (只要调用了setValue/putExtraValue就是已处理) **/ - private boolean handled; - /** 是否进入容器, 如果设置为false则不继续处理容器内容 (只在容器值时有效) **/ - private boolean enter; - - private MapEntry(Map map) { - this.map = map; - } - - public void init(String fieldPath, String fieldName, Object fieldValue) { - this.fieldPath = fieldPath; - this.fieldName = fieldName; - this.fieldValue = fieldValue; - this.extras.clear(); - this.handled = false; - this.enter = true; - } - - @Override - public String getFieldPath() { - return fieldPath; - } - - @Override - public String getFieldName() { - return fieldName; - } - - @Override - public Object getFieldValue() { - return fieldValue; - } - - @Override - public void setValue(Object value) { - this.map.put(this.fieldName, value); - this.fieldValue = value; - this.handled = true; - } - - @Override - public void putExtraValue(String key, Object value) { - this.map.put(key, value); - this.extras.put(key, value); - this.handled = true; - } - - @Override - public MapPlus getExtraValues() { - return new MapPlus(this.extras); - } - - @Override - public boolean isHandled() { - return this.handled; - } - - @Override - public void setEnter(boolean enter) { - this.enter = enter; - } - } - - private static class ListEntry implements FieldEntry { - - private final List list; - private String fieldPath; - private String fieldName; - private int index; - private Object fieldValue; - /** 是否已处理 (只要调用了setValue/putExtraValue就是已处理) **/ - private boolean handled; - /** 是否进入容器, 如果设置为false则不继续处理容器内容 (只在容器值时有效) **/ - private boolean enter; - - private ListEntry(List list) { - this.list = list; - } - - public void init(String fieldPath, String fieldName, int index, Object fieldValue) { - this.fieldPath = fieldPath; - this.fieldName = fieldName; - this.index = index; - this.fieldValue = fieldValue; - this.handled = false; - this.enter = true; - } - - @Override - public String getFieldPath() { - return fieldPath; - } - - @Override - public String getFieldName() { - return fieldName; - } - - @Override - public Object getFieldValue() { - return fieldValue; - } - - @Override - public void setValue(Object value) { - this.list.set(this.index, value); - this.fieldValue = value; - this.handled = true; - } - - @Override - public void putExtraValue(String key, Object value) { - // 父对象是数组, 则该操作无效 - } - - @Override - public MapPlus getExtraValues() { - return null; - } - - @Override - public boolean isHandled() { - return this.handled; - } - - @Override - public void setEnter(boolean enter) { - this.enter = enter; - } - } } diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java index 7e6dca7..a22f2d9 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java @@ -15,7 +15,12 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import com.gitee.qdbp.able.beans.KeyValue; +import com.gitee.qdbp.able.model.entry.EntryItem; +import com.gitee.qdbp.able.model.entry.ListEntryItem; +import com.gitee.qdbp.able.model.entry.MapEntryItem; +import com.gitee.qdbp.able.model.entry.ObjectEntryItem; +import com.gitee.qdbp.able.model.entry.ObjectsEntryItem; +import com.gitee.qdbp.able.model.entry.ReadonlyEntryItem; import com.gitee.qdbp.able.model.reusable.ExpressionMap; import com.gitee.qdbp.tools.parse.StringParser; @@ -69,8 +74,6 @@ public abstract class ReflectTools { private static Object doGetDepthValue(Object target, String fields) { // 将表达式以.或[]拆分为数组 List fieldNames = StringParser.splitsFields(fields); - // 清除空值和this - clearFieldNames(fieldNames); // 逐层取值 Object value = target; for (int i = 0, z = fieldNames.size(); value != null && i < z; i++) { @@ -103,41 +106,38 @@ public abstract class ReflectTools { } private static Object getArrayFieldValue(Object array, String fieldName) { + Integer index = ConvertTools.toInteger(fieldName, null); + return index == null ? null : getArrayFieldValue(array, index); + } + + private static Object getArrayFieldValue(Object array, int index) { int size = Array.getLength(array); - Integer number = ConvertTools.toInteger(fieldName, null); - if (number == null) { - return null; - } else { - int index = number; - if (number < 0) { - index = size + number; - } - return index < 0 || index >= size ? null : Array.get(array, index); - } + int i = index >= 0 ? index : size + index; + return i < 0 || i >= size ? null : Array.get(array, i); } private static Object getListFieldValue(List list, String fieldName) { - Integer number = ConvertTools.toInteger(fieldName, null); - if (number == null) { - return null; - } - int index = number; - if (number < 0) { - index = list.size() + number; - } - return index < 0 || index >= list.size() ? null : list.get(index); + Integer index = ConvertTools.toInteger(fieldName, null); + return index == null ? null : getListFieldValue(list, index); + } + + private static Object getListFieldValue(List list, int index) { + int size = list.size(); + int i = index >= 0 ? index : size + index; + return i < 0 || i >= size ? null : list.get(i); } private static Object getIterableFieldValue(Iterable iterable, String fieldName) { - Integer number = ConvertTools.toInteger(fieldName, null); - if (number == null) { - return null; - } - if (number >= 0) { - int index = number; + Integer index = ConvertTools.toInteger(fieldName, null); + return index == null ? null : getIterableFieldValue(iterable, index); + } + + private static Object getIterableFieldValue(Iterable iterable, int index) { + if (index >= 0) { + int number = index; int i = 0; for (Object value : iterable) { - if (i++ == index) { + if (i++ == number) { return value; } } @@ -150,8 +150,8 @@ public abstract class ReflectTools { size++; } } - int index = size + number; - if (index < 0 || index >= size) { + int number = size + index; + if (number < 0 || number >= size) { return null; } { // 再次循环, 获取对象 @@ -159,7 +159,7 @@ public abstract class ReflectTools { int i = 0; while (iterator.hasNext()) { Object value = iterator.next(); - if (i++ == index) { + if (i++ == i) { return value; } } @@ -169,12 +169,12 @@ public abstract class ReflectTools { } private static Object getIteratorFieldValue(Iterator iterator, String fieldName) { - Integer number = ConvertTools.toInteger(fieldName, null); - if (number == null) { - return null; - } - if (number >= 0) { - int index = number; + Integer index = ConvertTools.toInteger(fieldName, null); + return index == null ? null : getIteratorFieldValue(iterator, index); + } + + private static Object getIteratorFieldValue(Iterator iterator, int index) { + if (index >= 0) { int i = 0; while (iterator.hasNext()) { Object value = iterator.next(); @@ -191,18 +191,18 @@ public abstract class ReflectTools { size++; temp.add(iterator.next()); } - int index = size + number; - return index < 0 || index >= size ? null : temp.get(index); + int i = size + index; + return i < 0 || i >= size ? null : temp.get(i); } } private static Object getEnumerationFieldValue(Enumeration enumeration, String fieldName) { - Integer number = ConvertTools.toInteger(fieldName, null); - if (number == null) { - return null; - } - if (number >= 0) { - int index = number; + Integer index = ConvertTools.toInteger(fieldName, null); + return index == null ? null : getEnumerationFieldValue(enumeration, index); + } + + private static Object getEnumerationFieldValue(Enumeration enumeration, int index) { + if (index >= 0) { int i = 0; while (enumeration.hasMoreElements()) { Object value = enumeration.nextElement(); @@ -219,8 +219,8 @@ public abstract class ReflectTools { size++; temp.add(enumeration.nextElement()); } - int index = size + number; - return index < 0 || index >= size ? null : temp.get(index); + int i = size + index; + return i < 0 || i >= size ? null : temp.get(i); } } @@ -251,9 +251,9 @@ public abstract class ReflectTools { * * @param target 目标对象, 支持数组/List/Map/Bean * @param fieldNames 字段名, 支持带点的多级字段名/数组下标/负数下标 - * @return 字段值 + * @return EntryItem字段对象 (支持修改字段值) */ - public static List> findDepthValues(Object target, String fieldNames) { + public static List findDepthValues(Object target, String fieldNames) { VerifyTools.requireNotBlank(fieldNames, "field"); if (target == null) { return new ArrayList<>(); @@ -261,14 +261,14 @@ public abstract class ReflectTools { String[] orFields = StringTools.split(fieldNames, "||"); for (int i = 0, z = orFields.length - 1; i <= z; i++) { String fields = orFields[i]; - List> result = doFindDepthValues(target, fields); + List result = doFindDepthValues(target, fields); if (i == z) { // 最后一个OR字段, 直接返回 return result; } else { // 不是最后一个OR字段, 判断是否存在非空的值 boolean existValue = false; - for (KeyValue item : result) { + for (EntryItem item : result) { if (VerifyTools.isNotBlank(item.getValue())) { existValue = true; } @@ -281,21 +281,22 @@ public abstract class ReflectTools { return new ArrayList<>(); } - private static List> doFindDepthValues(Object target, String fields) { + private static List doFindDepthValues(Object target, String fields) { + VerifyTools.requireNotBlank(fields, "fields"); // 将表达式以.或[]拆分为数组 List fieldNames = StringParser.splitsFields(fields); - // 清除空值和this - clearFieldNames(fieldNames); + // 如果target是对象, 将target装入list, 此时entry中的容器对象为null + // 如果target是数组或列表, 转换为list返回, 此时entry中的容器对象为target + List items = parseRootValues(target, needExpandList(fieldNames, 0)); // 逐层取值 - List> items = parseListValues(null, target, needExpandList(fieldNames, 0)); for (int i = 0, z = fieldNames.size() - 1; i <= z; i++) { String field = fieldNames.get(i); // 是否需要展开 (有下一层且下一层是数字时,不需要展开) boolean expand = needExpandList(fieldNames, i + 1); - List> temp = new ArrayList<>(); - for (KeyValue item : items) { - // 上级字段名 - String parentFields = item.getKey(); + List temp = new ArrayList<>(); + for (EntryItem item : items) { + // 本级字段路径 + String currPath = item.getKey(); // 本级字段值 Object currValue = item.getValue(); // 下级字段值 @@ -305,6 +306,9 @@ public abstract class ReflectTools { if (currValue == null) { nextValue = null; currList = false; + } else if (currValue instanceof Map) { + nextValue = getMapFieldValue((Map) currValue, field); + currList = false; } else if (currValue instanceof List) { nextValue = getListFieldValue((List) currValue, field); currList = true; @@ -320,23 +324,14 @@ public abstract class ReflectTools { } else if (currValue instanceof Enumeration) { nextValue = getEnumerationFieldValue((Enumeration) currValue, field); currList = true; - } else if (currValue instanceof Map) { - nextValue = getMapFieldValue((Map) currValue, field); - currList = false; } else { nextValue = getFieldValue(currValue, field, false); currList = false; } - String nextField; - if (currList) { - nextField = StringTools.concat(parentFields, "[" + field + "]"); - } else { - nextField = StringTools.concat('.', parentFields, field); - } // 最末级即使值为空也要加入结果集, 不是最末级则只要值为空就不再继续 boolean isLastField = i >= z; if (isLastField || nextValue != null) { - temp.addAll(parseListValues(nextField, nextValue, expand)); + temp.addAll(parseListValues(currValue, currPath, currList, field, nextValue, expand)); } } items = temp; @@ -344,75 +339,123 @@ public abstract class ReflectTools { return items; } - @SuppressWarnings("all") - private static void clearFieldNames(List fieldNames) { - // 清除空值和this - Iterator iterator = fieldNames.iterator(); - while (iterator.hasNext()) { - String next = iterator.next(); - if (VerifyTools.isBlank(next) || next.equals("this")) { - iterator.remove(); - } - } - } - - // 根据字段名判断是否需要展开 (有下一层且下一层是数字时,说明是取数组的其中一项,不需要展开) + // 根据字段名判断是否需要展开 + // 没有下一层,说明已经是最末级字段了,不需要展开 + // 有下一层且下一层是数字时,说明是取数组的其中一项,不需要展开 private static boolean needExpandList(List fields, int index) { if (index >= fields.size()) { - return true; + return false; } else { String field = fields.get(index); return !StringTools.isNumber(field) || field.indexOf('.') >= 0; } } - private static List> parseListValues(String field, Object value, boolean expand) { - List> results = new ArrayList<>(); + private static List parseRootValues(Object fieldValue, boolean expand) { + return parseListValues(null, null, false, null, fieldValue, expand); + } + + // 为了简化处理, 单个对象也转换为list + // 如果parent是对象, 返回的list只有一个元素: EntryItem的容器是parent, 值是fieldValue + // 如果parent是列表, 返回的list是列表的每个元素: EntryItem的容器是fieldValue, 值是fieldValue[i] + private static List parseListValues(Object parent, String parentPath, boolean parentList, + String fieldName, Object fieldValue, boolean expand) { + List results = new ArrayList<>(); if (!expand) { - results.add(new KeyValue<>(field, value)); + results.add(newObjectEntryItem(parent, parentPath, parentList, fieldName, fieldValue)); } else { - if (value == null) { - results.add(new KeyValue<>(field, null)); - } else if (value instanceof List) { - List values = (List) value; - for (int i = 0; i < values.size(); i++) { - String key = StringTools.concat(field, "[" + i + "]"); - results.add(new KeyValue<>(key, values.get(i))); - } - } else if (value.getClass().isArray()) { - Object[] values = (Object[]) value; - for (int i = 0; i < values.length; i++) { - String key = StringTools.concat(field, "[" + i + "]"); - results.add(new KeyValue<>(key, values[i])); - } - } else if (value instanceof Iterable) { - Iterable iterable = (Iterable) value; - int i = 0; - for (Object item : iterable) { - String key = StringTools.concat(field, "[" + (i++) + "]"); - results.add(new KeyValue<>(key, item)); - } - } else if (value instanceof Iterator) { - Iterator iterator = (Iterator) value; - int i = 0; - while (iterator.hasNext()) { - String key = StringTools.concat(field, "[" + (i++) + "]"); - results.add(new KeyValue<>(key, iterator.next())); - } - } else if (value instanceof Enumeration) { - Enumeration enumeration = (Enumeration) value; - int i = 0; - while (enumeration.hasMoreElements()) { - String key = StringTools.concat(field, "[" + (i++) + "]"); - results.add(new KeyValue<>(key, enumeration.nextElement())); - } + if (fieldValue == null) { + results.add(newObjectEntryItem(parent, parentPath, parentList, fieldName, null)); + } else if (fieldValue instanceof Map) { + results.add(newObjectEntryItem(parent, parentPath, parentList, fieldName, fieldValue)); } else { - results.add(new KeyValue<>(field, value)); + String realFieldName = parentList ? "[" + fieldName + "]" : fieldName; + if (fieldValue instanceof List) { + List values = (List) fieldValue; + for (int i = 0; i < values.size(); i++) { + String name = "[" + i + "]"; + String path = concatFieldPaths(parentPath, realFieldName, name); + results.add(new ListEntryItem(values).init(path, name, i, values.get(i))); + } + } else if (fieldValue.getClass().isArray()) { + Object[] values = (Object[]) fieldValue; + for (int i = 0; i < values.length; i++) { + String name = "[" + i + "]"; + String path = concatFieldPaths(parentPath, realFieldName, name); + results.add(new ObjectsEntryItem(values).init(path, name, i, values[i])); + } + } else if (fieldValue instanceof Iterable) { + Iterable iterable = (Iterable) fieldValue; + int i = 0; + for (Object item : iterable) { + String name = "[" + (i++) + "]"; + String path = concatFieldPaths(parentPath, realFieldName, name); + results.add(new ReadonlyEntryItem(iterable).init(path, name, item)); + } + } else if (fieldValue instanceof Iterator) { + Iterator iterator = (Iterator) fieldValue; + int i = 0; + while (iterator.hasNext()) { + String name = "[" + (i++) + "]"; + String path = concatFieldPaths(parentPath, realFieldName, name); + results.add(new ReadonlyEntryItem(iterator).init(path, name, iterator.next())); + } + } else if (fieldValue instanceof Enumeration) { + Enumeration enumeration = (Enumeration) fieldValue; + int i = 0; + while (enumeration.hasMoreElements()) { + String name = "[" + (i++) + "]"; + String path = concatFieldPaths(parentPath, realFieldName, name); + results.add(new ReadonlyEntryItem(enumeration).init(path, name, enumeration.nextElement())); + } + } else { + results.add(newObjectEntryItem(parent, parentPath, parentList, fieldName, fieldValue)); + } } } return results; } + private static EntryItem newObjectEntryItem(Object parent, String parentPath, boolean parentList, + String fieldName, Object fieldValue) { + if (!parentList) { + String path = concatFieldPaths(parentPath, fieldName); + if (parent instanceof Map) { + return new MapEntryItem((Map) parent).init(path, fieldName, fieldValue); + } else { + return new ObjectEntryItem(parent).init(path, fieldName, fieldValue); + } + } else { + Integer index = ConvertTools.toInteger(fieldName, null); + String name = "[" + fieldName + "]"; + String path = concatFieldPaths(parentPath, name); + if (index != null && parent instanceof List) { + return new ListEntryItem((List) parent).init(path, name, index, fieldValue); + } else if (index != null && parent.getClass().isArray()) { + return new ObjectsEntryItem(parent).init(path, name, index, fieldValue); + } else { + return new ReadonlyEntryItem(parent).init(path, name, fieldValue); + } + } + } + + static String concatFieldPaths(String... parts) { + StringBuilder buffer = new StringBuilder(); + for (String part : parts) { + if (part == null || part.length() == 0) { + continue; + } + if (buffer.length() == 0) { + buffer.append(part); + } else if (StringTools.startsWithChar(part, '[')) { + buffer.append(part); + } else { + buffer.append('.').append(part); + } + } + return buffer.length() == 0 ? null : buffer.toString(); + } + /** * 深度判断对象中是否存在指定的字段, 支持多级字段名 * @@ -441,7 +484,7 @@ public abstract class ReflectTools { // 逐层取值 for (int j = 0, z = list == null ? 0 : list.length; value != null && j < z; j++) { String field = list[j]; - if (VerifyTools.isNotBlank(field) && !field.equals("this")) { + if (VerifyTools.isNotBlank(field)) { if (value instanceof List) { if (containsListIndex((List) value, field)) { value = getListFieldValue((List) value, field); @@ -606,7 +649,8 @@ public abstract class ReflectTools { } if (throwOnNotFound) { - throw new IllegalArgumentException(clazz.getSimpleName() + "." + fieldName + " not found."); + String fieldPath = concatFieldPaths(clazz.getSimpleName(), fieldName); + throw new IllegalArgumentException(fieldPath + " not found."); } else { return null; } -- Gitee From d38ac903fff99ca5aa65425c98b1b9061d180120 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 28 May 2023 23:26:10 +0800 Subject: [PATCH 04/54] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/tools/test/EachMapTest.java | 33 +- .../qdbp/tools/utils/ReflectToolsTest.java | 452 ++++++++++++++++-- 2 files changed, 451 insertions(+), 34 deletions(-) diff --git a/test/qdbp-tools-test-jdk7/src/test/java/com/gitee/qdbp/tools/test/EachMapTest.java b/test/qdbp-tools-test-jdk7/src/test/java/com/gitee/qdbp/tools/test/EachMapTest.java index 92506e2..775c159 100644 --- a/test/qdbp-tools-test-jdk7/src/test/java/com/gitee/qdbp/tools/test/EachMapTest.java +++ b/test/qdbp-tools-test-jdk7/src/test/java/com/gitee/qdbp/tools/test/EachMapTest.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.Map; import org.testng.Assert; import org.testng.annotations.Test; +import com.gitee.qdbp.able.model.entry.EachEntry; import com.gitee.qdbp.tools.beans.MapPlus; import com.gitee.qdbp.tools.utils.JsonTools; import com.gitee.qdbp.tools.utils.MapTools; @@ -47,12 +48,14 @@ public class EachMapTest { Assert.assertEquals(address1.getClass(), MapPlus.class); Assert.assertSame(address1, address); + System.out.println("-------------------------------"); + final Map result = new LinkedHashMap<>(); MapTools.each(root, new MapTools.EachInterceptor() { @Override - public void intercept(MapTools.FieldEntry entry) { - String fieldPath = entry.getFieldPath(); - Object fieldValue = entry.getFieldValue(); + public void intercept(EachEntry entry) { + String fieldPath = entry.getKey(); + Object fieldValue = entry.getValue(); if (fieldValue == null) { result.put(fieldPath, null); } else if (ReflectTools.isPrimitive(fieldValue.getClass(), false)) { @@ -70,5 +73,29 @@ public class EachMapTest { Assert.assertEquals(result.get("entity.user.address[0].city"), "nanjing"); Assert.assertEquals(result.get("entity.user.address[0].phones[0]"), "1301112222"); Assert.assertEquals(result.get("entity.user.address[0].phones[1]"), "13044445555"); + + System.out.println("-------------------------------"); + + final Map aResult = new LinkedHashMap<>(); + MapTools.each(addresses, new MapTools.EachInterceptor() { + @Override + public void intercept(EachEntry entry) { + String fieldPath = entry.getKey(); + Object fieldValue = entry.getValue(); + if (fieldValue == null) { + aResult.put(fieldPath, null); + } else if (ReflectTools.isPrimitive(fieldValue.getClass(), false)) { + aResult.put(fieldPath, fieldValue); + } + } + }); + System.out.println(JsonTools.toLogString(aResult)); + Assert.assertTrue(aResult.containsKey("[0].city")); + Assert.assertTrue(aResult.containsKey("[0].phones[0]")); + Assert.assertTrue(aResult.containsKey("[0].phones[1]")); + + Assert.assertEquals(aResult.get("[0].city"), "nanjing"); + Assert.assertEquals(aResult.get("[0].phones[0]"), "1301112222"); + Assert.assertEquals(aResult.get("[0].phones[1]"), "13044445555"); } } diff --git a/tools/src/test/java/com/gitee/qdbp/tools/utils/ReflectToolsTest.java b/tools/src/test/java/com/gitee/qdbp/tools/utils/ReflectToolsTest.java index 05eaa84..c6aa830 100644 --- a/tools/src/test/java/com/gitee/qdbp/tools/utils/ReflectToolsTest.java +++ b/tools/src/test/java/com/gitee/qdbp/tools/utils/ReflectToolsTest.java @@ -1,10 +1,11 @@ package com.gitee.qdbp.tools.utils; +import java.util.HashMap; import java.util.List; import java.util.Map; -import com.gitee.qdbp.able.beans.KeyValue; import org.testng.Assert; import org.testng.annotations.Test; +import com.gitee.qdbp.able.model.entry.EntryItem; @Test public class ReflectToolsTest { @@ -260,30 +261,50 @@ public class ReflectToolsTest { public void testFindDepthValue11() { String json = "{domain:{text:'baidu',url:'https://baidu.com'}}"; System.out.println(json); - Object object = JsonTools.parseAsMap(json); { + Object object = JsonTools.parseAsMap(json); String key = "domain.text"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "domain.text", key); + Assert.assertEquals(values.get(0).getFields(), "domain.text", key); + Assert.assertEquals(values.get(0).getName(), "text", key); Assert.assertEquals(values.get(0).getValue(), "baidu", key); + // 设置值 + values.get(0).setValue("baidu2"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "baidu2", key); } { + Object object = JsonTools.parseAsMap(json); String key = "domain.name"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "domain.name", key); + Assert.assertEquals(values.get(0).getFields(), "domain.name", key); + Assert.assertEquals(values.get(0).getName(), "name", key); Assert.assertNull(values.get(0).getValue(), key); + // 设置值 + values.get(0).setValue("baidu22"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "baidu22", key); } { + Object object = JsonTools.parseAsMap(json); String key = "domain.name || domain.text"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "domain.text", key); + Assert.assertEquals(values.get(0).getFields(), "domain.text", key); + Assert.assertEquals(values.get(0).getName(), "text", key); Assert.assertEquals(values.get(0).getValue(), "baidu", key); + // 设置值 + values.get(0).setValue("baidu222"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "baidu222", key); } } @@ -292,36 +313,57 @@ public class ReflectToolsTest { String json = "[{domain:{text:'baidu',url:'https://baidu.com'}},{domain:{text:'bing',url:'https://cn.bing.com'}}]"; System.out.println(json); - Object object = JsonTools.parseAsMaps(json); { + Object object = JsonTools.parseAsMaps(json); String key = "[1].domain.text"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "[1].domain.text", key); + Assert.assertEquals(values.get(0).getFields(), "domain.text", key); + Assert.assertEquals(values.get(0).getName(), "text", key); Assert.assertEquals(values.get(0).getValue(), "bing", key); + // 设置值 + values.get(0).setValue("bing2"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "bing2", key); } { + Object object = JsonTools.parseAsMaps(json); String key = "[2].domain.text"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 0, key + ".size"); } { + Object object = JsonTools.parseAsMaps(json); String key = "[-1].domain.text"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "[-1].domain.text", key); + Assert.assertEquals(values.get(0).getFields(), "domain.text", key); + Assert.assertEquals(values.get(0).getName(), "text", key); Assert.assertEquals(values.get(0).getValue(), "bing", key); + // 设置值 + values.get(0).setValue("bing22"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "bing22", key); } { + Object object = JsonTools.parseAsMaps(json); String key = "[-2].domain.text"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "[-2].domain.text", key); + Assert.assertEquals(values.get(0).getFields(), "domain.text", key); + Assert.assertEquals(values.get(0).getName(), "text", key); Assert.assertEquals(values.get(0).getValue(), "baidu", key); + // 设置值 + values.get(0).setValue("baidu222"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "baidu222", key); } } @@ -332,13 +374,23 @@ public class ReflectToolsTest { System.out.println(json); Object object = JsonTools.parseAsMaps(json); String key = "domain.text"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 2, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "[0].domain.text", key); + Assert.assertEquals(values.get(0).getFields(), "domain.text", key); + Assert.assertEquals(values.get(0).getName(), "text", key); Assert.assertEquals(values.get(0).getValue(), "baidu", key); Assert.assertEquals(values.get(1).getKey(), "[1].domain.text", key); + Assert.assertEquals(values.get(1).getFields(), "domain.text", key); + Assert.assertEquals(values.get(1).getName(), "text", key); Assert.assertEquals(values.get(1).getValue(), "bing", key); + // 设置值 + values.get(0).setValue("baidu2"); + values.get(1).setValue("bing2"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "baidu2", key); + Assert.assertEquals(values2.get(1).getValue(), "bing2", key); } @Test @@ -349,10 +401,12 @@ public class ReflectToolsTest { Object object = JsonTools.parseAsMap(json); { String key = "data[1].domain"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); Object value = values.get(0).getValue(); System.out.println(key + " = " + JsonTools.toLogString(value)); Assert.assertEquals(values.get(0).getKey(), "data[1].domain", key); + Assert.assertEquals(values.get(0).getFields(), "data.domain", key); + Assert.assertEquals(values.get(0).getName(), "domain", key); Assert.assertNotNull(value); Assert.assertTrue(Map.class.isAssignableFrom(value.getClass())); Map domain = (Map) value; @@ -361,7 +415,7 @@ public class ReflectToolsTest { } { String key = "data[2].domain"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + JsonTools.toLogString(values)); Assert.assertEquals(values.size(), 0, key); } @@ -374,13 +428,15 @@ public class ReflectToolsTest { System.out.println(json); Object object = JsonTools.parseAsMap(json); String key = "data.domain"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); Assert.assertEquals(values.size(), 2, key + ".size"); String key1 = values.get(0).getKey(); Object value1 = values.get(0).getValue(); System.out.println(key1 + " = " + JsonTools.toLogString(value1)); Assert.assertEquals(key1, "data[0].domain", key); + Assert.assertEquals(values.get(0).getFields(), "data.domain", key); + Assert.assertEquals(values.get(0).getName(), "domain", key); Assert.assertNotNull(value1); Assert.assertTrue(Map.class.isAssignableFrom(value1.getClass())); Map domain1 = (Map) value1; @@ -391,6 +447,8 @@ public class ReflectToolsTest { Object value2 = values.get(1).getValue(); System.out.println(key2 + " = " + JsonTools.toLogString(value2)); Assert.assertEquals(key2, "data[1].domain", key); + Assert.assertEquals(values.get(1).getFields(), "data.domain", key); + Assert.assertEquals(values.get(1).getName(), "domain", key); Assert.assertNotNull(value2); Assert.assertTrue(Map.class.isAssignableFrom(value2.getClass())); Map domain2 = (Map) value2; @@ -403,38 +461,65 @@ public class ReflectToolsTest { String json = "{data:[{domain:{text:'baidu',url:'https://baidu.com'}}," + "{domain:{text:'bing',url:'https://cn.bing.com'}}]}"; System.out.println(json); - Object object = JsonTools.parseAsMap(json); { + Object object = JsonTools.parseAsMap(json); String key = "data[1].domain.text"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "data[1].domain.text", key); + Assert.assertEquals(values.get(0).getFields(), "data.domain.text", key); + Assert.assertEquals(values.get(0).getName(), "text", key); Assert.assertEquals(values.get(0).getValue(), "bing", key); + // 设置值 + values.get(0).setValue("bing2"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "bing2", key); } { + Object object = JsonTools.parseAsMap(json); String key = "data[1].domain.name"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "data[1].domain.name", key); + Assert.assertEquals(values.get(0).getFields(), "data.domain.name", key); + Assert.assertEquals(values.get(0).getName(), "name", key); Assert.assertNull(values.get(0).getValue(), key); + // 设置值 + values.get(0).setValue("bing22"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "bing22", key); } { + Object object = JsonTools.parseAsMap(json); String key = "data[1].domain.name || data[1].domain.text"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "data[1].domain.text", key); + Assert.assertEquals(values.get(0).getFields(), "data.domain.text", key); + Assert.assertEquals(values.get(0).getName(), "text", key); Assert.assertEquals(values.get(0).getValue(), "bing", key); + // 设置值 + values.get(0).setValue("bing222"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "bing222", key); } { + Object object = JsonTools.parseAsMap(json); String key = ".data[1].domain.name"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "data[1].domain.name", key); + Assert.assertEquals(values.get(0).getFields(), "data.domain.name", key); + Assert.assertEquals(values.get(0).getName(), "name", key); Assert.assertNull(values.get(0).getValue(), key); + // 设置值 + values.get(0).setValue("bing2222"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "bing2222", key); } } @@ -445,19 +530,41 @@ public class ReflectToolsTest { System.out.println(json); Object object = JsonTools.parseAsMap(json); String key = "data.domain.address.city"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 5, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "data[0].domain.address[0].city", key); + Assert.assertEquals(values.get(0).getFields(), "data.domain.address.city", key); + Assert.assertEquals(values.get(0).getName(), "city", key); Assert.assertEquals(values.get(0).getValue(), "Guangzhou", key); Assert.assertEquals(values.get(1).getKey(), "data[0].domain.address[1].city", key); + Assert.assertEquals(values.get(1).getFields(), "data.domain.address.city", key); + Assert.assertEquals(values.get(1).getName(), "city", key); Assert.assertEquals(values.get(1).getValue(), "Nanjing", key); Assert.assertEquals(values.get(2).getKey(), "data[1].domain.address[0].city", key); + Assert.assertEquals(values.get(2).getFields(), "data.domain.address.city", key); + Assert.assertEquals(values.get(2).getName(), "city", key); Assert.assertEquals(values.get(2).getValue(), "Beijing", key); Assert.assertEquals(values.get(3).getKey(), "data[1].domain.address[1].city", key); + Assert.assertEquals(values.get(3).getFields(), "data.domain.address.city", key); + Assert.assertEquals(values.get(3).getName(), "city", key); Assert.assertEquals(values.get(3).getValue(), "Shanghai", key); Assert.assertEquals(values.get(4).getKey(), "data[1].domain.address[2].city", key); + Assert.assertEquals(values.get(4).getFields(), "data.domain.address.city", key); + Assert.assertEquals(values.get(4).getName(), "city", key); Assert.assertEquals(values.get(4).getValue(), "Shenzhen", key); + // 设置值 + values.get(0).setValue("Guangzhou2"); + values.get(1).setValue("Nanjing2"); + values.get(2).setValue("Beijing2"); + values.get(3).setValue("Shanghai2"); + values.get(4).setValue("Shenzhen2"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "Guangzhou2", key); + Assert.assertEquals(values2.get(1).getValue(), "Nanjing2", key); + Assert.assertEquals(values2.get(2).getValue(), "Beijing2", key); + Assert.assertEquals(values2.get(3).getValue(), "Shanghai2", key); + Assert.assertEquals(values2.get(4).getValue(), "Shenzhen2", key); } @Test @@ -466,11 +573,17 @@ public class ReflectToolsTest { System.out.println(json); Object object = JsonTools.parseAsMap(json); String key = "data.domain.text"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "data[0].domain.text", key); + Assert.assertEquals(values.get(0).getFields(), "data.domain.text", key); + Assert.assertEquals(values.get(0).getName(), "text", key); Assert.assertNull(values.get(0).getValue(), key); + // 设置值 + values.get(0).setValue("baidu2"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "baidu2", key); } @Test @@ -479,70 +592,347 @@ public class ReflectToolsTest { System.out.println(json); Object object = JsonTools.parseAsMap(json); String key = "data.domain.text"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 0, key + ".size"); } @Test - public void testFindLastListIndex() { + public void testFindLastListIndex11() { String json = "{data:[1,2,3,4,5,6]}"; System.out.println(json); - Object object = JsonTools.parseAsMap(json); { + Object object = JsonTools.parseAsMap(json); + String key = "data[0]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[0]", key); + Assert.assertEquals(values.get(0).getValue(), 1, key); + // 设置值 + values.get(0).setValue(11); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 11, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[5]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[5]", key); + Assert.assertEquals(values.get(0).getValue(), 6, key); + // 设置值 + values.get(0).setValue(66); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 66, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[-1]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-1]", key); + Assert.assertEquals(values.get(0).getValue(), 6, key); + // 设置值 + values.get(0).setValue(66); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 66, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[-2]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-2]", key); + Assert.assertEquals(values.get(0).getValue(), 5, key); + // 设置值 + values.get(0).setValue(55); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 55, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[-6]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-6]", key); + Assert.assertEquals(values.get(0).getValue(), 1, key); + // 设置值 + values.get(0).setValue(11); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 11, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[+7]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[+7]", key); + Assert.assertNull(values.get(0).getValue(), key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[-7]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-7]", key); + Assert.assertNull(values.get(0).getValue(), key); + } + } + + @Test + public void testFindLastListIndex12() { + { + Map object = new HashMap<>(); + object.put("data", new int[] { 1,2,3,4,5,6 }); String key = "data[0]"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[0]", key); Assert.assertEquals(values.get(0).getValue(), 1, key); + // 设置值 + values.get(0).setValue(11); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 11, key); } { + Map object = new HashMap<>(); + object.put("data", new int[] { 1,2,3,4,5,6 }); String key = "data[5]"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[5]", key); Assert.assertEquals(values.get(0).getValue(), 6, key); + // 设置值 + values.get(0).setValue(66); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 66, key); } { + Map object = new HashMap<>(); + object.put("data", new int[] { 1,2,3,4,5,6 }); String key = "data[-1]"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-1]", key); Assert.assertEquals(values.get(0).getValue(), 6, key); + // 设置值 + values.get(0).setValue(66); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 66, key); } { + Map object = new HashMap<>(); + object.put("data", new int[] { 1,2,3,4,5,6 }); String key = "data[-2]"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-2]", key); Assert.assertEquals(values.get(0).getValue(), 5, key); + // 设置值 + values.get(0).setValue(55); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 55, key); } { + Map object = new HashMap<>(); + object.put("data", new int[] { 1,2,3,4,5,6 }); String key = "data[-6]"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-6]", key); Assert.assertEquals(values.get(0).getValue(), 1, key); + // 设置值 + values.get(0).setValue(11); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 11, key); } { + Map object = new HashMap<>(); + object.put("data", new int[] { 1,2,3,4,5,6 }); String key = "data[+7]"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[+7]", key); Assert.assertNull(values.get(0).getValue(), key); } { + Map object = new HashMap<>(); + object.put("data", new int[] { 1,2,3,4,5,6 }); String key = "data[-7]"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-7]", key); + Assert.assertNull(values.get(0).getValue(), key); + } + } + + @Test + public void testFindLastListIndex21() { + String json = "{data:[[1,2,3,4,5,6],[7,8,9,0]]}"; + System.out.println(json); + { + Object object = JsonTools.parseAsMap(json); + String key = "data"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "data", key); + Object value = values.get(0).getValue(); + Assert.assertTrue(value instanceof List, key); + Assert.assertEquals(((List)value).size(), 2, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[0]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[0]", key); + Object value = values.get(0).getValue(); + Assert.assertTrue(value instanceof List, key); + Assert.assertEquals(((List)value).size(), 6, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[0][0]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[0]", key); + Assert.assertEquals(values.get(0).getValue(), 1, key); + // 设置值 + values.get(0).setValue(11); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 11, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[0][5]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[5]", key); + Assert.assertEquals(values.get(0).getValue(), 6, key); + // 设置值 + values.get(0).setValue(66); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 66, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[0][-1]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-1]", key); + Assert.assertEquals(values.get(0).getValue(), 6, key); + // 设置值 + values.get(0).setValue(66); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 66, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[0][-2]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-2]", key); + Assert.assertEquals(values.get(0).getValue(), 5, key); + // 设置值 + values.get(0).setValue(55); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 55, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[0][-6]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-6]", key); + Assert.assertEquals(values.get(0).getValue(), 1, key); + // 设置值 + values.get(0).setValue(11); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 11, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[0][+7]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[+7]", key); + Assert.assertNull(values.get(0).getValue(), key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[0][-7]"; + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-7]", key); Assert.assertNull(values.get(0).getValue(), key); } } -- Gitee From 5e9529ae9928a19950e883d766d2485a15d54803 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 28 May 2023 23:26:22 +0800 Subject: [PATCH 05/54] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/resources/settings/i18n/ResultCode_zh_CN.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties b/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties index ce93a70..8ccb692 100644 --- a/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties +++ b/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties @@ -19,4 +19,4 @@ FORBIDDEN = 没有权限 ACCESS_DENIED = 访问被拒绝 OPERATE_TIMEOUT = 操作已超时 SYSTEM_CONFIG_ERROR = 系统配置错误 -UNSUPPORTED_OPERATION = 暂不支持该操作 +UNSUPPORTED_OPERATION = 不支持该操作 -- Gitee From fe7fe05238b0e00d38990ea6ba145e6b6b726af5 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 28 May 2023 23:31:35 +0800 Subject: [PATCH 06/54] =?UTF-8?q?5.6.0,=20=E7=89=88=E6=9C=AC=E5=8D=87?= =?UTF-8?q?=E7=BA=A7,=20MapTools.each/ReflectTools.findDepthValues?= =?UTF-8?q?=E4=B8=8D=E5=85=BC=E5=AE=B9=E6=97=A7=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- able/pom.xml | 2 +- json/pom.xml | 4 ++-- test/pom.xml | 2 +- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- tools/pom.xml | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index bbd0d0a..607f591 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.5.15 + 5.6.0 ``` ```xml com.gitee.qdbp qdbp-tools - 5.5.15 + 5.6.0 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index c80e177..40c3dcd 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.5.15 + 5.6.0 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ diff --git a/json/pom.xml b/json/pom.xml index 6ef795c..551c81c 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.5.15 + 5.6.0 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.5.15 + 5.6.0 diff --git a/test/pom.xml b/test/pom.xml index e0c3828..01b64b0 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.5.15 + 5.6.0 https://gitee.com/qdbp/qdbp-able/ qdbp json test diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index 7ca5221..336526e 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.15 + 5.6.0 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index 8aa4fcc..e60ff7c 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.15 + 5.6.0 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index 55df0db..073d4f4 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.15 + 5.6.0 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index 3b7215f..582ae0b 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.15 + 5.6.0 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index ecebe93..d526484 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.15 + 5.6.0 qdbp-tools-test-jdk7 diff --git a/tools/pom.xml b/tools/pom.xml index 057e332..8b849d1 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.5.15 + 5.6.0 https://gitee.com/qdbp/qdbp-able/ qdbp tools library -- Gitee From 20afc5842454589946296ad5fb0ce123aad798ab Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 31 May 2023 22:46:50 +0800 Subject: [PATCH 07/54] =?UTF-8?q?=E4=BF=AE=E6=94=B9idea=E8=AD=A6=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/gitee/qdbp/tools/utils/ConvertTools.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java index a6e6af2..433a81e 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java @@ -3,6 +3,7 @@ package com.gitee.qdbp.tools.utils; import java.lang.reflect.Array; import java.math.BigDecimal; import java.math.BigInteger; +import java.math.RoundingMode; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.time.Instant; @@ -482,7 +483,7 @@ public class ConvertTools { } BigDecimal value = clearTrailingZeros(number); if (value.scale() > maxScale) { - value = value.setScale(maxScale, BigDecimal.ROUND_HALF_UP); + value = value.setScale(maxScale, RoundingMode.HALF_UP); value = clearTrailingZeros(value); } if (expect == BigDecimal.class) { @@ -573,7 +574,7 @@ public class ConvertTools { // new BigDecimal(20000).stripTrailingZeros(); = 2E+4 (科学计数法) // 此时precision=1,scale=-4; 需要将scale设置为0 if (number.scale() < 0) { - number = number.setScale(0, BigDecimal.ROUND_HALF_UP); + number = number.setScale(0, RoundingMode.HALF_UP); } return number; } -- Gitee From 74323ee5985b3b57e1b4670c75b2cb6f43eaa62e Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Thu, 1 Jun 2023 00:06:36 +0800 Subject: [PATCH 08/54] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=BD=AC=E6=8D=A2?= =?UTF-8?q?=E4=B8=BA=E6=A0=91=E5=BD=A2=E6=95=B0=E6=8D=AE=E7=9A=84=E9=80=9A?= =?UTF-8?q?=E7=94=A8=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/able/beans/TreeNodes.java | 66 ++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/able/src/main/java/com/gitee/qdbp/able/beans/TreeNodes.java b/able/src/main/java/com/gitee/qdbp/able/beans/TreeNodes.java index 7252722..53ee1e4 100644 --- a/able/src/main/java/com/gitee/qdbp/able/beans/TreeNodes.java +++ b/able/src/main/java/com/gitee/qdbp/able/beans/TreeNodes.java @@ -9,6 +9,7 @@ import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; import com.gitee.qdbp.able.function.BaseFunction; +import com.gitee.qdbp.able.function.BinaryConsumer; import com.gitee.qdbp.tools.utils.VerifyTools; /** @@ -32,7 +33,8 @@ public class TreeNodes { this(list, false, keyGetter, parentGetter); } - public TreeNodes(List list, boolean upgrade, BaseFunction keyGetter, BaseFunction parentGetter) { + public TreeNodes(List list, boolean upgrade, BaseFunction keyGetter, + BaseFunction parentGetter) { Node container = new Node<>(null); String rootCode = "0"; List> all = new ArrayList<>(); @@ -172,6 +174,24 @@ public class TreeNodes { return this.keysOfWithoutParent; } + /** + * 转换为树形数据, 即从code+parent形式的平行列表转换为element+children形式的树形层级结构
+ * 使用方式:
+ * TreeNodes<TreeNode> tree = new TreeNodes<>(beans, TreeNode::getCode, TreeNode::getParent);
+ * List<TreeNode> list = tree.toTreeList(TreeNode::setChildren);
+ * + * @param childSetter 子节点设置方法 + * @return 树形数据的根节点 + */ + public List toTreeList(BinaryConsumer> childSetter) { + List list = new ArrayList<>(); + for (Node child : container.children) { + child.fillAllChildren(childSetter); + list.add(child.element); + } + return list; + } + /** 广度优先遍历 **/ public Iterator breadthFirstIterator() { return container.breadthFirstElementIterator(); @@ -182,6 +202,30 @@ public class TreeNodes { return container.depthFirstElementIterator(); } + /** + * 转换为树形数据, 即从code+parent形式的平行列表转换为element+children形式的树形层级结构
+ * 使用方式:
+ * List<TreeNode> list = TreeNodes.toTreeList(beans,
+ *         TreeNode::getCode, TreeNode::getParent, TreeNode::setChildren);
+ * + * @param list 原始列表 + * @param keyGetter KEY的获取方法 + * @param parentGetter 上级的获取方法 + * @param childSetter 子级的设置方法 + * @return 树形数据列表 + * @param 数据类型 + */ + public static List toTreeList(List list, BaseFunction keyGetter, + BaseFunction parentGetter, BinaryConsumer> childSetter) { + return toTreeList(list, false, keyGetter, parentGetter, childSetter); + } + + public static List toTreeList(List list, boolean upgrade, BaseFunction keyGetter, + BaseFunction parentGetter, BinaryConsumer> childSetter) { + TreeNodes tree = new TreeNodes<>(list, upgrade, keyGetter, parentGetter); + return tree.toTreeList(childSetter); + } + public static class Node { /** 本级 **/ @@ -300,6 +344,26 @@ public class TreeNodes { return new DepthFirstNodeIterator<>(this); } + /** 设置所有后代元素的Children属性 **/ + public void fillAllChildren(BinaryConsumer> childSetter) { + Iterator> iterator = this.depthFirstNodeIterator(); + List myChildren = new ArrayList<>(); + while (iterator.hasNext()) { + Node node = iterator.next(); + if (node.parent == this) { + myChildren.add(node.element); + } else { + List> children = node.children; + List temp = new ArrayList<>(); + for (Node child : children) { + temp.add(child.element); + } + childSetter.accept(node.element, temp); + } + } + childSetter.accept(this.element, myChildren); + } + @Override public String toString() { return element == null ? "{root}" : element.toString(); -- Gitee From 5205438162efd748c6ec520cb5be3d344268464b Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Thu, 1 Jun 2023 00:07:14 +0800 Subject: [PATCH 09/54] =?UTF-8?q?=E6=A0=91=E5=BD=A2=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/able/beans/TreeNode.java | 55 +++++++ .../gitee/qdbp/able/beans/TreeNodesTest.java | 135 ++++++++++++++++-- 2 files changed, 180 insertions(+), 10 deletions(-) create mode 100644 tools/src/test/java/com/gitee/qdbp/able/beans/TreeNode.java diff --git a/tools/src/test/java/com/gitee/qdbp/able/beans/TreeNode.java b/tools/src/test/java/com/gitee/qdbp/able/beans/TreeNode.java new file mode 100644 index 0000000..79490ac --- /dev/null +++ b/tools/src/test/java/com/gitee/qdbp/able/beans/TreeNode.java @@ -0,0 +1,55 @@ +package com.gitee.qdbp.able.beans; + +import java.util.List; +import java.util.Objects; +import com.gitee.qdbp.tools.utils.VerifyTools; + +class TreeNode { + + private String code; + + private List children; + + public TreeNode() { + } + + public TreeNode(String code) { + this.code = code; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getParent() { + return TreeNodesTest.codeTools.parent(code); + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } + + @Override + public boolean equals(Object other) { + return other instanceof TreeNode && VerifyTools.equals(this.code, ((TreeNode) other).code); + } + + @Override + public int hashCode() { + return Objects.hashCode(this.code); + } + + @Override + public String toString() { + return this.code; + } + +} diff --git a/tools/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java b/tools/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java index 30ed780..244ba30 100644 --- a/tools/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java +++ b/tools/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java @@ -20,33 +20,33 @@ import com.gitee.qdbp.tools.utils.StringTools; @Test public class TreeNodesTest { - private static final CodeTools codeTools = new CodeTools(1, 2); + static final CodeTools codeTools = new CodeTools(1, 2); - public void test() { + public void test1() { List list = generateTestData(); - TreeNodes container = new TreeNodes<>(list, true, new KeyGetter(), new ParentGetter()); + TreeNodes tree = new TreeNodes<>(list, new KeyGetter(), new ParentGetter()); - List rootElements = container.getRootElements(); + List rootElements = tree.getRootElements(); AssertTools.assertDeepEquals(rootElements, Arrays.asList("T01", "T02", "T03")); - List t01Children = container.findChildElements("T02"); + List t01Children = tree.findChildElements("T02"); AssertTools.assertDeepEquals(t01Children, Arrays.asList("T0201", "T0202", "T0203")); - List t020304Children = container.findChildElements("T020304"); + List t020304Children = tree.findChildElements("T020304"); Assert.assertEquals(t020304Children.size(), 0); - List t020304Ancestors = container.findAllAncestorElements("T020304"); + List t020304Ancestors = tree.findAllAncestorElements("T020304"); AssertTools.assertDeepEquals(t020304Ancestors, Arrays.asList("T02", "T0203")); - List t02Descendants = container.findAllDescendantElements("T02"); + List t02Descendants = tree.findAllDescendantElements("T02"); AssertTools.assertDeepEquals(t02Descendants, Arrays.asList( "T0201", "T020101", "T020102", "T020103", "T020104", "T0202", "T020201", "T020202", "T020203", "T020204", "T0203", "T020301", "T020302", "T020303", "T020304")); { // 深度优先遍历 - TreeNodes.Node t01Node = container.findNode("T01"); + TreeNodes.Node t01Node = tree.findNode("T01"); Iterator> t01NodeIterator = t01Node.depthFirstNodeIterator(); while (t01NodeIterator.hasNext()) { TreeNodes.Node next = t01NodeIterator.next(); @@ -76,7 +76,7 @@ public class TreeNodesTest { } { // 广度优先遍历 - TreeNodes.Node t03Node = container.findNode("T03"); + TreeNodes.Node t03Node = tree.findNode("T03"); Iterator> t03NodeIterator = t03Node.depthFirstNodeIterator(); while (t03NodeIterator.hasNext()) { TreeNodes.Node next = t03NodeIterator.next(); @@ -106,6 +106,121 @@ public class TreeNodesTest { } } + public void test2() { + List beans = generateNodeData(); + TreeNodes tree = new TreeNodes<>(beans, true, + TreeNode::getCode, TreeNode::getParent); + + List rootElements = tree.getRootElements(); + AssertTools.assertDeepEquals(rootElements, asTreeNodeList("T01", "T02", "T03")); + + List t01Children = tree.findChildElements("T02"); + AssertTools.assertDeepEquals(t01Children, asTreeNodeList("T0201", "T0202", "T0203")); + + List t020304Children = tree.findChildElements("T020304"); + Assert.assertEquals(t020304Children.size(), 0); + + List t020304Ancestors = tree.findAllAncestorElements("T020304"); + AssertTools.assertDeepEquals(t020304Ancestors, asTreeNodeList("T02", "T0203")); + + List t02Descendants = tree.findAllDescendantElements("T02"); + AssertTools.assertDeepEquals(t02Descendants, asTreeNodeList( + "T0201", "T020101", "T020102", "T020103", "T020104", + "T0202", "T020201", "T020202", "T020203", "T020204", + "T0203", "T020301", "T020302", "T020303", "T020304")); + + { // 深度优先遍历 + TreeNodes.Node t01Node = tree.findNode("T01"); + Iterator> t01NodeIterator = t01Node.depthFirstNodeIterator(); + while (t01NodeIterator.hasNext()) { + TreeNodes.Node next = t01NodeIterator.next(); + TreeNode element = next.getElement(); + String nodeCode = element.getCode(); + if (nodeCode.endsWith("04")) { + String newCode = StringTools.replaceSuffix(nodeCode, "05"); + next.getParentNode().addChildElement(new TreeNode(newCode)); + } + } + List t01Descendants = t01Node.getAllDescendantElements(); + AssertTools.assertDeepEquals(t01Descendants, asTreeNodeList( + "T0101", "T010101", "T010102", "T010103", "T010104", "T010105", + "T0102", "T010201", "T010202", "T010203", "T010204", "T010205", + "T0103", "T010301", "T010302", "T010303", "T010304", "T010305")); + + Iterator> t01NodeIterator2 = t01Node.depthFirstNodeIterator(); + while (t01NodeIterator2.hasNext()) { + TreeNodes.Node next = t01NodeIterator2.next(); + TreeNode element = next.getElement(); + String nodeCode = element.getCode(); + if (nodeCode.contains("02")) { + t01NodeIterator2.remove(); + } + } + List t01Descendants2 = t01Node.getAllDescendantElements(); + AssertTools.assertDeepEquals(t01Descendants2, asTreeNodeList( + "T0101", "T010101", "T010103", "T010104", "T010105", + "T0103", "T010301", "T010303", "T010304", "T010305")); + } + + { // 广度优先遍历 + TreeNodes.Node t03Node = tree.findNode("T03"); + Iterator> t03NodeIterator = t03Node.depthFirstNodeIterator(); + while (t03NodeIterator.hasNext()) { + TreeNodes.Node next = t03NodeIterator.next(); + TreeNode element = next.getElement(); + String nodeCode = element.getCode(); + if (nodeCode.endsWith("04")) { + String newCode = StringTools.replaceSuffix(nodeCode, "05"); + next.getParentNode().addChildElement(new TreeNode(newCode)); + } + } + List t03Descendants = t03Node.getAllDescendantElements(); + AssertTools.assertDeepEquals(t03Descendants, asTreeNodeList( + "T0301", "T030101", "T030102", "T030103", "T030104", "T030105", + "T0302", "T030201", "T030202", "T030203", "T030204", "T030205", + "T0303", "T030301", "T030302", "T030303", "T030304", "T030305")); + + Iterator> t03NodeIterator2 = t03Node.depthFirstNodeIterator(); + while (t03NodeIterator2.hasNext()) { + TreeNodes.Node next = t03NodeIterator2.next(); + TreeNode element = next.getElement(); + String nodeCode = element.getCode(); + if (nodeCode.contains("02")) { + t03NodeIterator2.remove(); + } + } + List t03Descendants2 = t03Node.getAllDescendantElements(); + AssertTools.assertDeepEquals(t03Descendants2, asTreeNodeList( + "T0301", "T030101", "T030103", "T030104", "T030105", + "T0303", "T030301", "T030303", "T030304", "T030305")); + } + } + + + public void test3() { + List beans = generateNodeData(); + TreeNodes tree = new TreeNodes<>(beans, TreeNode::getCode, TreeNode::getParent); + List treeList = tree.toTreeList(TreeNode::setChildren); + AssertTools.assertDeepEquals(treeList, asTreeNodeList("T01", "T02", "T03")); + } + + private List generateNodeData() { + List list = generateTestData(); + List beans = new ArrayList<>(); + for (String item : list) { + beans.add(new TreeNode(item)); + } + return beans; + } + + private List asTreeNodeList(String ... codes) { + List beans = new ArrayList<>(); + for (String item : codes) { + beans.add(new TreeNode(item)); + } + return beans; + } + private List generateTestData() { List list = new ArrayList<>(); for (int i = 1; i <= 3; i++) { -- Gitee From 0d31ce62c67ddb436bda8c97b93013d29d21fe1b Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Thu, 1 Jun 2023 00:16:51 +0800 Subject: [PATCH 10/54] ConvertTools.copyObject --- .../gitee/qdbp/tools/utils/ConvertTools.java | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java index 433a81e..05a4177 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java @@ -22,11 +22,15 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TimeZone; +import java.util.TreeSet; +import com.gitee.qdbp.able.beans.Copyable; +import com.gitee.qdbp.tools.beans.MapPlus; /** * 格式转换工具 @@ -1669,4 +1673,82 @@ public class ConvertTools { LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone); return localDateTime.toLocalTime(); } + + /** + * 复制对象
+ * 调用Copyable的copy()方法进行复制
+ * List/Set/Map容器将会循环递归复制其中的内容
+ * + * @param value 原对象 + * @return 复制后的对象 + * @throws IllegalArgumentException 如果value既不是原生对象也不是容器对象, 又没有实现Copyable接口, 将会抛出异常 + * @param 对象类型 + */ + public static T copyObject(T value) { + T result = doCopyObject(value); + if (result != null && result == value) { + if (value instanceof Copyable || ReflectTools.isPrimitive(value.getClass(), false)) { + return result; + } else { + // 如果不是原生对象又没有实现Copyable接口, 就抛出异常 + throw new IllegalArgumentException("Cannot copy object that do not implement the 'Copyable' interface"); + } + } + return result; + } + + @SuppressWarnings("unchecked") + private static T doCopyObject(T value) { + if (value == null) { + return null; + } + if (value instanceof Copyable) { + return (T) ((Copyable) value).copy(); + } + if (value instanceof List) { + List older = (List) value; + List newer = new ArrayList<>(); + for (Object o : older) { + newer.add(doCopyObject(o)); + } + return (T) newer; + } + if (value instanceof Set) { + Set newer; + if (value instanceof TreeSet) { + newer = new TreeSet<>(); + } else if (value instanceof LinkedHashSet) { + newer = new LinkedHashSet<>(); + } else { + newer = new HashSet<>(); + } + Set older = (Set) value; + for (Object o : older) { + newer.add(doCopyObject(o)); + } + return (T) newer; + } + if (value instanceof MapPlus) { + MapPlus newer = new MapPlus(); + MapPlus older = (MapPlus) value; + for (Map.Entry entry : older.entrySet()) { + newer.put(entry.getKey(), doCopyObject(entry.getValue())); + } + return (T) newer; + } + if (value instanceof Map) { + Map newer; + if (value instanceof LinkedHashMap) { + newer = new LinkedHashMap<>(); + } else { + newer = new HashMap<>(); + } + Map older = (Map) value; + for (Map.Entry entry : older.entrySet()) { + newer.put(entry.getKey(), doCopyObject(entry.getValue())); + } + return (T) newer; + } + return value; + } } -- Gitee From bf539cf4417b5e108fa090d56a2d7de88580437e Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Thu, 1 Jun 2023 00:19:58 +0800 Subject: [PATCH 11/54] 5.6.230531 --- README.md | 4 ++-- able/pom.xml | 2 +- json/pom.xml | 4 ++-- test/pom.xml | 2 +- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- tools/pom.xml | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 607f591..8617ca2 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.6.0 + 5.6.230531 ``` ```xml com.gitee.qdbp qdbp-tools - 5.6.0 + 5.6.230531 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index 40c3dcd..e54323f 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.6.0 + 5.6.230531 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ diff --git a/json/pom.xml b/json/pom.xml index 551c81c..f9e6e39 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.6.0 + 5.6.230531 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.6.0 + 5.6.230531 diff --git a/test/pom.xml b/test/pom.xml index 01b64b0..a12e98c 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.6.0 + 5.6.230531 https://gitee.com/qdbp/qdbp-able/ qdbp json test diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index 336526e..96c8631 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.0 + 5.6.230531 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index e60ff7c..935654e 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.0 + 5.6.230531 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index 073d4f4..33e7325 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.0 + 5.6.230531 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index 582ae0b..0b110e3 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.0 + 5.6.230531 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index d526484..4271084 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.0 + 5.6.230531 qdbp-tools-test-jdk7 diff --git a/tools/pom.xml b/tools/pom.xml index 8b849d1..e20e132 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.6.0 + 5.6.230531 https://gitee.com/qdbp/qdbp-able/ qdbp tools library -- Gitee From f9670f0878a738e304a6a81acc2646eb2cdd5015 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 18 Jun 2023 23:42:40 +0800 Subject: [PATCH 12/54] =?UTF-8?q?eachMap=E5=A2=9E=E5=8A=A0isCollection?= =?UTF-8?q?=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/able/model/entry/EntryItem.java | 3 +++ .../gitee/qdbp/able/model/entry/ListEntryItem.java | 5 +++++ .../com/gitee/qdbp/able/model/entry/MapEntryItem.java | 5 +++++ .../gitee/qdbp/able/model/entry/ObjectEntryItem.java | 5 +++++ .../gitee/qdbp/able/model/entry/ObjectsEntryItem.java | 5 +++++ .../qdbp/able/model/entry/ReadonlyEntryItem.java | 11 +++++++++-- tools/pom.xml | 2 +- 7 files changed, 33 insertions(+), 3 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/EntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/EntryItem.java index ae742bb..f8751fe 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/EntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/EntryItem.java @@ -18,6 +18,9 @@ public interface EntryItem { /** 名称, path的最后一段, 如 [1] **/ String getName(); + /** 是不是集合对象 **/ + boolean isCollection(); + /** 值 **/ Object getValue(); diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java index 64f9cd8..fd74a73 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java @@ -21,6 +21,11 @@ public class ListEntryItem extends BaseEntryItem { this.list = list; } + @Override + public boolean isCollection() { + return true; + } + public ListEntryItem init(String path, String name, int index, Object value) { super.init(path, name, value); this.index = index; diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java index 05df397..9a243fb 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java @@ -17,6 +17,11 @@ public class MapEntryItem extends BaseEntryItem { this.map = map; } + @Override + public boolean isCollection() { + return false; + } + public MapEntryItem init(String key, String name, Object value) { super.init(key, name, value); return this; diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java index f495dee..c7b7c68 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java @@ -19,6 +19,11 @@ public class ObjectEntryItem extends BaseEntryItem { this.object = object; } + @Override + public boolean isCollection() { + return false; + } + public ObjectEntryItem init(String key, String name, Object value) { super.init(key, name, value); return this; diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java index 32fe937..d2ad533 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java @@ -18,6 +18,11 @@ public class ObjectsEntryItem extends BaseEntryItem { this.object = object; } + @Override + public boolean isCollection() { + return true; + } + public ObjectsEntryItem init(String path, String name, int index, Object value) { super.init(path, name, value); this.index = index; diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java index 232e158..d06902b 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java @@ -14,8 +14,16 @@ public class ReadonlyEntryItem extends BaseEntryItem { private final Object object; - public ReadonlyEntryItem(Object object) { + private final boolean isCollection; + + public ReadonlyEntryItem(Object object, boolean isCollection) { this.object = object; + this.isCollection = isCollection; + } + + @Override + public boolean isCollection() { + return isCollection; } public ReadonlyEntryItem init(String key, String name, Object value) { @@ -29,5 +37,4 @@ public class ReadonlyEntryItem extends BaseEntryItem { throw new ServiceException(ResultCode.UNSUPPORTED_OPERATION) .setDetails("Cannot set field value for " + className + ", --> " + key); } - } \ No newline at end of file diff --git a/tools/pom.xml b/tools/pom.xml index e20e132..4da9f84 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.6.230531 + 5.6.230618 https://gitee.com/qdbp/qdbp-able/ qdbp tools library -- Gitee From ad31d6541fdabcbe97c5e30ac1f039167e48bc1c Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 18 Jun 2023 23:43:15 +0800 Subject: [PATCH 13/54] =?UTF-8?q?eachMap=E5=A2=9E=E5=8A=A0isCollection?= =?UTF-8?q?=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/tools/utils/ReflectTools.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java index a22f2d9..69ce971 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java @@ -390,7 +390,7 @@ public abstract class ReflectTools { for (Object item : iterable) { String name = "[" + (i++) + "]"; String path = concatFieldPaths(parentPath, realFieldName, name); - results.add(new ReadonlyEntryItem(iterable).init(path, name, item)); + results.add(new ReadonlyEntryItem(iterable, true).init(path, name, item)); } } else if (fieldValue instanceof Iterator) { Iterator iterator = (Iterator) fieldValue; @@ -398,7 +398,8 @@ public abstract class ReflectTools { while (iterator.hasNext()) { String name = "[" + (i++) + "]"; String path = concatFieldPaths(parentPath, realFieldName, name); - results.add(new ReadonlyEntryItem(iterator).init(path, name, iterator.next())); + Object next = iterator.next(); + results.add(new ReadonlyEntryItem(iterator, true).init(path, name, next)); } } else if (fieldValue instanceof Enumeration) { Enumeration enumeration = (Enumeration) fieldValue; @@ -406,7 +407,8 @@ public abstract class ReflectTools { while (enumeration.hasMoreElements()) { String name = "[" + (i++) + "]"; String path = concatFieldPaths(parentPath, realFieldName, name); - results.add(new ReadonlyEntryItem(enumeration).init(path, name, enumeration.nextElement())); + Object next = enumeration.nextElement(); + results.add(new ReadonlyEntryItem(enumeration, true).init(path, name, next)); } } else { results.add(newObjectEntryItem(parent, parentPath, parentList, fieldName, fieldValue)); @@ -419,6 +421,7 @@ public abstract class ReflectTools { private static EntryItem newObjectEntryItem(Object parent, String parentPath, boolean parentList, String fieldName, Object fieldValue) { if (!parentList) { + // 上级不是list String path = concatFieldPaths(parentPath, fieldName); if (parent instanceof Map) { return new MapEntryItem((Map) parent).init(path, fieldName, fieldValue); @@ -426,6 +429,7 @@ public abstract class ReflectTools { return new ObjectEntryItem(parent).init(path, fieldName, fieldValue); } } else { + // 上级是list, fieldName就应该是序号, 可以解析为数字 Integer index = ConvertTools.toInteger(fieldName, null); String name = "[" + fieldName + "]"; String path = concatFieldPaths(parentPath, name); @@ -434,7 +438,7 @@ public abstract class ReflectTools { } else if (index != null && parent.getClass().isArray()) { return new ObjectsEntryItem(parent).init(path, name, index, fieldValue); } else { - return new ReadonlyEntryItem(parent).init(path, name, fieldValue); + return new ReadonlyEntryItem(parent, true).init(path, name, fieldValue); } } } -- Gitee From fea29f5c3f97edffa2f4d77c82eb4a8c60a6b28d Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 18 Jun 2023 23:43:51 +0800 Subject: [PATCH 14/54] =?UTF-8?q?ReflectTools=E5=A2=9E=E5=8A=A0findMethods?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/tools/utils/ReflectTools.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java index 69ce971..07851a8 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java @@ -1102,6 +1102,56 @@ public abstract class ReflectTools { return buffer.toString(); } + /** + * 查找类的所有方法 + * + * @param clazz 类 + * @return 方法列表 + */ + public static List findAllMethods(Class clazz) { + return doFindMethods(clazz, null); + } + + /** + * 按方法名查找方法对象 + * + * @param clazz 类 + * @param methodName 方法名 + * @return 方法列表 + */ + public static List findMethods(Class clazz, String methodName) { + return doFindMethods(clazz, methodName); + } + + private static List doFindMethods(Class clazz, String methodName) { + List result = new ArrayList<>(); + Class temp = clazz; + while (temp != null && temp != Object.class) { + Method[] declaredMethods = temp.getDeclaredMethods(); + List methods = new ArrayList<>(); + for (Method method : declaredMethods) { + if (Modifier.isStatic(method.getModifiers())) { + continue; // 去掉静态方法 + } + if (Modifier.isAbstract(method.getModifiers())) { + continue; // 去掉抽象方法 + } + if (!Modifier.isPublic(method.getModifiers())) { + continue; // 去掉非公开的方法 + } + if (methodName == null || methodName.equals(method.getName())) { + methods.add(method); + } + } + if (!methods.isEmpty()) { + // 父类字段放在前面 + result.addAll(0, methods); + } + temp = temp.getSuperclass(); + } + return result; + } + /** * 查找无参数的方法 * -- Gitee From e6a1bd710b2315ebb6c72867adb5b6af8628e022 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 18 Jun 2023 23:46:27 +0800 Subject: [PATCH 15/54] =?UTF-8?q?ConvertTools=E7=9A=84toList=E4=BC=98?= =?UTF-8?q?=E5=8C=96=20/=20copyObject=E9=87=8D=E5=91=BD=E5=90=8D=E4=B8=BAd?= =?UTF-8?q?eepCopyObject?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/tools/utils/ConvertTools.java | 53 ++++++++++++------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java index 05a4177..27510b5 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java @@ -216,13 +216,15 @@ public class ConvertTools { * @return 转换后的List, 如果array=null将返回空List */ @SafeVarargs + @SuppressWarnings("all") public static List toList(C... array) { if (array == null) { return new ArrayList<>(); } else { - // JDK1.7必须强转, JDK1.8不需要 - @SuppressWarnings("all") - List temp = (List) new ArrayList<>(Arrays.asList(array)); + List temp = new ArrayList<>(); + for (C item : array) { + temp.add(item); + } return temp; } } @@ -251,14 +253,16 @@ public class ConvertTools { * @return 转换后的Set, 如果array=null将返回空Set */ @SafeVarargs - @SuppressWarnings("unchecked") + @SuppressWarnings("all") public static Set toSet(C... array) { if (array == null) { return new HashSet<>(); } else { - Set list = new HashSet<>(Arrays.asList(array)); - // JDK1.7必须强转, JDK1.8不需要 - return (Set) list; + Set temp = new LinkedHashSet<>(); + for (C item : array) { + temp.add(item); + } + return temp; } } @@ -285,7 +289,7 @@ public class ConvertTools { * @return Map */ public static Map toKeyMaps(String... keys) { - Map map = new HashMap<>(); + Map map = new LinkedHashMap<>(); if (keys != null) { for (String item : keys) { String[] array = StringTools.split(item, ','); @@ -304,8 +308,9 @@ public class ConvertTools { * @param strings KEY * @return Map */ + @SuppressWarnings("all") public static Map toCharMaps(String... strings) { - Map map = new HashMap<>(); + Map map = new LinkedHashMap<>(); if (strings != null) { for (String string : strings) { char[] chars = string.toCharArray(); @@ -347,9 +352,9 @@ public class ConvertTools { @SuppressWarnings("unchecked") public static Map toMap(Collection array, V value) { if (array == null) { - return new HashMap<>(); + return new LinkedHashMap<>(); } else { - Map map = new HashMap<>(); + Map map = new LinkedHashMap<>(); for (C field : array) { map.put(field, value); } @@ -1675,7 +1680,17 @@ public class ConvertTools { } /** - * 复制对象
+ * 深度复制对象 + * + * @deprecated 修改方法名, 此方法名不能描述功能, 改为 {@linkplain #deepCopyObject(Object)} + */ + @Deprecated + public static T copyObject(T value) { + return deepCopyObject(value); + } + + /** + * 深度复制对象
* 调用Copyable的copy()方法进行复制
* List/Set/Map容器将会循环递归复制其中的内容
* @@ -1684,8 +1699,8 @@ public class ConvertTools { * @throws IllegalArgumentException 如果value既不是原生对象也不是容器对象, 又没有实现Copyable接口, 将会抛出异常 * @param 对象类型 */ - public static T copyObject(T value) { - T result = doCopyObject(value); + public static T deepCopyObject(T value) { + T result = doDeepCopyObject(value); if (result != null && result == value) { if (value instanceof Copyable || ReflectTools.isPrimitive(value.getClass(), false)) { return result; @@ -1698,7 +1713,7 @@ public class ConvertTools { } @SuppressWarnings("unchecked") - private static T doCopyObject(T value) { + private static T doDeepCopyObject(T value) { if (value == null) { return null; } @@ -1709,7 +1724,7 @@ public class ConvertTools { List older = (List) value; List newer = new ArrayList<>(); for (Object o : older) { - newer.add(doCopyObject(o)); + newer.add(doDeepCopyObject(o)); } return (T) newer; } @@ -1724,7 +1739,7 @@ public class ConvertTools { } Set older = (Set) value; for (Object o : older) { - newer.add(doCopyObject(o)); + newer.add(doDeepCopyObject(o)); } return (T) newer; } @@ -1732,7 +1747,7 @@ public class ConvertTools { MapPlus newer = new MapPlus(); MapPlus older = (MapPlus) value; for (Map.Entry entry : older.entrySet()) { - newer.put(entry.getKey(), doCopyObject(entry.getValue())); + newer.put(entry.getKey(), doDeepCopyObject(entry.getValue())); } return (T) newer; } @@ -1745,7 +1760,7 @@ public class ConvertTools { } Map older = (Map) value; for (Map.Entry entry : older.entrySet()) { - newer.put(entry.getKey(), doCopyObject(entry.getValue())); + newer.put(entry.getKey(), doDeepCopyObject(entry.getValue())); } return (T) newer; } -- Gitee From bf1053d7332e0a14b4ecfb2136d44343b75597ca Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 18 Jun 2023 23:47:24 +0800 Subject: [PATCH 16/54] =?UTF-8?q?=E5=A2=9E=E5=8A=A0isCollection/isPlainObj?= =?UTF-8?q?ect=E5=88=A4=E6=96=AD=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/tools/utils/VerifyTools.java | 46 ++++++++++++++++++- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java index 3baab94..d233f8a 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java @@ -3,6 +3,7 @@ package com.gitee.qdbp.tools.utils; import java.lang.reflect.Array; import java.util.Collection; import java.util.Enumeration; +import java.util.Iterator; import java.util.Map; import com.gitee.qdbp.able.exception.ServiceException; import com.gitee.qdbp.able.result.ResultCode; @@ -165,7 +166,7 @@ public class VerifyTools { * @return 是否全都为空 */ public static boolean isAllBlank(Object... objects) { - if (objects == null || objects.length == 0) { + if (objects == null) { return true; } @@ -188,6 +189,47 @@ public class VerifyTools { return !isAnyBlank(objects); } + /** + * 判断是不是集合对象, 能转换为list就是集合对象 + * + * @param object 目标对象 + * @return 是否集合对象 + * @see ConvertTools#parseList(Object) + */ + public static boolean isCollection(Object object) { + if (object == null) { + return false; + } else if (object.getClass().isArray()) { + return true; + } else if (object instanceof Collection) { + return true; + } else if (object instanceof Iterator) { + return true; + } else if (object instanceof Iterable) { + return true; + } else if (object instanceof Enumeration) { + return true; + } else { + return false; + } + } + + /** + * 判断是不是普通对象, 能转换为map就是普通对象, 不能是原始类型也不能是列表 + * + * @param object 目标对象 + * @return 是否普通对象 + */ + public static boolean isPlainObject(Object object) { + if (object == null) { + return false; + } else if (ReflectTools.isPrimitive(object.getClass(), false)) { + return false; + } else { + return !isCollection(object); + } + } + /** * 判断对象是否存在于列表中 * @@ -197,7 +239,7 @@ public class VerifyTools { */ @SafeVarargs public static boolean isExists(T object, T... objects) { - if (objects == null || objects.length == 0) { + if (objects == null) { return false; } for (Object i : objects) { -- Gitee From 06e23b265481ab7e7186eba6894f2bb503c05eeb Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 18 Jun 2023 23:48:51 +0800 Subject: [PATCH 17/54] =?UTF-8?q?YamlTools=E5=A4=A7=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/tools/utils/ConvertTools.java | 26 --- .../com/gitee/qdbp/tools/utils/YamlTools.java | 183 ++++++++++++++++-- 2 files changed, 168 insertions(+), 41 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java index 27510b5..8ba11a7 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java @@ -111,8 +111,6 @@ public class ConvertTools { return list; } else if (object.getClass().isArray()) { return new ArrayList<>(Arrays.asList((Object[]) object)); - } else if (object instanceof Map && isListLikeness((Map) object)) { - return new ArrayList<>(((Map) object).values()); } else if (object instanceof Iterable) { List values = new ArrayList<>(); Iterable iterable = (Iterable) object; @@ -139,30 +137,6 @@ public class ConvertTools { } } - // 所有key是从0开始的连续整数, 就判定为类似数组 - // Yaml的数组有时会解析为key为序号的map, 因此加一个特殊处理 - private static boolean isListLikeness(Map map) { - if (map.isEmpty() || !(map instanceof LinkedHashMap)) { - return false; - } - int index = 0; - for (Map.Entry entry : map.entrySet()) { - Object key = entry.getKey(); - if (key instanceof Integer) { - if (key.equals(index++)) { - continue; - } - } else if (key instanceof String && StringTools.isDigit((String) key)) { - if (Integer.parseInt((String) key) == index++) { - continue; - } - } - return false; - } - // 所有key是从0开始的连续整数 - return true; - } - /** * 将对象解析为列表 * diff --git a/tools/src/main/java/com/gitee/qdbp/tools/utils/YamlTools.java b/tools/src/main/java/com/gitee/qdbp/tools/utils/YamlTools.java index e86d559..2ca6582 100644 --- a/tools/src/main/java/com/gitee/qdbp/tools/utils/YamlTools.java +++ b/tools/src/main/java/com/gitee/qdbp/tools/utils/YamlTools.java @@ -1,10 +1,14 @@ package com.gitee.qdbp.tools.utils; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.yaml.snakeyaml.LoaderOptions; import org.yaml.snakeyaml.Yaml; +import com.gitee.qdbp.able.exception.ServiceException; +import com.gitee.qdbp.able.model.entry.EachEntry; +import com.gitee.qdbp.able.result.ResultCode; /** * Yaml工具类 @@ -20,41 +24,78 @@ public class YamlTools { /** 将Java对象转换为Yaml字符串 **/ public static String toYamlString(Object object) { - Yaml yaml = createYaml(); - return yaml.dump(object); + if (object == null) { + return null; + } else { + Yaml yaml = createYaml(); + return yaml.dump(object); + } } /** 将Yaml字符串解析为Map对象 **/ public static Map parseAsMap(String string) { + Map map = doParseAsMap(string); + return map != null ? map : new LinkedHashMap<>(); + } + + private static Map doParseAsMap(String string) { + if (string == null) { + return null; + } Yaml yaml = createYaml(); Object result = yaml.load(string); - return JsonTools.beanToMap(result, false, false); + if (result == null) { + return null; + } else if (result instanceof Map) { + Map map = MapTools.toJsonMap((Map) result); + normalizeMap(map); + return map; + } else { + String msg = "Expected format is map yaml, actual result type is {}: {}"; + throw new ServiceException(ResultCode.PARAMETER_VALUE_ERROR) + .setDetails(msg, result.getClass().getSimpleName(), string); + } } /** 将Yaml字符串解析为Map数组 **/ public static List> parseAsMaps(String string) { + List> maps = doParseAsMaps(string); + return maps != null ? maps : new ArrayList<>(); + } + + public static List> doParseAsMaps(String string) { + if (string == null) { + return null; + } Yaml yaml = createYaml(); Object object = yaml.load(string); - List list = ConvertTools.parseList(object); - return JsonTools.beanToMaps(list, false, false); + + if (object == null) { + return null; + } else if (object instanceof Map) { + Map map = MapTools.toJsonMap((Map) object); + normalizeMap(map); + List> list = new ArrayList<>(); + list.add(map); + return list; + } else { + List list = ConvertTools.parseList(object); + List> maps = MapTools.toJsonMaps(list); + normalizeMaps(maps); + return maps; + } } /** 将Yaml字符串解析为Java对象 **/ public static T parseAsObject(String string, Class clazz) { - Yaml yaml = createYaml(); - return yaml.loadAs(string, clazz); + Map map = doParseAsMap(string); + return map == null ? null : JsonTools.mapToBean(map, clazz); } /** 将Yaml字符串解析为Java对象列表 **/ public static List parseAsObjects(String string, Class clazz) { - Yaml yaml = createYaml(); - Object object = yaml.load(string); - List list = ConvertTools.parseList(object); - List results = new ArrayList<>(); - for (Object item : list) { - results.add(JsonTools.convert(item, clazz)); - } - return results; + List> maps = doParseAsMaps(string); + return maps == null ? null : JsonTools.mapToBeans(maps, clazz); } private static Yaml createYaml() { @@ -65,4 +106,116 @@ public class YamlTools { options.setMaxAliasesForCollections(Integer.MAX_VALUE); return new Yaml(options); } + + /** + * 规范化处理
+ * Yaml中的数组有时会解析成以数字序号为key的map, 因此加一个规范化处理
+ * { "0": "string1", "1": "string2", "2": "string3" }
+ * 处理成: [ "string1", "string2", "string3" ]
+ * + * @param map Map对象 + */ + public static void normalizeMap(Map map) { + MapTools.each(map, LIST_LIKENESS_CLEANER); + } + + /** + * 规范化处理
+ * Yaml中的数组有时会解析成以数字序号为key的map, 因此加一个规范化处理
+ * { "0": "string1", "1": "string2", "2": "string3" }
+ * 处理成: [ "string1", "string2", "string3" ]
+ * + * @param maps Map列表 + */ + public static void normalizeMaps(List> maps) { + MapTools.each(maps, LIST_LIKENESS_CLEANER); + } + + /** + * 规范化成为一个新副本
+ * Yaml中的数组有时会解析成以数字序号为key的map, 因此加一个规范化处理
+ * { "0": "string1", "1": "string2", "2": "string3" }
+ * 处理成: [ "string1", "string2", "string3" ]
+ * + * @param map Map对象 + * @return 返回Map对象的副本 + */ + public static Map normalizeAsCopy(Map map) { + Map newer = ConvertTools.deepCopyObject(map); + MapTools.each(newer, LIST_LIKENESS_CLEANER); + return newer; + } + + /** + * 规范化成为一个新副本
+ * Yaml中的数组有时会解析成以数字序号为key的map, 因此加一个规范化处理
+ * { "0": "string1", "1": "string2", "2": "string3" }
+ * 处理成: [ "string1", "string2", "string3" ]
+ * + * @param maps Map列表 + * @return 返回Map列表的副本 + */ + public static List> normalizeAsCopy(List> maps) { + List> newer = ConvertTools.deepCopyObject(maps); + MapTools.each(newer, LIST_LIKENESS_CLEANER); + return newer; + } + + /** + * 将对象解析为列表
+ * 如果是以连续数字序号为key的map, 将返回map.values() + * + * @param object 待解析的对象 + * @return 解析后的列表, 如果object=null将返回空列表 + * @since 5.6.230618 + */ + public static List parseList(Object object) { + if (object instanceof Map) { + Map map = (Map) object; + if (isListLikeness(map)) { + return new ArrayList<>(map.values()); + } + } + return ConvertTools.parseList(object); + } + + // 所有key是从0开始的连续整数, 就判定为类似数组 + // Yaml的数组有时会解析成以key为序号的map, 因此加一个特殊处理 + private static boolean isListLikeness(Map map) { + if (map.isEmpty() || !(map instanceof LinkedHashMap)) { + return false; + } + int index = 0; + for (Map.Entry entry : map.entrySet()) { + Object key = entry.getKey(); + if (key instanceof Integer) { + if (key.equals(index++)) { + continue; + } + } else if (key instanceof String && StringTools.isDigit((String) key)) { + if (Integer.parseInt((String) key) == index++) { + continue; + } + } + return false; + } + // 所有key是从0开始的连续整数 + return true; + } + + private static final ListLikenessCleaner LIST_LIKENESS_CLEANER = new ListLikenessCleaner(); + + /** Yaml的数组有时会解析成以key为序号的map, 因此加一个特殊处理 **/ + private static class ListLikenessCleaner implements MapTools.EachInterceptor { + @Override + public void intercept(EachEntry entry) { + if (entry.getValue() instanceof Map) { + Map map = (Map) entry.getValue(); + if (isListLikeness(map)) { + ArrayList list = new ArrayList<>((map).values()); + entry.setValue(list); + } + } + } + } } -- Gitee From fa6e56f530a0020b6f61f35d983b374a910debc7 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 18 Jun 2023 23:50:45 +0800 Subject: [PATCH 18/54] =?UTF-8?q?YamlTools=E4=BC=98=E5=8C=96=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E7=9A=84=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../qdbp/tools/test/ConvertToolsTest.java | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/test/qdbp-tools-test-jdk7/src/test/java/com/gitee/qdbp/tools/test/ConvertToolsTest.java b/test/qdbp-tools-test-jdk7/src/test/java/com/gitee/qdbp/tools/test/ConvertToolsTest.java index 9beb3da..e958b45 100644 --- a/test/qdbp-tools-test-jdk7/src/test/java/com/gitee/qdbp/tools/test/ConvertToolsTest.java +++ b/test/qdbp-tools-test-jdk7/src/test/java/com/gitee/qdbp/tools/test/ConvertToolsTest.java @@ -7,6 +7,7 @@ import java.util.Map; import org.testng.Assert; import org.testng.annotations.Test; import com.gitee.qdbp.tools.utils.ConvertTools; +import com.gitee.qdbp.tools.utils.YamlTools; /** * 数据转换工具类 @@ -66,10 +67,18 @@ public class ConvertToolsTest { map.put(0, "A"); map.put(1, "B"); map.put(2, "C"); - List objects = ConvertTools.parseList(map); - Assert.assertEquals(objects.size(), 3); - Assert.assertEquals(objects.get(0), "A"); - System.out.println(objects); + { + List objects = ConvertTools.parseList(map); + Assert.assertEquals(objects.size(), 1); + Assert.assertEquals(objects.get(0), map); + System.out.println(objects); + } + { + List objects = YamlTools.parseList(map); + Assert.assertEquals(objects.size(), 3); + Assert.assertEquals(objects.get(0), "A"); + System.out.println(objects); + } } @Test @@ -78,10 +87,18 @@ public class ConvertToolsTest { map.put("0", "A"); map.put("1", "B"); map.put("2", "C"); - List objects = ConvertTools.parseList(map); - Assert.assertEquals(objects.size(), 3); - Assert.assertEquals(objects.get(0), "A"); - System.out.println(objects); + { + List objects = ConvertTools.parseList(map); + Assert.assertEquals(objects.size(), 1); + Assert.assertEquals(objects.get(0), map); + System.out.println(objects); + } + { + List objects = YamlTools.parseList(map); + Assert.assertEquals(objects.size(), 3); + Assert.assertEquals(objects.get(0), "A"); + System.out.println(objects); + } } @Test -- Gitee From 95090311dea951093e1760a0027ecab3701bb505 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 18 Jun 2023 23:51:09 +0800 Subject: [PATCH 19/54] qdbp-5.6.230618 --- README.md | 4 ++-- able/pom.xml | 2 +- json/pom.xml | 4 ++-- test/pom.xml | 2 +- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 8617ca2..8057150 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.6.230531 + 5.6.230618 ``` ```xml com.gitee.qdbp qdbp-tools - 5.6.230531 + 5.6.230618 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index e54323f..6d25ce4 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.6.230531 + 5.6.230618 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ diff --git a/json/pom.xml b/json/pom.xml index f9e6e39..203373d 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.6.230531 + 5.6.230618 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.6.230531 + 5.6.230618 diff --git a/test/pom.xml b/test/pom.xml index a12e98c..2557c87 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.6.230531 + 5.6.230618 https://gitee.com/qdbp/qdbp-able/ qdbp json test diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index 96c8631..61d7525 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230531 + 5.6.230618 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index 935654e..8f4e52a 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230531 + 5.6.230618 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index 33e7325..ca03bb9 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230531 + 5.6.230618 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index 0b110e3..d6fc2cc 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230531 + 5.6.230618 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index 4271084..334a45c 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230531 + 5.6.230618 qdbp-tools-test-jdk7 -- Gitee From 7d73593fdf8f402863c615dfa5f47efae2aa7bf0 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 12 Jul 2023 07:43:56 +0800 Subject: [PATCH 20/54] explicit type argument string on jdk7 --- .../src/main/java/com/gitee/qdbp/tools/utils/YamlTools.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/src/main/java/com/gitee/qdbp/tools/utils/YamlTools.java b/tools/src/main/java/com/gitee/qdbp/tools/utils/YamlTools.java index 2ca6582..b643dfb 100644 --- a/tools/src/main/java/com/gitee/qdbp/tools/utils/YamlTools.java +++ b/tools/src/main/java/com/gitee/qdbp/tools/utils/YamlTools.java @@ -35,7 +35,8 @@ public class YamlTools { /** 将Yaml字符串解析为Map对象 **/ public static Map parseAsMap(String string) { Map map = doParseAsMap(string); - return map != null ? map : new LinkedHashMap<>(); + // explicit type argument string on jdk7 + return map != null ? map : new LinkedHashMap(); } private static Map doParseAsMap(String string) { @@ -60,7 +61,8 @@ public class YamlTools { /** 将Yaml字符串解析为Map数组 **/ public static List> parseAsMaps(String string) { List> maps = doParseAsMaps(string); - return maps != null ? maps : new ArrayList<>(); + // explicit type argument string on jdk7 + return maps != null ? maps : new ArrayList>(); } public static List> doParseAsMaps(String string) { -- Gitee From 7626d2e492e89d596783479375fcdf944657f6fb Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 12 Jul 2023 07:45:22 +0800 Subject: [PATCH 21/54] test-jdk8 --- test/pom.xml | 1 + test/qdbp-tools-test-jdk8/pom.xml | 104 ++++++++++++++++ .../com/gitee/qdbp/able/beans/TreeNode.java | 0 .../gitee/qdbp/able/beans/TreeNodesTest.java | 0 .../qdbp/tools/test/ConvertToolsTest.java | 116 ++++++++++++++++++ .../gitee/qdbp/tools/test/EachMapTest.java | 101 +++++++++++++++ .../src/test/resources/logback.xml | 51 ++++++++ .../src/test/resources/testng.xml | 9 ++ 8 files changed, 382 insertions(+) create mode 100644 test/qdbp-tools-test-jdk8/pom.xml rename {tools => test/qdbp-tools-test-jdk8}/src/test/java/com/gitee/qdbp/able/beans/TreeNode.java (100%) rename {tools => test/qdbp-tools-test-jdk8}/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java (100%) create mode 100644 test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/tools/test/ConvertToolsTest.java create mode 100644 test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/tools/test/EachMapTest.java create mode 100644 test/qdbp-tools-test-jdk8/src/test/resources/logback.xml create mode 100644 test/qdbp-tools-test-jdk8/src/test/resources/testng.xml diff --git a/test/pom.xml b/test/pom.xml index 2557c87..be34dd9 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -25,6 +25,7 @@ qdbp-json-test-gson qdbp-json-test-jackson qdbp-tools-test-jdk7 + qdbp-tools-test-jdk8 diff --git a/test/qdbp-tools-test-jdk8/pom.xml b/test/qdbp-tools-test-jdk8/pom.xml new file mode 100644 index 0000000..d652967 --- /dev/null +++ b/test/qdbp-tools-test-jdk8/pom.xml @@ -0,0 +1,104 @@ + + + 4.0.0 + + + com.gitee.qdbp + qdbp-json-test + 5.6.230618 + + + qdbp-tools-test-jdk8 + jar + https://gitee.com/qdbp/qdbp-able/ + qdbp tools test + + + 8 + 8 + + + + + + com.gitee.qdbp + qdbp-able + ${project.version} + + + com.gitee.qdbp + qdbp-json + ${project.version} + + + com.gitee.qdbp + qdbp-tools + ${project.version} + + + + com.alibaba + fastjson + 1.2.16 + + + + org.slf4j + slf4j-api + 1.7.25 + + + + org.slf4j + jcl-over-slf4j + 1.7.25 + + + org.slf4j + log4j-over-slf4j + 1.7.25 + + + ch.qos.logback + logback-core + 1.2.3 + + + ch.qos.logback + logback-classic + 1.2.3 + + + + org.testng + testng + 6.14.3 + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + ${maven.compiler.source} + ${maven.compiler.source} + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12.4 + + + src/test/resources/testng.xml + + + + + + diff --git a/tools/src/test/java/com/gitee/qdbp/able/beans/TreeNode.java b/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/able/beans/TreeNode.java similarity index 100% rename from tools/src/test/java/com/gitee/qdbp/able/beans/TreeNode.java rename to test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/able/beans/TreeNode.java diff --git a/tools/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java b/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java similarity index 100% rename from tools/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java rename to test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java diff --git a/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/tools/test/ConvertToolsTest.java b/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/tools/test/ConvertToolsTest.java new file mode 100644 index 0000000..e958b45 --- /dev/null +++ b/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/tools/test/ConvertToolsTest.java @@ -0,0 +1,116 @@ +package com.gitee.qdbp.tools.test; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.testng.Assert; +import org.testng.annotations.Test; +import com.gitee.qdbp.tools.utils.ConvertTools; +import com.gitee.qdbp.tools.utils.YamlTools; + +/** + * 数据转换工具类 + * + * @author zhaohuihua + * @version 20230129 + */ +@Test +public class ConvertToolsTest { + + @Test + public void test1() { + long value = ConvertTools.toLong("1024 * 1024"); + Assert.assertEquals(value, 1024 * 1024); + } + + @Test + public void test2() { + long value = ConvertTools.toLong("10:20:30.456"); + Assert.assertEquals(value, 10*60*60*1000+20*60*1000+30*1000+456); + } + + @Test + public void test3() { + long value = ConvertTools.toLong("16KB"); + Assert.assertEquals(value, 16*1024); + } + + @Test + public void test4() { + long value = ConvertTools.toLong("1024"); + Assert.assertEquals(value, 1024); + } + + @Test + public void test5() { + long value = ConvertTools.toLong("-1024"); + Assert.assertEquals(value, -1024); + } + + @Test + public void test6() { + try { + // Duration since jdk8 + Class.forName("java.time.Duration"); + + long value = ConvertTools.toLong("PT15H"); + Assert.assertEquals(value, 15*60*60*1000); + } catch (ClassNotFoundException ignore) { + System.out.println("test6 skipped on jdk7 ......"); + } + } + + @Test + public void test7() { + Map map = new LinkedHashMap<>(); + map.put(0, "A"); + map.put(1, "B"); + map.put(2, "C"); + { + List objects = ConvertTools.parseList(map); + Assert.assertEquals(objects.size(), 1); + Assert.assertEquals(objects.get(0), map); + System.out.println(objects); + } + { + List objects = YamlTools.parseList(map); + Assert.assertEquals(objects.size(), 3); + Assert.assertEquals(objects.get(0), "A"); + System.out.println(objects); + } + } + + @Test + public void test8() { + Map map = new LinkedHashMap<>(); + map.put("0", "A"); + map.put("1", "B"); + map.put("2", "C"); + { + List objects = ConvertTools.parseList(map); + Assert.assertEquals(objects.size(), 1); + Assert.assertEquals(objects.get(0), map); + System.out.println(objects); + } + { + List objects = YamlTools.parseList(map); + Assert.assertEquals(objects.size(), 3); + Assert.assertEquals(objects.get(0), "A"); + System.out.println(objects); + } + } + + @Test + public void test9() { + Map map = new HashMap<>(); + map.put(0, "A"); + map.put(1, "B"); + map.put(2, "C"); + List objects = ConvertTools.parseList(map); + Assert.assertEquals(objects.size(), 1); + Assert.assertSame(objects.get(0), map); + Assert.assertEquals(objects.get(0).getClass(), HashMap.class); + System.out.println(objects); + } +} diff --git a/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/tools/test/EachMapTest.java b/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/tools/test/EachMapTest.java new file mode 100644 index 0000000..775c159 --- /dev/null +++ b/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/tools/test/EachMapTest.java @@ -0,0 +1,101 @@ +package com.gitee.qdbp.tools.test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.testng.Assert; +import org.testng.annotations.Test; +import com.gitee.qdbp.able.model.entry.EachEntry; +import com.gitee.qdbp.tools.beans.MapPlus; +import com.gitee.qdbp.tools.utils.JsonTools; +import com.gitee.qdbp.tools.utils.MapTools; +import com.gitee.qdbp.tools.utils.ReflectTools; + +/** + * 深度遍历Map测试 + * + * @author zhaohuihua + * @version 20230215 + */ +@Test +public class EachMapTest { + + @Test + public void test() { + List> addresses = new ArrayList<>(); + MapPlus address = new MapPlus(); + address.put("city", "nanjing"); + address.put("phones", Arrays.asList("1301112222", "13044445555")); + addresses.add(address); + + MapPlus root = new MapPlus(); + root.put("entity.user.userName", "test1"); + root.put("entity.user.address", addresses); + System.out.println(JsonTools.toLogString(root)); + Assert.assertEquals(root.size(), 1); + Map entity = root.getSubMap("entity"); + System.out.println(entity.getClass()); + Assert.assertEquals(entity.getClass(), MapPlus.class); + + List> list = root.getSubMaps("entity.user.address"); + System.out.println(list.getClass()); + Assert.assertEquals(list.size(), 1); + Assert.assertSame(list, addresses); + Map address1 = list.get(0); + System.out.println(address1.getClass()); + Assert.assertEquals(address1.getClass(), MapPlus.class); + Assert.assertSame(address1, address); + + System.out.println("-------------------------------"); + + final Map result = new LinkedHashMap<>(); + MapTools.each(root, new MapTools.EachInterceptor() { + @Override + public void intercept(EachEntry entry) { + String fieldPath = entry.getKey(); + Object fieldValue = entry.getValue(); + if (fieldValue == null) { + result.put(fieldPath, null); + } else if (ReflectTools.isPrimitive(fieldValue.getClass(), false)) { + result.put(fieldPath, fieldValue); + } + } + }); + System.out.println(JsonTools.toLogString(result)); + Assert.assertTrue(result.containsKey("entity.user.userName")); + Assert.assertTrue(result.containsKey("entity.user.address[0].city")); + Assert.assertTrue(result.containsKey("entity.user.address[0].phones[0]")); + Assert.assertTrue(result.containsKey("entity.user.address[0].phones[1]")); + + Assert.assertEquals(result.get("entity.user.userName"), "test1"); + Assert.assertEquals(result.get("entity.user.address[0].city"), "nanjing"); + Assert.assertEquals(result.get("entity.user.address[0].phones[0]"), "1301112222"); + Assert.assertEquals(result.get("entity.user.address[0].phones[1]"), "13044445555"); + + System.out.println("-------------------------------"); + + final Map aResult = new LinkedHashMap<>(); + MapTools.each(addresses, new MapTools.EachInterceptor() { + @Override + public void intercept(EachEntry entry) { + String fieldPath = entry.getKey(); + Object fieldValue = entry.getValue(); + if (fieldValue == null) { + aResult.put(fieldPath, null); + } else if (ReflectTools.isPrimitive(fieldValue.getClass(), false)) { + aResult.put(fieldPath, fieldValue); + } + } + }); + System.out.println(JsonTools.toLogString(aResult)); + Assert.assertTrue(aResult.containsKey("[0].city")); + Assert.assertTrue(aResult.containsKey("[0].phones[0]")); + Assert.assertTrue(aResult.containsKey("[0].phones[1]")); + + Assert.assertEquals(aResult.get("[0].city"), "nanjing"); + Assert.assertEquals(aResult.get("[0].phones[0]"), "1301112222"); + Assert.assertEquals(aResult.get("[0].phones[1]"), "13044445555"); + } +} diff --git a/test/qdbp-tools-test-jdk8/src/test/resources/logback.xml b/test/qdbp-tools-test-jdk8/src/test/resources/logback.xml new file mode 100644 index 0000000..acff406 --- /dev/null +++ b/test/qdbp-tools-test-jdk8/src/test/resources/logback.xml @@ -0,0 +1,51 @@ + + + + + + + + ${pattern.stdout} + + + + ../logs/qdbp-json-test-jackson.log + + + ../logs/qdbp-json-test-jackson-%d{yyyyMMdd}-%i.log + 30 + + + 50MB + + + + ${pattern.normal} + + + + + 0 + + 1024 + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/qdbp-tools-test-jdk8/src/test/resources/testng.xml b/test/qdbp-tools-test-jdk8/src/test/resources/testng.xml new file mode 100644 index 0000000..3f55d76 --- /dev/null +++ b/test/qdbp-tools-test-jdk8/src/test/resources/testng.xml @@ -0,0 +1,9 @@ + + + + + + + + + -- Gitee From 702137f8def4111faf06a5471b65c3b43d351aae Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 12 Jul 2023 07:47:26 +0800 Subject: [PATCH 22/54] =?UTF-8?q?EachEntry=E5=8E=BB=E6=8E=89init=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F,=E6=94=B9=E4=B8=BA=E5=AF=B9=E6=AF=8F=E4=B8=80?= =?UTF-8?q?=E9=A1=B9=E8=BF=9B=E8=A1=8C=E5=AE=9E=E4=BE=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../qdbp/able/model/entry/BaseEntryItem.java | 19 ++++++++++---- .../qdbp/able/model/entry/ListEachEntry.java | 10 ++----- .../qdbp/able/model/entry/ListEntryItem.java | 15 +++-------- .../qdbp/able/model/entry/MapEachEntry.java | 10 ++----- .../qdbp/able/model/entry/MapEntryItem.java | 13 ++-------- .../able/model/entry/ObjectEntryItem.java | 13 ++-------- .../able/model/entry/ObjectsEntryItem.java | 15 +++-------- .../able/model/entry/ReadonlyEntryItem.java | 16 ++---------- .../com/gitee/qdbp/tools/utils/MapTools.java | 26 +++++++++---------- .../gitee/qdbp/tools/utils/ReflectTools.java | 20 +++++++------- 10 files changed, 52 insertions(+), 105 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/BaseEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/BaseEntryItem.java index 603c4f8..1c4496c 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/BaseEntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/BaseEntryItem.java @@ -1,6 +1,7 @@ package com.gitee.qdbp.able.model.entry; import java.util.regex.Pattern; +import com.gitee.qdbp.tools.utils.VerifyTools; /** * 基础字段项变量 @@ -13,17 +14,17 @@ abstract class BaseEntryItem implements EntryItem, EntryItem.Resetable { private static final Pattern CLEAR_NUMBER_INDEX = Pattern.compile("(^\\[[+-]?\\d+]\\.|\\[[+-]?\\d+])"); - protected String key; - protected String name; + protected final String key; + protected final String name; + protected String fields; protected Object value; protected boolean handled; - protected BaseEntryItem init(String key, String name, Object value) { + BaseEntryItem(String key, String name, Object value) { this.key = key; this.name = name; this.value = value; this.handled = false; - return this; } @Override @@ -33,7 +34,15 @@ abstract class BaseEntryItem implements EntryItem, EntryItem.Resetable { @Override public String getFields() { - return key == null ? null : CLEAR_NUMBER_INDEX.matcher(key).replaceAll(""); + if (this.fields == null) { + this.fields = key == null ? null : CLEAR_NUMBER_INDEX.matcher(key).replaceAll(""); + } + return this.fields; + } + + @Override + public final boolean isCollection() { + return VerifyTools.isCollection(this.value); } @Override diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEachEntry.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEachEntry.java index 90ed1fd..cb6d831 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEachEntry.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEachEntry.java @@ -15,17 +15,11 @@ public class ListEachEntry extends ListEntryItem implements EachEntry, EachEntry private boolean skipAfter; private boolean skipEnter; - public ListEachEntry(Collection list) { - super(list); - } - - @Override - public ListEachEntry init(String path, String name, int index, Object value) { - super.init(path, name, index, value); + public ListEachEntry(Collection list, String path, String name, int index, Object value) { + super(list, path, name, index, value); this.skipAll = false; this.skipAfter = false; this.skipEnter = false; - return this; } public void skipAll() { diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java index fd74a73..74c86e5 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java @@ -15,21 +15,12 @@ import com.gitee.qdbp.able.result.ResultCode; public class ListEntryItem extends BaseEntryItem { private final Collection list; - private int index; + private final int index; - public ListEntryItem(Collection list) { + public ListEntryItem(Collection list, String path, String name, int index, Object value) { + super(path, name, value); this.list = list; - } - - @Override - public boolean isCollection() { - return true; - } - - public ListEntryItem init(String path, String name, int index, Object value) { - super.init(path, name, value); this.index = index; - return this; } @Override diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEachEntry.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEachEntry.java index 8857ae9..f5e0ed7 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEachEntry.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEachEntry.java @@ -15,17 +15,11 @@ public class MapEachEntry extends MapEntryItem implements EachEntry, EachEntry.B private boolean skipAfter; private boolean skipEnter; - public MapEachEntry(Map map) { - super(map); - } - - @Override - public MapEachEntry init(String key, String name, Object value) { - super.init(key, name, value); + public MapEachEntry(Map map, String key, String name, Object value) { + super(map, key, name, value); this.skipAll = false; this.skipAfter = false; this.skipEnter = false; - return this; } public void skipAll() { diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java index 9a243fb..acdaa1e 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java @@ -13,20 +13,11 @@ public class MapEntryItem extends BaseEntryItem { private final Map map; - public MapEntryItem(Map map) { + public MapEntryItem(Map map, String key, String name, Object value) { + super(key, name, value); this.map = map; } - @Override - public boolean isCollection() { - return false; - } - - public MapEntryItem init(String key, String name, Object value) { - super.init(key, name, value); - return this; - } - @Override public void resetValue(Object value) { @SuppressWarnings("unchecked") diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java index c7b7c68..32d2f04 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java @@ -15,20 +15,11 @@ public class ObjectEntryItem extends BaseEntryItem { private final Object object; - public ObjectEntryItem(Object object) { + public ObjectEntryItem(Object object, String key, String name, Object value) { + super(key, name, value); this.object = object; } - @Override - public boolean isCollection() { - return false; - } - - public ObjectEntryItem init(String key, String name, Object value) { - super.init(key, name, value); - return this; - } - @Override public void resetValue(Object value) { if (object != null) { diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java index d2ad533..ccd33dc 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java @@ -12,21 +12,12 @@ import java.lang.reflect.Array; public class ObjectsEntryItem extends BaseEntryItem { private final Object object; - private int index; + private final int index; - public ObjectsEntryItem(Object object) { + public ObjectsEntryItem(Object object, String key, String name, int index, Object value) { + super(key, name, value); this.object = object; - } - - @Override - public boolean isCollection() { - return true; - } - - public ObjectsEntryItem init(String path, String name, int index, Object value) { - super.init(path, name, value); this.index = index; - return this; } @Override diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java index d06902b..81d912d 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java @@ -14,21 +14,9 @@ public class ReadonlyEntryItem extends BaseEntryItem { private final Object object; - private final boolean isCollection; - - public ReadonlyEntryItem(Object object, boolean isCollection) { + public ReadonlyEntryItem(Object object, String key, String name, Object value) { + super(key, name, value); this.object = object; - this.isCollection = isCollection; - } - - @Override - public boolean isCollection() { - return isCollection; - } - - public ReadonlyEntryItem init(String key, String name, Object value) { - super.init(key, name, value); - return this; } @Override diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java index 2a9d216..faa9042 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java @@ -885,7 +885,6 @@ public class MapTools { } private static boolean doEachMap(String parentPath, Map map, EachInterceptor interceptor) { - MapEachEntry mapEntry = new MapEachEntry(map); for (Map.Entry item : map.entrySet()) { if (item.getKey() == null || item.getKey().trim().length() == 0) { continue; @@ -893,20 +892,20 @@ public class MapTools { String fieldName = item.getKey(); String fieldPath = StringTools.concat('.', parentPath, fieldName); Object fieldValue = item.getValue(); - mapEntry.init(fieldPath, fieldName, fieldValue); + MapEachEntry entry = new MapEachEntry(map, fieldPath, fieldName, fieldValue); // 调用拦截函数 - interceptor.intercept(mapEntry); - if (mapEntry.isSkipAll()) { + interceptor.intercept(entry); + if (entry.isSkipAll()) { // 跳过全部 return false; } - if (mapEntry.isSkipAfter()) { + if (entry.isSkipAfter()) { // 跳过当前容器中的后续字段 break; } - if (!mapEntry.isSkipEnter() && mapEntry.getValue() != null) { + if (!entry.isSkipEnter() && entry.getValue() != null) { // 递归进入字段内部 - boolean isContinue = doEnterEntryValue(mapEntry, interceptor); + boolean isContinue = doEnterEntryValue(entry, interceptor); if (!isContinue) { return false; } @@ -916,24 +915,23 @@ public class MapTools { } private static boolean doEachList(String parentPath, List list, EachInterceptor interceptor) { - ListEachEntry listEntry = new ListEachEntry(list); for (int i = 0; i < list.size(); i++) { String childName = "[" + i + "]"; String childPath = ReflectTools.concatFieldPaths(parentPath, childName); Object childValue = list.get(i); - listEntry.init(childPath, childName, i, childValue); + ListEachEntry entry = new ListEachEntry(list, childPath, childName, i, childValue); // 调用拦截函数 - interceptor.intercept(listEntry); - if (listEntry.isSkipAll()) { + interceptor.intercept(entry); + if (entry.isSkipAll()) { // 跳过全部 return false; } - if (listEntry.isSkipAfter()) { + if (entry.isSkipAfter()) { // 跳过当前容器中的后续字段 break; } - if (!listEntry.isSkipEnter() && listEntry.getValue() != null) { - boolean isContinue = doEnterEntryValue(listEntry, interceptor); + if (!entry.isSkipEnter() && entry.getValue() != null) { + boolean isContinue = doEnterEntryValue(entry, interceptor); if (!isContinue) { return false; } diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java index 07851a8..4aebb58 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java @@ -375,14 +375,14 @@ public abstract class ReflectTools { for (int i = 0; i < values.size(); i++) { String name = "[" + i + "]"; String path = concatFieldPaths(parentPath, realFieldName, name); - results.add(new ListEntryItem(values).init(path, name, i, values.get(i))); + results.add(new ListEntryItem(values, path, name, i, values.get(i))); } } else if (fieldValue.getClass().isArray()) { Object[] values = (Object[]) fieldValue; for (int i = 0; i < values.length; i++) { String name = "[" + i + "]"; String path = concatFieldPaths(parentPath, realFieldName, name); - results.add(new ObjectsEntryItem(values).init(path, name, i, values[i])); + results.add(new ObjectsEntryItem(values, path, name, i, values[i])); } } else if (fieldValue instanceof Iterable) { Iterable iterable = (Iterable) fieldValue; @@ -390,7 +390,7 @@ public abstract class ReflectTools { for (Object item : iterable) { String name = "[" + (i++) + "]"; String path = concatFieldPaths(parentPath, realFieldName, name); - results.add(new ReadonlyEntryItem(iterable, true).init(path, name, item)); + results.add(new ReadonlyEntryItem(iterable, path, name, item)); } } else if (fieldValue instanceof Iterator) { Iterator iterator = (Iterator) fieldValue; @@ -399,7 +399,7 @@ public abstract class ReflectTools { String name = "[" + (i++) + "]"; String path = concatFieldPaths(parentPath, realFieldName, name); Object next = iterator.next(); - results.add(new ReadonlyEntryItem(iterator, true).init(path, name, next)); + results.add(new ReadonlyEntryItem(iterator, path, name, next)); } } else if (fieldValue instanceof Enumeration) { Enumeration enumeration = (Enumeration) fieldValue; @@ -408,7 +408,7 @@ public abstract class ReflectTools { String name = "[" + (i++) + "]"; String path = concatFieldPaths(parentPath, realFieldName, name); Object next = enumeration.nextElement(); - results.add(new ReadonlyEntryItem(enumeration, true).init(path, name, next)); + results.add(new ReadonlyEntryItem(enumeration, path, name, next)); } } else { results.add(newObjectEntryItem(parent, parentPath, parentList, fieldName, fieldValue)); @@ -424,9 +424,9 @@ public abstract class ReflectTools { // 上级不是list String path = concatFieldPaths(parentPath, fieldName); if (parent instanceof Map) { - return new MapEntryItem((Map) parent).init(path, fieldName, fieldValue); + return new MapEntryItem((Map) parent, path, fieldName, fieldValue); } else { - return new ObjectEntryItem(parent).init(path, fieldName, fieldValue); + return new ObjectEntryItem(parent, path, fieldName, fieldValue); } } else { // 上级是list, fieldName就应该是序号, 可以解析为数字 @@ -434,11 +434,11 @@ public abstract class ReflectTools { String name = "[" + fieldName + "]"; String path = concatFieldPaths(parentPath, name); if (index != null && parent instanceof List) { - return new ListEntryItem((List) parent).init(path, name, index, fieldValue); + return new ListEntryItem((List) parent, path, name, index, fieldValue); } else if (index != null && parent.getClass().isArray()) { - return new ObjectsEntryItem(parent).init(path, name, index, fieldValue); + return new ObjectsEntryItem(parent, path, name, index, fieldValue); } else { - return new ReadonlyEntryItem(parent, true).init(path, name, fieldValue); + return new ReadonlyEntryItem(parent, path, name, fieldValue); } } } -- Gitee From 9a7f6a77bd958a446dbc29c9b6e33ccb21cda319 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 12 Jul 2023 07:50:29 +0800 Subject: [PATCH 23/54] 5.6.230712 --- README.md | 4 ++-- able/pom.xml | 2 +- json/pom.xml | 4 ++-- test/pom.xml | 2 +- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- test/qdbp-tools-test-jdk8/pom.xml | 2 +- tools/pom.xml | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 8057150..460a794 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.6.230618 + 5.6.230712 ``` ```xml com.gitee.qdbp qdbp-tools - 5.6.230618 + 5.6.230712 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index 6d25ce4..71da000 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.6.230618 + 5.6.230712 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ diff --git a/json/pom.xml b/json/pom.xml index 203373d..76d9dee 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.6.230618 + 5.6.230712 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.6.230618 + 5.6.230712 diff --git a/test/pom.xml b/test/pom.xml index be34dd9..6c9da77 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.6.230618 + 5.6.230712 https://gitee.com/qdbp/qdbp-able/ qdbp json test diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index 61d7525..4ffec8e 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230618 + 5.6.230712 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index 8f4e52a..ad9851a 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230618 + 5.6.230712 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index ca03bb9..7a5a008 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230618 + 5.6.230712 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index d6fc2cc..4c461cc 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230618 + 5.6.230712 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index 334a45c..5e117a0 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230618 + 5.6.230712 qdbp-tools-test-jdk7 diff --git a/test/qdbp-tools-test-jdk8/pom.xml b/test/qdbp-tools-test-jdk8/pom.xml index d652967..e1669bc 100644 --- a/test/qdbp-tools-test-jdk8/pom.xml +++ b/test/qdbp-tools-test-jdk8/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230618 + 5.6.230712 qdbp-tools-test-jdk8 diff --git a/tools/pom.xml b/tools/pom.xml index 4da9f84..5ece174 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.6.230618 + 5.6.230712 https://gitee.com/qdbp/qdbp-able/ qdbp tools library -- Gitee From 4eb9af986807ed56be0556cb7707abfd183ac452 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Mon, 14 Aug 2023 23:52:12 +0800 Subject: [PATCH 24/54] =?UTF-8?q?=E4=BF=AE=E6=AD=A3Debugger=E7=B1=BB?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E8=BD=AC=E6=8D=A2=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- able/src/main/java/com/gitee/qdbp/able/debug/BaseDebugger.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/able/src/main/java/com/gitee/qdbp/able/debug/BaseDebugger.java b/able/src/main/java/com/gitee/qdbp/able/debug/BaseDebugger.java index 678b411..9e730c2 100644 --- a/able/src/main/java/com/gitee/qdbp/able/debug/BaseDebugger.java +++ b/able/src/main/java/com/gitee/qdbp/able/debug/BaseDebugger.java @@ -65,7 +65,7 @@ public abstract class BaseDebugger implements Debugger { buffer.append(format); } else { String fmt = StringTools.replace(format, "{}", "%s"); - Object[] params = new String[args.length]; + Object[] params = new Object[args.length]; for (int i = 0; i < args.length; i++) { Object item = args[i]; if (item instanceof Date) { -- Gitee From 3917494d5df5293f42c1ebd97906790ceb91b8f7 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Mon, 14 Aug 2023 23:53:20 +0800 Subject: [PATCH 25/54] =?UTF-8?q?Byte=E5=B7=A5=E5=85=B7=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/tools/codec/BitConverter.java | 386 ++++++++++++++++++ .../com/gitee/qdbp/tools/codec/BitTools.java | 149 +++++++ 2 files changed, 535 insertions(+) create mode 100644 able/src/main/java/com/gitee/qdbp/tools/codec/BitConverter.java diff --git a/able/src/main/java/com/gitee/qdbp/tools/codec/BitConverter.java b/able/src/main/java/com/gitee/qdbp/tools/codec/BitConverter.java new file mode 100644 index 0000000..1e07042 --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/tools/codec/BitConverter.java @@ -0,0 +1,386 @@ +package com.gitee.qdbp.tools.codec; + +import java.nio.ByteOrder; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +/** + * 数字转字节数组工具类
+ * 来源: 数字转字节数组工具类
+ * + * author: zhuzhongxing + */ +class BitConverter { + + /** + * 以字节数组的形式返回指定的布尔值 + * @param data 一个布尔值 + * @return 长度为 1 的字节数组 + */ + public static byte[] getBytes(boolean data) { + byte[] bytes = new byte[1]; + bytes[0] = (byte) (data ? 1 : 0); + return bytes; + } + + /** + * 以字节数组的形式返回指定的 16 位有符号整数值 + * @param data 要转换的数字 + * @return 长度为 2 的字节数组 + */ + public static byte[] getBytes(short data) { + byte[] bytes = new byte[2]; + if (isLittleEndian()) { + bytes[0] = (byte) (data & 0xff); + bytes[1] = (byte) ((data & 0xff00) >> 8); + } else { + bytes[1] = (byte) (data & 0xff); + bytes[0] = (byte) ((data & 0xff00) >> 8); + } + return bytes; + } + + /** + * 以字节数组的形式返回指定的 Unicode 字符值 + * @param data 要转换的字符 + * @return 长度为 2 的字节数组 + */ + public static byte[] getBytes(char data) { + byte[] bytes = new byte[2]; + if (isLittleEndian()) { + bytes[0] = (byte) (data); + bytes[1] = (byte) (data >> 8); + } else { + bytes[1] = (byte) (data); + bytes[0] = (byte) (data >> 8); + } + return bytes; + } + + /** + * 以字节数组的形式返回指定的 32 位有符号整数值 + * @param data 要转换的数字 + * @return 长度为 4 的字节数组 + */ + public static byte[] getBytes(int data) { + byte[] bytes = new byte[4]; + if (isLittleEndian()) { + bytes[0] = (byte) (data & 0xff); + bytes[1] = (byte) ((data & 0xff00) >> 8); + bytes[2] = (byte) ((data & 0xff0000) >> 16); + bytes[3] = (byte) ((data & 0xff000000) >> 24); + } else { + bytes[3] = (byte) (data & 0xff); + bytes[2] = (byte) ((data & 0xff00) >> 8); + bytes[1] = (byte) ((data & 0xff0000) >> 16); + bytes[0] = (byte) ((data & 0xff000000) >> 24); + } + return bytes; + } + + /** + * 以字节数组的形式返回指定的 64 位有符号整数值 + * @param data 要转换的数字 + * @return 长度为 8 的字节数组 + */ + public static byte[] getBytes(long data) { + byte[] bytes = new byte[8]; + if (isLittleEndian()) { + bytes[0] = (byte) (data & 0xff); + bytes[1] = (byte) ((data >> 8) & 0xff); + bytes[2] = (byte) ((data >> 16) & 0xff); + bytes[3] = (byte) ((data >> 24) & 0xff); + bytes[4] = (byte) ((data >> 32) & 0xff); + bytes[5] = (byte) ((data >> 40) & 0xff); + bytes[6] = (byte) ((data >> 48) & 0xff); + bytes[7] = (byte) ((data >> 56) & 0xff); + } else { + bytes[7] = (byte) (data & 0xff); + bytes[6] = (byte) ((data >> 8) & 0xff); + bytes[5] = (byte) ((data >> 16) & 0xff); + bytes[4] = (byte) ((data >> 24) & 0xff); + bytes[3] = (byte) ((data >> 32) & 0xff); + bytes[2] = (byte) ((data >> 40) & 0xff); + bytes[1] = (byte) ((data >> 48) & 0xff); + bytes[0] = (byte) ((data >> 56) & 0xff); + } + return bytes; + } + + /** + * 以字节数组的形式返回指定的单精度浮点值 + * @param data 要转换的数字 + * @return 长度为 4 的字节数组 + */ + public static byte[] getBytes(float data) { + return getBytes(Float.floatToIntBits(data)); + } + + /** + * 以字节数组的形式返回指定的双精度浮点值 + * @param data 要转换的数字 + * @return 长度为 8 的字节数组 + */ + public static byte[] getBytes(double data) { + return getBytes(Double.doubleToLongBits(data)); + } + + /** + * 将指定字符串中的所有字符编码为一个字节序列 + * @param data 包含要编码的字符的字符串 + * @return 一个字节数组,包含对指定的字符集进行编码的结果 + */ + public static byte[] getBytes(String data) { + return data.getBytes(StandardCharsets.UTF_8); + } + + /** + * 将指定字符串中的所有字符编码为一个字节序列 + * @param data 包含要编码的字符的字符串 + * @param charsetName 字符集编码 + * @return 一个字节数组,包含对指定的字符集进行编码的结果 + */ + public static byte[] getBytes(String data, String charsetName) { + return data.getBytes(Charset.forName(charsetName)); + } + + /** + * 返回由字节数组转换来的布尔值 + * @param bytes 字节数组 + * @return 布尔值 + */ + public static boolean toBoolean(byte[] bytes) { + return bytes[0] != 0; + } + + /** + * 返回由字节数组中的指定的一个字节转换来的布尔值 + * @param bytes 字节数组 + * @param startIndex 起始下标 + * @return 布尔值 + */ + public static boolean toBoolean(byte[] bytes, int startIndex) { + return toBoolean(copyFrom(bytes, startIndex, 1)); + } + + /** + * 返回由字节数组转换来的 16 位有符号整数 + * @param bytes 字节数组 + * @return 由两个字节构成的 16 位有符号整数 + */ + public static short toShort(byte[] bytes) { + if (isLittleEndian()) { + return (short) ((0xff & bytes[0]) | (0xff00 & (bytes[1] << 8))); + } else { + return (short) ((0xff & bytes[1]) | (0xff00 & (bytes[0] << 8))); + } + } + + /** + * 返回由字节数组中的指定的两个字节转换来的 16 位有符号整数 + * @param bytes 字节数组 + * @param startIndex 起始下标 + * @return 由两个字节构成的 16 位有符号整数 + */ + public static short toShort(byte[] bytes, int startIndex) { + return toShort(copyFrom(bytes, startIndex, 2)); + } + + /** + * 返回由字节数组转换来的 Unicode 字符 + * @param bytes 字节数组 + * @return 由两个字节构成的字符 + */ + public static char toChar(byte[] bytes) { + if (isLittleEndian()) { + return (char) ((0xff & bytes[0]) | (0xff00 & (bytes[1] << 8))); + } else { + return (char) ((0xff & bytes[1]) | (0xff00 & (bytes[0] << 8))); + } + } + + /** + * 返回由字节数组中的指定的两个字节转换来的 Unicode 字符 + * @param bytes 字节数组 + * @param startIndex 起始下标 + * @return 由两个字节构成的字符 + */ + public static char toChar(byte[] bytes, int startIndex) { + return toChar(copyFrom(bytes, startIndex, 2)); + } + + /** + * 返回由字节数组转换来的 32 位有符号整数 + * @param bytes 字节数组 + * @return 由四个字节构成的 32 位有符号整数 + */ + public static int toInt(byte[] bytes) { + if (isLittleEndian()) { + return (0xff & bytes[0]) + | (0xff00 & (bytes[1] << 8)) + | (0xff0000 & (bytes[2] << 16)) + | (0xff000000 & (bytes[3] << 24)); + } else { + return (0xff & bytes[3]) + | (0xff00 & (bytes[2] << 8)) + | (0xff0000 & (bytes[1] << 16)) + | (0xff000000 & (bytes[0] << 24)); + } + } + + /** + * 返回由字节数组中的指定的四个字节转换来的 32 位有符号整数 + * @param bytes 字节数组 + * @param startIndex 起始下标 + * @return 由四个字节构成的 32 位有符号整数 + */ + public static int toInt(byte[] bytes, int startIndex) { + return toInt(copyFrom(bytes, startIndex, 4)); + } + + /** + * 返回由字节数组转换来的 64 位有符号整数 + * @param bytes 字节数组 + * @return 由八个字节构成的 64 位有符号整数 + */ + public static long toLong(byte[] bytes) { + if (isLittleEndian()) { + return (0xffL & (long) bytes[0]) + | (0xff00L & ((long) bytes[1] << 8)) + | (0xff0000L & ((long) bytes[2] << 16)) + | (0xff000000L & ((long) bytes[3] << 24)) + | (0xff00000000L & ((long) bytes[4] << 32)) + | (0xff0000000000L & ((long) bytes[5] << 40)) + | (0xff000000000000L & ((long) bytes[6] << 48)) + | (0xff00000000000000L & ((long) bytes[7] << 56)); + } else { + return (0xffL & (long) bytes[7]) + | (0xff00L & ((long) bytes[6] << 8)) + | (0xff0000L & ((long) bytes[5] << 16)) + | (0xff000000L & ((long) bytes[4] << 24)) + | (0xff00000000L & ((long) bytes[3] << 32)) + | (0xff0000000000L & ((long) bytes[2] << 40)) + | (0xff000000000000L & ((long) bytes[1] << 48)) + | (0xff00000000000000L & ((long) bytes[0] << 56)); + } + } + + /** + * 返回由字节数组中的指定的八个字节转换来的 64 位有符号整数 + * @param bytes 字节数组 + * @param startIndex 起始下标 + * @return 由八个字节构成的 64 位有符号整数 + */ + public static long toLong(byte[] bytes, int startIndex) { + return toLong(copyFrom(bytes, startIndex, 8)); + } + + /** + * 返回由字节数组转换来的单精度浮点数 + * @param bytes 字节数组 + * @return 由四个字节构成的单精度浮点数 + */ + public static float toFloat(byte[] bytes) { + return Float.intBitsToFloat(toInt(bytes)); + } + + /** + * 返回由字节数组中的指定的四个字节转换来的单精度浮点数 + * @param bytes 字节数组 + * @param startIndex 起始下标 + * @return 由四个字节构成的单精度浮点数 + */ + public static float toFloat(byte[] bytes, int startIndex) { + return Float.intBitsToFloat(toInt(copyFrom(bytes, startIndex, 4))); + } + + /** + * 返回由字节数组转换来的双精度浮点数 + * @param bytes 字节数组 + * @return 由八个字节构成的双精度浮点数 + */ + public static double toDouble(byte[] bytes) { + return Double.longBitsToDouble(toLong(bytes)); + } + + /** + * 返回由字节数组中的指定的八个字节转换来的双精度浮点数 + * @param bytes 字节数组 + * @param startIndex 起始下标 + * @return 由八个字节构成的双精度浮点数 + */ + public static double toDouble(byte[] bytes, int startIndex) { + return Double.longBitsToDouble(toLong(copyFrom(bytes, startIndex, 8))); + } + + /** + * 返回由字节数组转换来的字符串 + * @param bytes 字节数组 + * @return 字符串 + */ + public static String toString(byte[] bytes) { + return new String(bytes, StandardCharsets.UTF_8); + } + + /** + * 返回由字节数组转换来的字符串 + * @param bytes 字节数组 + * @param charsetName 字符集编码 + * @return 字符串 + */ + public static String toString(byte[] bytes, String charsetName) { + return new String(bytes, Charset.forName(charsetName)); + } + + /** + * 以字符串表示形式返回字节数组的内容 + * @param bytes 字节数组 + * @return 字符串形式的 bytes + */ + public static String toHexString(byte[] bytes) { + if (bytes == null) { + return "null"; + } + int iMax = bytes.length - 1; + if (iMax == -1) { + return "[]"; + } + String digits = "0123456789abcdef"; + StringBuilder b = new StringBuilder(); + b.append('['); + for (int i = 0; ; i++) { + b.append(digits.charAt((0xF0 & bytes[i]) >>> 4)); + b.append(digits.charAt(0x0F & bytes[i])); + if (i == iMax) { + return b.append(']').toString(); + } + b.append(',').append(' '); + } + } + + + // -------------------------------------------------------------------------------------------- + + + /** + * 数组拷贝。 + * @param src 字节数组。 + * @param off 起始下标。 + * @param len 拷贝长度。 + * @return 指定长度的字节数组。 + */ + private static byte[] copyFrom(byte[] src, int off, int len) { + // return Arrays.copyOfRange(src, off, off + len); + byte[] copy = new byte[len]; + System.arraycopy(src, off, copy, 0, Math.min(src.length - off, len)); + return copy; + } + + /** + * 判断 CPU Endian 是否为 Little + * @return 判断结果 + */ + private static boolean isLittleEndian() { + return ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN; + } +} diff --git a/able/src/main/java/com/gitee/qdbp/tools/codec/BitTools.java b/able/src/main/java/com/gitee/qdbp/tools/codec/BitTools.java index fa20cfa..e88769a 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/codec/BitTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/codec/BitTools.java @@ -87,4 +87,153 @@ public abstract class BitTools { public static boolean state(byte b, int p) { return get(b, p) == 1; } + + /** + * 布尔值转换为字节数组 + * + * @param data 一个布尔值 + * @return 长度为 1 的字节数组 + */ + public static byte[] toBytes(boolean data) { + return BitConverter.getBytes(data); + } + + /** + * short型数字转换为字节数组 + * + * @param data short型数字 + * @return 长度为 2 的字节数组 + */ + public static byte[] toBytes(short data) { + return BitConverter.getBytes(data); + } + + /** + * char型字符转换为字节数组 + * + * @param data 字符 + * @return 长度为 2 的字节数组 + */ + public static byte[] toBytes(char data) { + return BitConverter.getBytes(data); + } + + /** + * 整形数字转换为字节数组 + * + * @param data 整形数字 + * @return 长度为 4 的字节数组 + */ + public static byte[] toBytes(int data) { + return BitConverter.getBytes(data); + } + + /** + * long形数字转换为字节数组 + * + * @param data long形数字 + * @return 长度为 4 的字节数组 + */ + public static byte[] toBytes(long data) { + return BitConverter.getBytes(data); + } + + /** + * float形数字转换为字节数组 + * + * @param data float形数字 + * @return 长度为 4 的字节数组 + */ + public static byte[] toBytes(float data) { + return BitConverter.getBytes(data); + } + + /** + * double形数字转换为字节数组 + * + * @param data double形数字 + * @return 长度为 8 的字节数组 + */ + public static byte[] toBytes(double data) { + return BitConverter.getBytes(data); + } + + /** + * 字节数组转换为布尔值 + * + * @param bytes 字节数组 (只会取前1位) + * @return 布尔值 + */ + public static boolean toBoolean(byte[] bytes) { + return BitConverter.toBoolean(bytes); + } + + /** + * 字节数组转换为short型数字 + * + * @param bytes 字节数组 (只会取前2位) + * @return short型数字 + */ + public static short toShort(byte[] bytes) { + return BitConverter.toShort(bytes); + } + + /** + * 字节数组转换为整形数字 + * + * @param bytes 字节数组 (只会取前4位) + * @return 整形数字 + */ + public static int toInteger(byte[] bytes) { + return BitConverter.toInt(bytes); + } + + /** + * 字节数组转换为long形数字 + * + * @param bytes 字节数组 (只会取前8位) + * @return long形数字 + */ + public static long toLong(byte[] bytes) { + if (bytes.length == 4) { + return BitConverter.toInt(bytes); + } else { + return BitConverter.toLong(bytes); + } + } + + /** + * 字节数组转换为float形数字 + * + * @param bytes 字节数组 (只会取前4位) + * @return float形数字 + */ + public static float toFloat(byte[] bytes) { + return BitConverter.toFloat(bytes); + } + + /** + * 字节数组转换为double形数字 + * + * @param bytes 字节数组 (只会取前8位) + * @return double形数字 + */ + public static double toDouble(byte[] bytes) { + if (bytes.length == 4) { + return BitConverter.toFloat(bytes); + } else { + return BitConverter.toDouble(bytes); + } + } + + + /** + * 字节数组转换为char字符 + * + * @param bytes 字节数组 (只会取前2位) + * @return char字符 + */ + public static char toCharacter(byte[] bytes) { + return BitConverter.toChar(bytes); + } } -- Gitee From 2002102c8a5ef4df3fba1b8c3b27c9ad0ea78625 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Mon, 14 Aug 2023 23:54:46 +0800 Subject: [PATCH 26/54] =?UTF-8?q?=E8=AF=BB=E5=8F=96=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/tools/files/FileTools.java | 97 ++++++++++++++++++- 1 file changed, 93 insertions(+), 4 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/files/FileTools.java b/able/src/main/java/com/gitee/qdbp/tools/files/FileTools.java index 75ade1d..f3bdcef 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/files/FileTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/files/FileTools.java @@ -88,16 +88,105 @@ public abstract class FileTools { if (!file.exists()) { throw new FileNotFoundException(file.getAbsolutePath()); } + try (FileInputStream fis = new FileInputStream(file)) { + return readTextContent(fis, maxSize); + } + } + + /** + * 读取文件的文本内容 + * + * @param input 待读取的文件流 + * @return 文本内容 + */ + public static String readTextContent(InputStream input) throws IOException { + return readTextContent(input, 0); + } + + /** + * 读取文件的文本内容 + * + * @param input 待读取的文件流 + * @param maxSize 允许读取的最大字节数, 0表示无限制 + * @return 文本内容 + */ + public static String readTextContent(InputStream input, long maxSize) throws IOException { byte[] bytes; - try (FileInputStream fis = new FileInputStream(file); - ByteArrayOutputStream bos = new ByteArrayOutputStream()) { - copy(fis, bos, maxSize); + try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) { + copy(input, bos, maxSize); bytes = bos.toByteArray(); } return bytesToString(bytes, CHARSET); } + /** + * 读取文件的二进制内容 + * + * @param file 待读取的文件 + * @return 二进制内容 + */ + public static byte[] readByteContent(String file) throws IOException { + return readByteContent(new File(file)); + } + + /** + * 读取文件的二进制内容 + * + * @param file 待读取的文件 + * @return 二进制内容 + */ + public static byte[] readByteContent(File file) throws IOException { + if (!file.exists()) { + throw new FileNotFoundException(file.getAbsolutePath()); + } + try (FileInputStream fis = new FileInputStream(file); + ByteArrayOutputStream bos = new ByteArrayOutputStream()) { + copy(fis, bos); + return bos.toByteArray(); + } + } + + /** + * 读取文件的二进制内容 + * + * @param file 待读取的文件 + * @param maxSize 允许读取的最大字节数, 0表示无限制 + * @return 二进制内容 + */ + public static byte[] readByteContent(File file, long maxSize) throws IOException { + if (!file.exists()) { + throw new FileNotFoundException(file.getAbsolutePath()); + } + try (FileInputStream fis = new FileInputStream(file)) { + return readByteContent(fis, maxSize); + } + } + + /** + * 读取文件的二进制内容 + * + * @param input 待读取的文件流 + * @return 二进制内容 + */ + public static byte[] readByteContent(InputStream input) throws IOException { + return readByteContent(input, 0); + } + + /** + * 读取文件的二进制内容 + * + * @param input 待读取的文件流 + * @param maxSize 允许读取的最大字节数, 0表示无限制 + * @return 二进制内容 + */ + public static byte[] readByteContent(InputStream input, long maxSize) throws IOException { + try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) { + copy(input, bos, maxSize); + return bos.toByteArray(); + } + } + static String bytesToString(byte[] bytes, Charset defaultCharset) throws IOException { try (InputStream input = new ByteArrayInputStream(bytes)) { // 解析内容的字符集 @@ -527,7 +616,7 @@ public abstract class FileTools { // 是文件夹, 目标路径已经存在或目标路径在源路径之中(移到源路径下面), 则只能遍历一个个的移动 File sfile = spath.toFile(); File[] files = sfile.listFiles(); - if (files != null && files.length > 0) { + if (files != null) { for (File next : files) { boolean continues = move(next.toPath(), dpath.resolve(next.getName()), exceptionWatcher); if (!continues) { -- Gitee From c95b7a58f2ec45cbb1d77020fd102358329c0fab Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Mon, 14 Aug 2023 23:55:44 +0800 Subject: [PATCH 27/54] =?UTF-8?q?=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86?= =?UTF-8?q?=E7=B1=BB=E6=A2=B3=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../able/exception/EditableException.java | 32 +--- .../able/exception/FormFieldException.java | 161 ++++++++++++++++++ .../qdbp/able/exception/FormatException.java | 14 +- .../able/exception/NonFatalException.java | 133 +++++++++++++++ .../exception/ResourceNotFoundException.java | 12 +- .../qdbp/able/exception/ServiceException.java | 121 ++++++++++--- .../gitee/qdbp/able/result/ResultCode.java | 9 + .../gitee/qdbp/tools/utils/VerifyTools.java | 17 +- .../settings/i18n/ResultCode_zh_CN.properties | 3 + .../exception/ResultSetMismatchException.java | 30 ++-- .../qdbp/tools/excel/json/BeanGroup.java | 2 +- 11 files changed, 459 insertions(+), 75 deletions(-) create mode 100644 able/src/main/java/com/gitee/qdbp/able/exception/FormFieldException.java create mode 100644 able/src/main/java/com/gitee/qdbp/able/exception/NonFatalException.java diff --git a/able/src/main/java/com/gitee/qdbp/able/exception/EditableException.java b/able/src/main/java/com/gitee/qdbp/able/exception/EditableException.java index 459c4ab..ba0ce14 100644 --- a/able/src/main/java/com/gitee/qdbp/able/exception/EditableException.java +++ b/able/src/main/java/com/gitee/qdbp/able/exception/EditableException.java @@ -5,7 +5,9 @@ package com.gitee.qdbp.able.exception; * * @author zhaohuihua * @version 170624 + * @deprecated 改为使用ServiceException (也可以追加消息了) */ +@Deprecated public abstract class EditableException extends RuntimeException { /** 版本序列号 **/ @@ -75,19 +77,8 @@ public abstract class EditableException extends RuntimeException { * @param message 异常消息 */ public void prependMessage(String message) { - if (message == null || message.length() == 0) { - return; - } - - if (this.message == null) { - this.message = message; - } else { - char last = message.charAt(message.length() - 1); - if (last == ' ' || last == '\t' || last == '\r' || last == '\n') { - this.message = message + this.message; - } else { - this.message = message + " " + this.message; - } + if (message != null && message.length() > 0) { + this.message = (this.message == null) ? message : (message + " " + this.message); } } @@ -97,19 +88,8 @@ public abstract class EditableException extends RuntimeException { * @param message 异常消息 */ public void appendMessage(String message) { - if (message == null || message.length() == 0) { - return; - } - - if (this.message == null) { - this.message = message; - } else { - char last = message.charAt(message.length() - 1); - if (last == ' ' || last == '\t' || last == '\r' || last == '\n') { - this.message = this.message + message; - } else { - this.message = this.message + " " + message; - } + if (message != null && message.length() > 0) { + this.message = (this.message == null) ? message : (this.message + " " + message); } } diff --git a/able/src/main/java/com/gitee/qdbp/able/exception/FormFieldException.java b/able/src/main/java/com/gitee/qdbp/able/exception/FormFieldException.java new file mode 100644 index 0000000..858ca9e --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/exception/FormFieldException.java @@ -0,0 +1,161 @@ +package com.gitee.qdbp.able.exception; + +import com.gitee.qdbp.able.result.IResultMessage; +import com.gitee.qdbp.able.result.ResultCode; + +/** + * 表单字段异常类 + * + * @author zhaohuihua + * @version 20230726 + */ +public class FormFieldException extends NonFatalException { + + private static final long serialVersionUID = -219502305847916492L; + + private String fieldName; + + /** 默认构造函数 **/ + public FormFieldException() { + super(ResultCode.PARAMETER_FORMAT_ERROR); + } + + /** 构造函数 **/ + public FormFieldException(String fieldName) { + super(ResultCode.PARAMETER_FORMAT_ERROR); + this.fieldName = fieldName; + } + + /** + * 构造函数 + * + * @param fieldName 字段名 + * @param result 错误返回码 + */ + public FormFieldException(String fieldName, IResultMessage result) { + super(result); + this.fieldName = fieldName; + } + + /** + * 构造函数 + * + * @param fieldName 字段名 + * @param result 错误返回码 + * @param cause 引发异常的原因 + */ + public FormFieldException(String fieldName, IResultMessage result, Throwable cause) { + super(result, cause); + this.fieldName = fieldName; + } + + /** 设置字段名 **/ + public FormFieldException setFieldName(String fieldName) { + this.fieldName = fieldName; + return this; + } + + /** 字段名 **/ + public String getFieldName() { + return fieldName; + } + + @Override + protected void appendKeywords(StringBuilder buffer) { + buffer.append('[').append(fieldName).append(']'); + } + + /** + * 设置错误返回码 + * + * @param code 错误返回码 + */ + @Override + public ServiceException setCode(String code) { + super.setCode(code); + return this; + } + + /** + * 设置消息 + * + * @param message 消息 + */ + @Override + public FormFieldException setMessage(String message) { + super.setMessage(message); + return this; + } + + /** + * 重新设置错误消息 + * @param pattern 错误消息 + * @param args 替换参数 + * @return 对象自身 + */ + @Override + public FormFieldException setMessage(String pattern, Object... args) { + super.setMessage(pattern, args); + return this; + } + + /** + * 在消息前面追加异常消息 + * + * @param message 异常消息 + */ + @Override + public FormFieldException prependMessage(String message) { + super.prependMessage(message); + return this; + } + + /** + * 在消息后面追加异常消息 + * + * @param message 异常消息 + */ + @Override + public FormFieldException appendMessage(String message) { + super.appendMessage(message); + return this; + } + + /** + * 设置错误详情 + * + * @param details 错误详情 + */ + @Override + public FormFieldException setDetails(String details) { + super.setDetails(details); + return this; + } + + /** + * 设置错误详情 + * + * @param pattern 错误消息 + * @param args 替换参数 + * @return 对象自身 + */ + @Override + public FormFieldException setDetails(String pattern, Object... args) { + super.setDetails(pattern, args); + return this; + } + + /** 在错误详情前面追加提示信息 **/ + @Override + public FormFieldException prependDetails(String details) { + super.prependDetails(details); + return this; + } + + /** 在错误详情后面追加提示信息 **/ + @Override + public FormFieldException appendDetails(String details) { + super.appendDetails(details); + return this; + } +} diff --git a/able/src/main/java/com/gitee/qdbp/able/exception/FormatException.java b/able/src/main/java/com/gitee/qdbp/able/exception/FormatException.java index a771d1f..a83d44d 100644 --- a/able/src/main/java/com/gitee/qdbp/able/exception/FormatException.java +++ b/able/src/main/java/com/gitee/qdbp/able/exception/FormatException.java @@ -1,6 +1,8 @@ package com.gitee.qdbp.able.exception; +import com.gitee.qdbp.able.result.ResultCode; + /** * 格式错误异常类 * @@ -8,14 +10,14 @@ package com.gitee.qdbp.able.exception; * @version 20210220 * @since 3.2.11 */ -public class FormatException extends EditableException { +public class FormatException extends ServiceException { /** 版本序列号 **/ private static final long serialVersionUID = 7269605602712999273L; /** 构造函数 **/ public FormatException() { - super(); + super(ResultCode.PARAMETER_FORMAT_ERROR); } /** @@ -24,7 +26,8 @@ public class FormatException extends EditableException { * @param message 异常信息 */ public FormatException(String message) { - super(message); + super(ResultCode.PARAMETER_FORMAT_ERROR); + this.setMessage(message); } /** @@ -33,7 +36,7 @@ public class FormatException extends EditableException { * @param cause 引发原因 */ public FormatException(Throwable cause) { - super(cause); + super(ResultCode.PARAMETER_FORMAT_ERROR, cause); } /** @@ -43,6 +46,7 @@ public class FormatException extends EditableException { * @param cause 引发原因 */ public FormatException(String message, Throwable cause) { - super(message, cause); + super(ResultCode.PARAMETER_FORMAT_ERROR, cause); + this.setMessage(message); } } \ No newline at end of file diff --git a/able/src/main/java/com/gitee/qdbp/able/exception/NonFatalException.java b/able/src/main/java/com/gitee/qdbp/able/exception/NonFatalException.java new file mode 100644 index 0000000..feaaa76 --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/exception/NonFatalException.java @@ -0,0 +1,133 @@ +package com.gitee.qdbp.able.exception; + +import com.gitee.qdbp.able.result.IResultMessage; +import com.gitee.qdbp.able.result.ResultCode; + +/** + * 非致命异常 (业务提示级别的异常) + * + * @author zhaohuihua + * @version 20230726 + */ +public class NonFatalException extends ServiceException { + + private static final long serialVersionUID = -5189857843104774374L; + + /** 默认构造函数 **/ + public NonFatalException() { + super(ResultCode.PARAMETER_FORMAT_ERROR); + } + + /** + * 构造函数 + * + * @param result 错误返回码 + */ + public NonFatalException(IResultMessage result) { + super(result); + } + + /** + * 构造函数 + * + * @param result 错误返回码 + * @param cause 引发异常的原因 + */ + public NonFatalException(IResultMessage result, Throwable cause) { + super(result, cause); + } + + /** + * 设置错误返回码 + * + * @param code 错误返回码 + */ + @Override + public ServiceException setCode(String code) { + super.setCode(code); + return this; + } + + /** + * 设置消息 + * + * @param message 消息 + */ + @Override + public NonFatalException setMessage(String message) { + super.setMessage(message); + return this; + } + + /** + * 重新设置错误消息 + * @param pattern 错误消息 + * @param args 替换参数 + * @return 对象自身 + */ + @Override + public NonFatalException setMessage(String pattern, Object... args) { + super.setMessage(pattern, args); + return this; + } + + /** + * 在消息前面追加异常消息 + * + * @param message 异常消息 + */ + @Override + public NonFatalException prependMessage(String message) { + super.prependMessage(message); + return this; + } + + /** + * 在消息后面追加异常消息 + * + * @param message 异常消息 + */ + @Override + public NonFatalException appendMessage(String message) { + super.appendMessage(message); + return this; + } + + /** + * 设置错误详情 + * + * @param details 错误详情 + */ + @Override + public NonFatalException setDetails(String details) { + super.setDetails(details); + return this; + } + + /** + * 设置错误详情 + * + * @param pattern 错误消息 + * @param args 替换参数 + * @return 对象自身 + */ + @Override + public NonFatalException setDetails(String pattern, Object... args) { + super.setDetails(pattern, args); + return this; + } + + /** 在错误详情前面追加提示信息 **/ + @Override + public NonFatalException prependDetails(String details) { + super.prependDetails(details); + return this; + } + + /** 在错误详情后面追加提示信息 **/ + @Override + public NonFatalException appendDetails(String details) { + super.appendDetails(details); + return this; + } +} diff --git a/able/src/main/java/com/gitee/qdbp/able/exception/ResourceNotFoundException.java b/able/src/main/java/com/gitee/qdbp/able/exception/ResourceNotFoundException.java index 926960a..bf8cfa7 100644 --- a/able/src/main/java/com/gitee/qdbp/able/exception/ResourceNotFoundException.java +++ b/able/src/main/java/com/gitee/qdbp/able/exception/ResourceNotFoundException.java @@ -1,12 +1,14 @@ package com.gitee.qdbp.able.exception; +import com.gitee.qdbp.able.result.ResultCode; + /** * 资源未找到 * * @author zhaohuihua * @version 170624 */ -public class ResourceNotFoundException extends EditableException { +public class ResourceNotFoundException extends ServiceException { /** 版本序列号 **/ private static final long serialVersionUID = 1L; @@ -16,15 +18,17 @@ public class ResourceNotFoundException extends EditableException { } public ResourceNotFoundException(String message) { - super(message); + super(ResultCode.RESOURCE_NOT_FOUND); + this.setMessage(message); } public ResourceNotFoundException(Throwable cause) { - super(cause); + super(ResultCode.RESOURCE_NOT_FOUND, cause); } public ResourceNotFoundException(String message, Throwable cause) { - super(message, cause); + super(ResultCode.RESOURCE_NOT_FOUND, cause); + this.setMessage(message); } } diff --git a/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java b/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java index a98e3ae..c9ea3bf 100644 --- a/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java +++ b/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java @@ -4,6 +4,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.UndeclaredThrowableException; import com.gitee.qdbp.able.result.IResultException; import com.gitee.qdbp.able.result.IResultMessage; +import com.gitee.qdbp.able.result.ResultCode; import com.gitee.qdbp.tools.utils.StringTools; /** @@ -19,11 +20,14 @@ public class ServiceException extends RuntimeException implements IResultExcepti /** 错误返回码 **/ private String code; + /** 异常消息 **/ + private String message; /** 错误详情 **/ private String details; /** 默认构造函数 **/ public ServiceException() { + this(ResultCode.SERVER_INNER_ERROR); } /** @@ -34,6 +38,7 @@ public class ServiceException extends RuntimeException implements IResultExcepti public ServiceException(IResultMessage result) { super(getRealMessage(result)); this.code = result.getCode(); + this.message = getRealMessage(result); if (result instanceof IResultException) { this.details = ((IResultException) result).getDetails(); } @@ -48,8 +53,7 @@ public class ServiceException extends RuntimeException implements IResultExcepti */ @Deprecated public ServiceException(IResultMessage result, String details) { - super(getRealMessage(result)); - this.code = result.getCode(); + this(result); this.details = details; } @@ -62,8 +66,11 @@ public class ServiceException extends RuntimeException implements IResultExcepti public ServiceException(IResultMessage result, Throwable cause) { super(getRealMessage(result), cause); this.code = result.getCode(); + this.message = getRealMessage(result); if (result instanceof IResultException) { this.details = ((IResultException) result).getDetails(); + } else if (cause instanceof IResultException) { + this.details = ((IResultException) cause).getDetails(); } } @@ -77,8 +84,7 @@ public class ServiceException extends RuntimeException implements IResultExcepti */ @Deprecated public ServiceException(IResultMessage result, String details, Throwable cause) { - super(getRealMessage(result), cause); - this.code = result.getCode(); + this(result, cause); this.details = details; } @@ -94,7 +100,7 @@ public class ServiceException extends RuntimeException implements IResultExcepti /** * 设置错误返回码 - * + * * @param code 错误返回码 */ public ServiceException setCode(String code) { @@ -102,6 +108,79 @@ public class ServiceException extends RuntimeException implements IResultExcepti return this; } + /** 提供给子类追加需要输出在异常信息中的关键字 **/ + protected void appendKeywords(StringBuilder buffer) { + } + + /** + * 获取简化的错误消息 (不会包含错误详情) + * + * @return 错误消息 + */ + @Override + public String getSimpleMessage() { + return super.getMessage(); + } + + @Override + public String getMessage() { + StringBuilder buffer = new StringBuilder(); + appendKeywords(buffer); + buffer.append(getSimpleMessage()); + appendDetails(buffer, details); + return buffer.toString(); + } + + /** + * 设置消息 + * + * @param message 消息 + */ + protected ServiceException setMessage(String message) { + this.message = message; + return this; + } + + /** + * 重新设置错误消息 + * @param pattern 错误消息 + * @param args 替换参数 + * @return 对象自身 + */ + public ServiceException setMessage(String pattern, Object... args) { + if (pattern == null || pattern.length() == 0 || args == null || args.length == 0) { + this.message = pattern; + } else { + String fmt = StringTools.replace(pattern, "{}", "%s"); + this.message = String.format(fmt, args); + } + return this; + } + + /** + * 在消息前面追加异常消息 + * + * @param message 异常消息 + */ + public ServiceException prependMessage(String message) { + if (message != null && message.length() > 0) { + this.message = (this.message == null) ? message : (message + " " + this.message); + } + return this; + } + + /** + * 在消息后面追加异常消息 + * + * @param message 异常消息 + */ + public ServiceException appendMessage(String message) { + if (message != null && message.length() > 0) { + this.message = (this.message == null) ? message : (this.message + " " + message); + } + return this; + } + /** * 获取错误详情 * @@ -114,7 +193,7 @@ public class ServiceException extends RuntimeException implements IResultExcepti /** * 设置错误详情 - * + * * @param details 错误详情 */ public ServiceException setDetails(String details) { @@ -132,30 +211,27 @@ public class ServiceException extends RuntimeException implements IResultExcepti public ServiceException setDetails(String pattern, Object... args) { if (pattern == null || pattern.length() == 0 || args == null || args.length == 0) { this.details = pattern; - return this; } else { String fmt = StringTools.replace(pattern, "{}", "%s"); this.details = String.format(fmt, args); - return this; } + return this; } - /** - * 获取简化的错误消息 (不会包含错误详情) - * - * @return 错误消息 - */ - @Override - public String getSimpleMessage() { - return super.getMessage(); + /** 在错误详情前面追加提示信息 **/ + public ServiceException prependDetails(String details) { + if (details != null && details.length() > 0) { + this.details = (this.details == null) ? details : (details + " " + this.details); + } + return this; } - @Override - public String getMessage() { - StringBuilder buffer = new StringBuilder(); - buffer.append(getSimpleMessage()); - appendDetails(buffer, details); - return buffer.toString(); + /** 在错误详情后面追加提示信息 **/ + public ServiceException appendDetails(String details) { + if (details != null && details.length() > 0) { + this.details = (this.details == null) ? details : (this.details + " " + details); + } + return this; } @Override @@ -163,6 +239,7 @@ public class ServiceException extends RuntimeException implements IResultExcepti StringBuilder buffer = new StringBuilder(); buffer.append(getClass().getSimpleName()); buffer.append('[').append(code).append(']'); + appendKeywords(buffer); buffer.append(getSimpleMessage()); appendDetails(buffer, details); return buffer.toString(); diff --git a/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java b/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java index d9e6dbb..d4836d5 100644 --- a/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java +++ b/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java @@ -34,6 +34,15 @@ public enum ResultCode implements IResultMessage { /** 远程服务对方返回失败 **/ REMOTE_SERVICE_FAIL, + /** 远程服务未找到 **/ + REMOTE_SERVICE_NOT_FOUND, + + /** 远程服务请求超时 **/ + REMOTE_SERVICE_TIMEOUT, + + /** 资源不存在 **/ + RESOURCE_NOT_FOUND, + /** 数据库INSERT失败 **/ DB_INSERT_ERROR, diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java index d233f8a..acdbf7c 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java @@ -5,7 +5,7 @@ import java.util.Collection; import java.util.Enumeration; import java.util.Iterator; import java.util.Map; -import com.gitee.qdbp.able.exception.ServiceException; +import com.gitee.qdbp.able.exception.FormFieldException; import com.gitee.qdbp.able.result.ResultCode; /** @@ -29,7 +29,8 @@ public class VerifyTools { */ public static void requireNonNull(Object object, String name) { if (object == null) { - throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED).setDetails(name + " must not be null."); + throw new FormFieldException(name, ResultCode.PARAMETER_IS_REQUIRED) + .setDetails(name + " must not be null."); } } @@ -42,10 +43,12 @@ public class VerifyTools { */ public static void requireNotBlank(Object object, String name) { if (object == null) { - throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED).setDetails(name + " must not be null."); + throw new FormFieldException(name, ResultCode.PARAMETER_IS_REQUIRED) + .setDetails(name + " must not be null."); } if (isBlank(object)) { - throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED).setDetails(name + " must not be empty."); + throw new FormFieldException(name, ResultCode.PARAMETER_IS_REQUIRED) + .setDetails(name + " must not be empty."); } } @@ -58,10 +61,12 @@ public class VerifyTools { */ public static void requireNotBlank(String string, String name) { if (string == null) { - throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED).setDetails(name + " must not be null."); + throw new FormFieldException(name, ResultCode.PARAMETER_IS_REQUIRED) + .setDetails(name + " must not be null."); } if (isBlank(string)) { - throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED).setDetails(name + " must not be empty."); + throw new FormFieldException(name, ResultCode.PARAMETER_IS_REQUIRED) + .setDetails(name + " must not be empty."); } } diff --git a/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties b/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties index 8ccb692..da5ddc3 100644 --- a/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties +++ b/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties @@ -7,6 +7,9 @@ PARAMETER_OUT_RANGE = 参数值超出允许范围 SERVER_INNER_ERROR = 服务器内部异常 REMOTE_SERVICE_ERROR = 远程服务调用失败 REMOTE_SERVICE_FAIL = 远程服务对方返回失败 +REMOTE_SERVICE_NOT_FOUND = 远程服务未找到 +REMOTE_SERVICE_TIMEOUT = 远程服务请求超时 +RESOURCE_NOT_FOUND = 资源不存在 DB_INSERT_ERROR = 数据保存失败 DB_UPDATE_ERROR = 数据更新失败 DB_DELETE_ERROR = 数据删除失败 diff --git a/tools/src/main/java/com/gitee/qdbp/tools/excel/exception/ResultSetMismatchException.java b/tools/src/main/java/com/gitee/qdbp/tools/excel/exception/ResultSetMismatchException.java index 14495ff..f3f73f2 100644 --- a/tools/src/main/java/com/gitee/qdbp/tools/excel/exception/ResultSetMismatchException.java +++ b/tools/src/main/java/com/gitee/qdbp/tools/excel/exception/ResultSetMismatchException.java @@ -1,6 +1,8 @@ package com.gitee.qdbp.tools.excel.exception; -import com.gitee.qdbp.able.exception.EditableException; +import com.gitee.qdbp.able.exception.ServiceException; +import com.gitee.qdbp.able.result.IResultMessage; +import com.gitee.qdbp.tools.utils.StringTools; /** * 结果集不匹配 @@ -8,7 +10,7 @@ import com.gitee.qdbp.able.exception.EditableException; * @author zhaohuihua * @version 190324 */ -public class ResultSetMismatchException extends EditableException { +public class ResultSetMismatchException extends ServiceException { /** serialVersionUID **/ private static final long serialVersionUID = 1L; @@ -19,16 +21,22 @@ public class ResultSetMismatchException extends EditableException { * @param message 异常消息 */ public ResultSetMismatchException(String message) { - super(message); + super(ErrorCode.RESULT_SET_MISMATCH); + super.setMessage(message); } - /** - * 构造函数 - * - * @param message 异常消息 - * @param cause 异常原因 - */ - public ResultSetMismatchException(String message, Throwable cause) { - super(message, cause); + private enum ErrorCode implements IResultMessage { + + RESULT_SET_MISMATCH; + + @Override + public String getCode() { + return this.name(); + } + + @Override + public String getMessage() { + return StringTools.replace(this.name(), "_", " ", ".", ""); + } } } diff --git a/tools/src/main/java/com/gitee/qdbp/tools/excel/json/BeanGroup.java b/tools/src/main/java/com/gitee/qdbp/tools/excel/json/BeanGroup.java index 0a63c29..250180e 100644 --- a/tools/src/main/java/com/gitee/qdbp/tools/excel/json/BeanGroup.java +++ b/tools/src/main/java/com/gitee/qdbp/tools/excel/json/BeanGroup.java @@ -501,7 +501,7 @@ public class BeanGroup implements Serializable { private String finalMismatchSummary(Map resources, int total, List errors) { // summary.single = The item don't match. - // summary.multiple = The are {total} items in total, {mismatch} of which don't match. + // summary.multiple = They are {total} items in total, {mismatch} of which don't match. String pattern = resources.get(total > 1 ? "summary.multiple" : "summary.single"); Map params = new HashMap<>(); params.put("total", total); -- Gitee From 503bbc853bfbe11ad45f56b6e43a99079760e1c1 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Mon, 14 Aug 2023 23:57:29 +0800 Subject: [PATCH 28/54] 5.6.230812 --- README.md | 4 ++-- able/pom.xml | 2 +- json/pom.xml | 4 ++-- test/pom.xml | 2 +- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- test/qdbp-tools-test-jdk8/pom.xml | 2 +- tools/pom.xml | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 460a794..8a1841c 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.6.230712 + 5.6.230812 ``` ```xml com.gitee.qdbp qdbp-tools - 5.6.230712 + 5.6.230812 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index 71da000..8a5a490 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.6.230712 + 5.6.230812 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ diff --git a/json/pom.xml b/json/pom.xml index 76d9dee..4e66e71 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.6.230712 + 5.6.230812 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.6.230712 + 5.6.230812 diff --git a/test/pom.xml b/test/pom.xml index 6c9da77..2e7f728 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.6.230712 + 5.6.230812 https://gitee.com/qdbp/qdbp-able/ qdbp json test diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index 4ffec8e..2a736dc 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230712 + 5.6.230812 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index ad9851a..3de47e9 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230712 + 5.6.230812 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index 7a5a008..031ebc0 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230712 + 5.6.230812 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index 4c461cc..5341511 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230712 + 5.6.230812 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index 5e117a0..37c4b1a 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230712 + 5.6.230812 qdbp-tools-test-jdk7 diff --git a/test/qdbp-tools-test-jdk8/pom.xml b/test/qdbp-tools-test-jdk8/pom.xml index e1669bc..ceb7bf7 100644 --- a/test/qdbp-tools-test-jdk8/pom.xml +++ b/test/qdbp-tools-test-jdk8/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230712 + 5.6.230812 qdbp-tools-test-jdk8 diff --git a/tools/pom.xml b/tools/pom.xml index 5ece174..0143240 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.6.230712 + 5.6.230812 https://gitee.com/qdbp/qdbp-able/ qdbp tools library -- Gitee From b485752bcd8a08412baa11f2aaecf154de330c61 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Fri, 18 Aug 2023 21:38:12 +0800 Subject: [PATCH 29/54] =?UTF-8?q?ServiceException=E7=9A=84SimpleMessage?= =?UTF-8?q?=E5=8F=96=E5=80=BC=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/gitee/qdbp/able/exception/ServiceException.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java b/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java index c9ea3bf..bc03520 100644 --- a/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java +++ b/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java @@ -119,7 +119,7 @@ public class ServiceException extends RuntimeException implements IResultExcepti */ @Override public String getSimpleMessage() { - return super.getMessage(); + return message; } @Override -- Gitee From f4bc416b063673d2581ad012117d92e2f760f3e8 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Fri, 18 Aug 2023 21:38:35 +0800 Subject: [PATCH 30/54] 5.6.230815 --- README.md | 4 ++-- able/pom.xml | 2 +- json/pom.xml | 4 ++-- test/pom.xml | 2 +- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- test/qdbp-tools-test-jdk8/pom.xml | 2 +- tools/pom.xml | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 8a1841c..98bb1ac 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.6.230812 + 5.6.230815 ``` ```xml com.gitee.qdbp qdbp-tools - 5.6.230812 + 5.6.230815 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index 8a5a490..a473a2c 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.6.230812 + 5.6.230815 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ diff --git a/json/pom.xml b/json/pom.xml index 4e66e71..77f42ab 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.6.230812 + 5.6.230815 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.6.230812 + 5.6.230815 diff --git a/test/pom.xml b/test/pom.xml index 2e7f728..8021f0e 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.6.230812 + 5.6.230815 https://gitee.com/qdbp/qdbp-able/ qdbp json test diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index 2a736dc..2498d6e 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230812 + 5.6.230815 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index 3de47e9..29e661c 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230812 + 5.6.230815 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index 031ebc0..857ab51 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230812 + 5.6.230815 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index 5341511..eb01039 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230812 + 5.6.230815 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index 37c4b1a..924f81e 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230812 + 5.6.230815 qdbp-tools-test-jdk7 diff --git a/test/qdbp-tools-test-jdk8/pom.xml b/test/qdbp-tools-test-jdk8/pom.xml index ceb7bf7..a09f689 100644 --- a/test/qdbp-tools-test-jdk8/pom.xml +++ b/test/qdbp-tools-test-jdk8/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230812 + 5.6.230815 qdbp-tools-test-jdk8 diff --git a/tools/pom.xml b/tools/pom.xml index 0143240..25117f4 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.6.230812 + 5.6.230815 https://gitee.com/qdbp/qdbp-able/ qdbp tools library -- Gitee From 36e7db8d041f7bbfdd33508a36f94ee617306b76 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 23 Aug 2023 22:55:09 +0800 Subject: [PATCH 31/54] =?UTF-8?q?=E6=A0=91=E5=BD=A2=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E7=B1=BB=E5=A2=9E=E5=BC=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/able/beans/TreeNodes.java | 243 ++++++++++++++---- 1 file changed, 194 insertions(+), 49 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/able/beans/TreeNodes.java b/able/src/main/java/com/gitee/qdbp/able/beans/TreeNodes.java index 53ee1e4..a7ef7bd 100644 --- a/able/src/main/java/com/gitee/qdbp/able/beans/TreeNodes.java +++ b/able/src/main/java/com/gitee/qdbp/able/beans/TreeNodes.java @@ -1,8 +1,10 @@ package com.gitee.qdbp.able.beans; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -22,8 +24,6 @@ public class TreeNodes { /** 容器节点 **/ private final Node container; - /** KEY与节点的映射表 **/ - private final Map> keyNodeMaps; /** 未找到上级的KEY **/ private final List keysOfWithoutParent; /** 获取KEY的方法 **/ @@ -66,11 +66,15 @@ public class TreeNodes { } } this.container = container; - this.keyNodeMaps = maps; this.keysOfWithoutParent = keysOfWithoutParent; this.keyGetter = keyGetter; } + /** 获取容器节点 **/ + public Node container() { + return this.container; + } + /** 获取容器节点 **/ public Node getContainer() { return this.container; @@ -99,22 +103,12 @@ public class TreeNodes { /** 查找指定节点 **/ public Node findNode(String key) { - Node node = keyNodeMaps.get(key); - if (node != null) { - // 考虑到有可能在外部修改key, 因此增加检查 - String nodeKey = keyGetter.apply(node.element); - if (key.equals(nodeKey)) { - return node; - } - } Iterator> iterator = container.depthFirstNodeIterator(); while (iterator.hasNext()) { - Node next = iterator.next(); - String nextKey = keyGetter.apply(next.element); - // 遍历时更新缓存中的对应关系 - keyNodeMaps.put(nextKey, next); + Node node = iterator.next(); + String nextKey = keyGetter.apply(node.element); if (key.equals(nextKey)) { - return next; + return node; } } return null; @@ -169,6 +163,29 @@ public class TreeNodes { return elements; } + /** 移除指定节点 **/ + public void removeElements(String... keys) { + if (keys != null) { + this.removeElements(Arrays.asList(keys)); + } + } + + /** 移除指定节点 **/ + @SuppressWarnings("all") + public void removeElements(final List keys) { + this.container.removeIf(new BaseFunction, Boolean>() { + @Override + public Boolean apply(Node node) { + return keys.contains(keyGetter.apply(node.element)); + } + }); + } + + /** 移除匹配节点 **/ + public void removeIf(BaseFunction, Boolean> matcher) { + this.container.removeIf(matcher); + } + /** 未找到上级的KEY **/ public List getKeysOfWithoutParent() { return this.keysOfWithoutParent; @@ -184,12 +201,7 @@ public class TreeNodes { * @return 树形数据的根节点 */ public List toTreeList(BinaryConsumer> childSetter) { - List list = new ArrayList<>(); - for (Node child : container.children) { - child.fillAllChildren(childSetter); - list.add(child.element); - } - return list; + return container.toTreeList(childSetter); } /** 广度优先遍历 **/ @@ -212,8 +224,8 @@ public class TreeNodes { * @param keyGetter KEY的获取方法 * @param parentGetter 上级的获取方法 * @param childSetter 子级的设置方法 - * @return 树形数据列表 * @param 数据类型 + * @return 树形数据列表 */ public static List toTreeList(List list, BaseFunction keyGetter, BaseFunction parentGetter, BinaryConsumer> childSetter) { @@ -240,6 +252,10 @@ public class TreeNodes { this.children = new ArrayList<>(); } + public boolean isLeaf() { + return this.children.isEmpty(); + } + public T getElement() { return element; } @@ -258,6 +274,11 @@ public class TreeNodes { return parent == null ? null : parent.element; } + /** 获取父级节点 **/ + public Node getParentNode() { + return parent == null ? null : parent; + } + /** 获取所有祖先元素 **/ public List getAllAncestorElements() { List parents = new ArrayList<>(); @@ -270,6 +291,18 @@ public class TreeNodes { return parents; } + /** 获取所有祖先节点 **/ + public List> getAllAncestorNodes() { + List> parents = new ArrayList<>(); + Node temp = parent; + while (temp != null && temp.element != null) { + parents.add(temp); + temp = temp.parent; + } + Collections.reverse(parents); + return parents; + } + /** 获取直接子级元素 **/ public List getChildElements() { List elements = new ArrayList<>(); @@ -279,11 +312,29 @@ public class TreeNodes { return elements; } + /** 获取直接节点列表 **/ + public List> getChildNodes() { + return children; + } + /** 增加子元素 **/ public void addChildElement(T child) { addChildNode(new Node<>(child)); } + /** 增加子级节点 **/ + protected void addChildNode(Node child) { + children.add(child); + child.parent = this; + } + + /** 增加子级节点 **/ + protected void addChildNodes(List> children) { + for (Node child : children) { + addChildNode(child); + } + } + /** 获取后代元素 **/ public List getAllDescendantElements() { Iterator iterator = depthFirstElementIterator(); @@ -295,33 +346,41 @@ public class TreeNodes { return elements; } + /** 获取后代节点 **/ + public List> getAllDescendantNodes() { + Iterator> iterator = depthFirstNodeIterator(); + List> nodes = new ArrayList<>(); + while (iterator.hasNext()) { + Node next = iterator.next(); + nodes.add(next); + } + return nodes; + } + /** 获取所有叶子元素 **/ public List getAllLeafElements() { Iterator> iterator = depthFirstNodeIterator(); List elements = new ArrayList<>(); while (iterator.hasNext()) { Node next = iterator.next(); - if (next.children.isEmpty()) { + if (next.isLeaf()) { elements.add(next.element); } } return elements; } - /** 获取直接节点列表 **/ - protected List> getChildNodes() { - return children; - } - - /** 增加子级节点 **/ - protected void addChildNode(Node child) { - children.add(child); - child.parent = this; - } - - /** 获取父级节点 **/ - protected Node getParentNode() { - return parent == null ? null : parent; + /** 获取所有叶子节点 **/ + public List> getAllLeafNodes() { + Iterator> iterator = depthFirstNodeIterator(); + List> nodes = new ArrayList<>(); + while (iterator.hasNext()) { + Node next = iterator.next(); + if (next.isLeaf()) { + nodes.add(next); + } + } + return nodes; } /** 广度优先遍历元素 **/ @@ -346,22 +405,108 @@ public class TreeNodes { /** 设置所有后代元素的Children属性 **/ public void fillAllChildren(BinaryConsumer> childSetter) { - Iterator> iterator = this.depthFirstNodeIterator(); - List myChildren = new ArrayList<>(); + if (this.element != null) { + childSetter.accept(this.element, this.getChildElements()); + } + Iterator> iterator = this.breadthFirstNodeIterator(); + while (iterator.hasNext()) { + Node node = iterator.next(); + childSetter.accept(node.element, node.getChildElements()); + } + } + + /** 转换为带Children属性的List **/ + public List toTreeList(BinaryConsumer> childSetter) { + List list = new ArrayList<>(); + this.fillAllChildren(childSetter); + if (this.element != null) { + list.add(this.element); + } else { + for (Node child : children) { + list.add(child.element); + } + } + return list; + } + + /** 移除匹配节点 **/ + public void removeIf(BaseFunction, Boolean> matcher) { + Iterator> iterator = this.breadthFirstNodeIterator(); + while (iterator.hasNext()) { + Node node = iterator.next(); + if (matcher.apply(node)) { + iterator.remove(); + } + } + } + + /** 过滤子树 (包含匹配节点及祖先节点, 不包含后代节点) **/ + public Node filterUpBy(BaseFunction, Boolean> matcher) { + return filterBy(true, false, matcher); + } + + /** 过滤子树 (包含匹配节点及后代节点, 不包含祖先节点) **/ + public Node filterDownBy(BaseFunction, Boolean> matcher) { + return filterBy(false, true, matcher); + } + + /** 过滤子树 (包含匹配节点及祖先节点及后代节点) **/ + public Node filterAllBy(BaseFunction, Boolean> matcher) { + return filterBy(true, true, matcher); + } + + /** 过滤子树 (包含匹配节点及祖先节点及后代节点) **/ + private Node filterBy(boolean ancestor, boolean descendant, BaseFunction, Boolean> matcher) { + // 需要保留的节点 + Map, ?> keepNodes = new LinkedHashMap<>(); + // 搜索符合条件的节点 + Iterator> searcher = this.breadthFirstNodeIterator(); + while (searcher.hasNext()) { + Node node = searcher.next(); + if (matcher.apply(node)) { + // 遇到匹配节点, 设置为保留节点 + keepNodes.put(node, null); + if (ancestor) { + // 如果需要包含祖先节点, 就将祖先节点也设置为保留节点 + for (Node parent : node.getAllAncestorNodes()) { + keepNodes.put(parent, null); + } + } + if (descendant) { + // 如果需要包含后代节点, 就将后代节点也设置为保留节点 + for (Node child : node.getAllDescendantNodes()) { + keepNodes.put(child, null); + } + } + } + } + // 根节点集合 + List> rootNodes = new ArrayList<>(); + // key=原节点, value=复制的新节点 + Map, Node> nodeCopies = new LinkedHashMap<>(); + Iterator> iterator = this.breadthFirstNodeIterator(); while (iterator.hasNext()) { Node node = iterator.next(); - if (node.parent == this) { - myChildren.add(node.element); - } else { - List> children = node.children; - List temp = new ArrayList<>(); - for (Node child : children) { - temp.add(child.element); + // 遇到保留节点 + if (keepNodes.containsKey(node)) { + // 复制副本 + Node newer = new Node<>(node.element); + nodeCopies.put(node, newer); + if (node.parent == null || !keepNodes.containsKey(node.parent)) { + // 这是一个新的顶级节点 + rootNodes.add(newer); + } else { + // 这到一个子节点 + Node pNode = nodeCopies.get(node.parent); + // 遍历时一定是先遇到父节点再遇到子节点, 所以pNode不可能为空 + // 将子节点加入父节点副本中 + pNode.addChildNode(newer); } - childSetter.accept(node.element, temp); } } - childSetter.accept(this.element, myChildren); + Node container = new Node<>(null); + container.addChildNodes(rootNodes); + return container; } @Override -- Gitee From 6b5a4ab910251e6247aaeb6754c7dd42d6a3d323 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 23 Aug 2023 22:56:41 +0800 Subject: [PATCH 32/54] =?UTF-8?q?Json=E5=B7=A5=E5=85=B7=E5=A2=9E=E5=8A=A0p?= =?UTF-8?q?arseAs(Type)=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/gitee/qdbp/json/JsonService.java | 10 ++++ .../com/gitee/qdbp/tools/utils/JsonTools.java | 16 +++++++ .../gitee/qdbp/json/JsonServiceForBase.java | 6 +++ .../qdbp/json/JsonServiceForFastjson.java | 16 +++++++ .../gitee/qdbp/json/JsonServiceForGson.java | 47 +++++++++++++++++-- .../qdbp/json/JsonServiceForJackson.java | 21 +++++++++ 6 files changed, 112 insertions(+), 4 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/json/JsonService.java b/able/src/main/java/com/gitee/qdbp/json/JsonService.java index e014d63..2c019b1 100644 --- a/able/src/main/java/com/gitee/qdbp/json/JsonService.java +++ b/able/src/main/java/com/gitee/qdbp/json/JsonService.java @@ -1,5 +1,6 @@ package com.gitee.qdbp.json; +import java.lang.reflect.Type; import java.util.Collection; import java.util.List; import java.util.Map; @@ -12,6 +13,9 @@ import java.util.Map; */ public interface JsonService { + /** 数据类型转换 **/ + T convert(Object object, Type type); + /** 数据类型转换 **/ T convert(Object object, Class clazz); @@ -33,6 +37,12 @@ public interface JsonService { /** 解析Json字符串数组 **/ List> parseAsMaps(String jsonString, JsonFeature.Deserialization feature); + /** 解析Json字符串对象 **/ + T parseAsObject(String jsonString, Type type); + + /** 解析Json字符串对象 **/ + T parseAsObject(String jsonString, Type type, JsonFeature.Deserialization feature); + /** 解析Json字符串对象 **/ T parseAsObject(String jsonString, Class clazz); diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java index ca02ac1..9ce11ac 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java @@ -1,5 +1,6 @@ package com.gitee.qdbp.tools.utils; +import java.lang.reflect.Type; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Collection; @@ -24,6 +25,11 @@ public class JsonTools extends JsonMaps { private JsonTools() { } + @SuppressWarnings("unchecked") + public static T convert(Object object, Type type) { + return findDefaultJsonService().convert(object, type); + } + @SuppressWarnings("unchecked") public static T convert(Object object, Class clazz) { if (object == null) { @@ -172,6 +178,16 @@ public class JsonTools extends JsonMaps { return findDefaultJsonService().parseAsMaps(jsonString, feature); } + /** 解析Json字符串对象 **/ + public static T parseAsObject(String jsonString, Type type) { + return findDefaultJsonService().parseAsObject(jsonString, type); + } + + /** 解析Json字符串对象 **/ + public static T parseAsObject(String jsonString, Type type, JsonFeature.Deserialization feature) { + return findDefaultJsonService().parseAsObject(jsonString, type, feature); + } + /** 解析Json字符串对象 **/ public static T parseAsObject(String jsonString, Class clazz) { return findDefaultJsonService().parseAsObject(jsonString, clazz); diff --git a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java index a6f2f0d..f67e211 100644 --- a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java +++ b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java @@ -1,6 +1,7 @@ package com.gitee.qdbp.json; import java.lang.reflect.Field; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -31,6 +32,11 @@ public abstract class JsonServiceForBase implements JsonService { this.deserializationFeature = deserializationFeature.copy().lockToUnmodifiable(); } + @Override + public T parseAsObject(String jsonString, Type type) { + return parseAsObject(jsonString, type, deserializationFeature); + } + @Override public T parseAsObject(String jsonString, Class clazz) { return parseAsObject(jsonString, clazz, deserializationFeature); diff --git a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForFastjson.java b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForFastjson.java index a178ed5..2524829 100644 --- a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForFastjson.java +++ b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForFastjson.java @@ -1,6 +1,7 @@ package com.gitee.qdbp.json; import java.lang.reflect.Array; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -75,6 +76,12 @@ public class JsonServiceForFastjson extends JsonServiceForBase { return TypeUtils.castToJavaBean(object, clazz); } + @Override + public T convert(Object object, Type type) { + ParserConfig parserConfig = ParserConfig.getGlobalInstance(); + return TypeUtils.cast(object, type, parserConfig); + } + @Override public String toJsonString(Object object, JsonFeature.Serialization feature) { if (object == null) { @@ -87,6 +94,15 @@ public class JsonServiceForFastjson extends JsonServiceForBase { } } + @Override + public T parseAsObject(String jsonString, Type type, JsonFeature.Deserialization feature) { + if (jsonString == null || jsonString.trim().length() == 0) { + return null; + } + Feature[] features = generateParserFeatures(feature); + return JSON.parseObject(jsonString, type, features); + } + @Override public T parseAsObject(String jsonString, Class clazz, JsonFeature.Deserialization feature) { if (jsonString == null || jsonString.trim().length() == 0) { diff --git a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForGson.java b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForGson.java index 0ef7b30..dfb9020 100644 --- a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForGson.java +++ b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForGson.java @@ -8,6 +8,8 @@ import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import com.google.gson.ExclusionStrategy; +import com.google.gson.FieldAttributes; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; @@ -26,6 +28,12 @@ import com.google.gson.reflect.TypeToken; */ public class JsonServiceForGson extends JsonServiceForBase { + @Override + public T convert(Object object, Type type) { + String string = toJsonString(object, serializationFeature); + return parseAsObject(string, type, deserializationFeature); + } + @Override public T convert(Object object, Class clazz) { String string = toJsonString(object, serializationFeature); @@ -61,6 +69,15 @@ public class JsonServiceForGson extends JsonServiceForBase { return gson.fromJson(jsonString, type); } + @Override + public T parseAsObject(String jsonString, Type type, JsonFeature.Deserialization feature) { + if (jsonString == null || jsonString.trim().length() == 0) { + return null; + } + Gson gson = generateGson(serializationFeature, feature); + return gson.fromJson(jsonString, type); + } + @Override public T parseAsObject(String jsonString, Class clazz, JsonFeature.Deserialization feature) { if (jsonString == null || jsonString.trim().length() == 0) { @@ -88,6 +105,14 @@ public class JsonServiceForGson extends JsonServiceForBase { builder.setLenient(); // 默认的转数字策略是ToNumberPolicy.DOUBLE, 导致所有的整数全转换为double了 builder.setObjectToNumberStrategy(ToNumberPolicy.LAZILY_PARSED_NUMBER); + // 排除STATIC/FINAL字段 + builder.excludeFieldsWithModifiers(Modifier.STATIC); + builder.excludeFieldsWithModifiers(Modifier.FINAL); + // 是否跳过transient修饰的字段 + if (sf.isSkipTransientField()) { + builder.excludeFieldsWithModifiers(Modifier.TRANSIENT); + } + builder.addDeserializationExclusionStrategy(new GsonExclusionStrategy(sf)); // 是否处理循环引用 (设置为true时不应该报错) // mapper.configure(SerializationFeature.FAIL_ON_SELF_REFERENCES, false); @@ -128,10 +153,6 @@ public class JsonServiceForGson extends JsonServiceForBase { if (sf.isWriteBigDecimalAsPlain()) { builder.registerTypeAdapter(BigDecimal.class, new BigDecimalToPlainStringSerializer()); } - // 是否跳过transient修饰的字段 - if (sf.isSkipTransientField()) { - builder.excludeFieldsWithModifiers(Modifier.TRANSIENT); - } // 是否输出格式化后的Json字符串 if (sf.isPrettyFormat()) { builder.setPrettyPrinting(); @@ -162,6 +183,24 @@ public class JsonServiceForGson extends JsonServiceForBase { return builder.create(); } + private static class GsonExclusionStrategy implements ExclusionStrategy { + private final JsonFeature.Serialization sf; + public GsonExclusionStrategy(JsonFeature.Serialization sf) { + this.sf = sf; + } + + @Override + public boolean shouldSkipField(FieldAttributes f) { + return f.hasModifier(Modifier.FINAL) || f.hasModifier(Modifier.STATIC) || + sf.isSkipTransientField() && f.hasModifier(Modifier.TRANSIENT); + } + + @Override + public boolean shouldSkipClass(Class clazz) { + return false; + } + } + private static class BigDecimalToPlainStringSerializer implements JsonSerializer { @Override public JsonElement serialize(BigDecimal src, Type typeOfSrc, JsonSerializationContext context) { diff --git a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForJackson.java b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForJackson.java index dafb4b3..cb3ccb2 100644 --- a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForJackson.java +++ b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForJackson.java @@ -1,6 +1,7 @@ package com.gitee.qdbp.json; import java.io.IOException; +import java.lang.reflect.Type; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -31,6 +32,12 @@ public class JsonServiceForJackson extends JsonServiceForBase { return parseAsObject(string, clazz, deserializationFeature); } + @Override + public T convert(Object object, Type type) { + String string = toJsonString(object, serializationFeature); + return parseAsObject(string, type, deserializationFeature); + } + @Override public String toJsonString(Object object, JsonFeature.Serialization feature) { if (object == null) { @@ -71,6 +78,20 @@ public class JsonServiceForJackson extends JsonServiceForBase { } } + @Override + public T parseAsObject(String jsonString, Type type, JsonFeature.Deserialization feature) { + if (jsonString == null || jsonString.trim().length() == 0) { + return null; + } + ObjectMapper mapper = generateObjectMapper(serializationFeature, feature); + JavaType javaType = mapper.getTypeFactory().constructType(type); + try { + return mapper.readValue(jsonString, javaType); + } catch (IOException e) { + throw new ServiceException(ResultCode.SERVER_INNER_ERROR, e).setDetails("parse json object string error"); + } + } + @Override public T parseAsObject(String jsonString, Class clazz, JsonFeature.Deserialization feature) { if (jsonString == null || jsonString.trim().length() == 0) { -- Gitee From 693016849aae923e8bf688b06b88ec490e396021 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 23 Aug 2023 22:57:27 +0800 Subject: [PATCH 33/54] =?UTF-8?q?=E9=97=AE=E9=A2=98=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=8F=8A=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../qdbp/tools/compare/CompareTools.java | 20 +++++++++++++++---- .../com/gitee/qdbp/tools/utils/MapTools.java | 6 ++++++ .../gitee/qdbp/tools/utils/ReflectTools.java | 13 ++++++++++++ .../qdbp/tools/utils/ThrowableToStrings.java | 5 +++-- 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/compare/CompareTools.java b/able/src/main/java/com/gitee/qdbp/tools/compare/CompareTools.java index db30486..a4bd946 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/compare/CompareTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/compare/CompareTools.java @@ -52,25 +52,37 @@ public class CompareTools { */ @SuppressWarnings("all") public static void sort(List> list, Orderings orderings) { + sort(list, orderings, false); + } + + /** + * 对Map列表进行排序 + * + * @param list 列表数据 + * @param orderings 排序规则, e.g. Orderings.of("dept desc, birthday asc, name desc"); + * @param nullsLow 空值优先级: true=空值排最前, false=空值排最后 + */ + @SuppressWarnings("all") + public static void sort(List> list, Orderings orderings, boolean nullsLow) { if (list == null || list.isEmpty() || orderings == null || orderings.isEmpty()) { return; } if (orderings.size() == 1) { - Collections.sort(list, newMapFieldComparator(orderings.get(0))); + Collections.sort(list, newMapFieldComparator(orderings.get(0), nullsLow)); return; } // dept desc, birthday asc, name desc ComplexComparator> comparator = new ComplexComparator<>(); for (Ordering ordering : orderings) { - comparator.addComparator(newMapFieldComparator(ordering)); + comparator.addComparator(newMapFieldComparator(ordering, nullsLow)); } Collections.sort(list, comparator); } - private static MapFieldComparator newMapFieldComparator(Ordering ordering) { + private static MapFieldComparator newMapFieldComparator(Ordering ordering, boolean nullsLow) { String orderBy = ordering.getOrderBy(); boolean ascending = !OrderType.DESC.equals(ordering.getOrderType()); - return new MapFieldComparator<>(orderBy, ascending); + return new MapFieldComparator<>(orderBy, nullsLow, ascending); } /** 链式比较多个字段 **/ diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java index faa9042..d422c93 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java @@ -395,6 +395,9 @@ public class MapTools { * @return 是否存在 */ public static boolean containsKey(Map map, String key) { + if (map == null) { + return false; + } if (key == null || map.containsKey(key)) { return map.containsKey(key); } else if (isComplexKey(key)) { @@ -424,6 +427,9 @@ public class MapTools { * @return Map值 */ public static Object getValue(Map map, String key) { + if (map == null) { + return null; + } if (key == null || map.containsKey(key)) { if (map instanceof ExpressionMap) { return ((ExpressionMap) map).getOriginal(key); diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java index 4aebb58..e5f213a 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java @@ -1066,6 +1066,19 @@ public abstract class ReflectTools { return getMethodLogSignature(clazz, clazz.getSimpleName(), constructor.getParameterTypes()); } + /** + * 获取方法签名的简要描述 + * + * @param method 方法 + * @return 方法签名描述 + */ + public static String getMethodLogSignature(Method method) { + Class clazz = method.getDeclaringClass(); + String methodName = method.getName(); + Class[] parameterTypes = method.getParameterTypes(); + return getMethodLogSignature(clazz, methodName, parameterTypes); + } + /** * 获取方法签名的简要描述 * diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ThrowableToStrings.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ThrowableToStrings.java index ee2e47e..33d6630 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ThrowableToStrings.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ThrowableToStrings.java @@ -40,8 +40,9 @@ public class ThrowableToStrings { int size = 0; for (int i = 0; i < (ste.length - numberOfcommonFrames); i++) { // size<1, 保留报错的那一行信息 - if (size < 1 || matcher == null || matcher.matches(ste[i].getClassName())) { - strList.add("\tat " + ste[i].toString()); + String trace = ste[i].toString(); + if (size < 1 || matcher == null || matcher.matches(trace)) { + strList.add("\tat " + trace); size++; } } -- Gitee From a09ede1e1f14e100fd7e8f94c4993854770360cd Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 23 Aug 2023 22:57:44 +0800 Subject: [PATCH 34/54] =?UTF-8?q?=E9=97=AE=E9=A2=98=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=8F=8A=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/gitee/qdbp/able/exception/ServiceException.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java b/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java index bc03520..6f3f7a0 100644 --- a/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java +++ b/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java @@ -88,6 +88,11 @@ public class ServiceException extends RuntimeException implements IResultExcepti this.details = details; } + /** 判断是不是特定的异常 **/ + public boolean is(IResultMessage rm) { + return rm.getCode().equals(this.getCode()); + } + /** * 获取错误返回码 * -- Gitee From cebdfb0b3d983cf71da22eae681e1eabb4a73ee1 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 23 Aug 2023 22:58:35 +0800 Subject: [PATCH 35/54] =?UTF-8?q?=E5=A2=9E=E5=8A=A0json=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/json/test/TestCase1.java | 31 +++++++++++++++++++ .../qdbp/json/test/TestCase1ForFastJson.java | 5 +++ .../qdbp/json/test/TestCase1ForGson.java | 5 +++ .../qdbp/json/test/TestCase1ForJackson.java | 5 +++ 4 files changed, 46 insertions(+) diff --git a/test/qdbp-json-test-base/src/main/java/com/gitee/qdbp/json/test/TestCase1.java b/test/qdbp-json-test-base/src/main/java/com/gitee/qdbp/json/test/TestCase1.java index ee0d28f..62acfe0 100644 --- a/test/qdbp-json-test-base/src/main/java/com/gitee/qdbp/json/test/TestCase1.java +++ b/test/qdbp-json-test-base/src/main/java/com/gitee/qdbp/json/test/TestCase1.java @@ -1,18 +1,25 @@ package com.gitee.qdbp.json.test; +import java.lang.reflect.Method; +import java.lang.reflect.Type; import java.math.BigDecimal; import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.testng.Assert; +import com.gitee.qdbp.able.beans.KeyValue; import com.gitee.qdbp.json.JsonFeature; import com.gitee.qdbp.json.JsonService; import com.gitee.qdbp.json.test.entity.Address; import com.gitee.qdbp.json.test.entity.Child; import com.gitee.qdbp.json.test.entity.Father; import com.gitee.qdbp.json.test.entity.Gender; +import com.gitee.qdbp.tools.utils.AssertTools; import com.gitee.qdbp.tools.utils.JsonTools; import com.gitee.qdbp.tools.utils.MapTools; +import com.gitee.qdbp.tools.utils.ReflectTools; /** * TestCase1 @@ -109,4 +116,28 @@ public class TestCase1 { int n1 = JsonTools.convert(null, int.class); Assert.assertEquals(n1, 0); } + + public void test7() { + Method method = ReflectTools.findMethod(ResultType.class, "test"); + Type returnType = method.getGenericReturnType(); + KeyValue item = new KeyValue<>("A001", 10001); + Map source = new LinkedHashMap<>(); + source.put("1", item); + + String jsonString = JsonTools.toJsonString(source); + System.out.println(jsonString); + Map> result = JsonTools.parseAsObject(jsonString, returnType); + + AssertTools.assertDeepEquals(result.keySet(), Collections.singleton(1)); + KeyValue object = result.get(1); + Assert.assertEquals(object.getClass(), KeyValue.class); + Assert.assertEquals(object.getValue().getClass(), Long.class); + } + + public static class ResultType { + + public Map> test() { + return null; + } + } } diff --git a/test/qdbp-json-test-fastjson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForFastJson.java b/test/qdbp-json-test-fastjson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForFastJson.java index 73db2a1..01c664a 100644 --- a/test/qdbp-json-test-fastjson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForFastJson.java +++ b/test/qdbp-json-test-fastjson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForFastJson.java @@ -45,4 +45,9 @@ public class TestCase1ForFastJson extends TestCase1 { public void test6() { super.test6(); } + + @Test + public void test7() { + super.test7(); + } } diff --git a/test/qdbp-json-test-gson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForGson.java b/test/qdbp-json-test-gson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForGson.java index c40bc99..e72fdfa 100644 --- a/test/qdbp-json-test-gson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForGson.java +++ b/test/qdbp-json-test-gson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForGson.java @@ -40,4 +40,9 @@ public class TestCase1ForGson extends TestCase1 { public void test6() { super.test6(); } + + @Test + public void test7() { + super.test7(); + } } diff --git a/test/qdbp-json-test-jackson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForJackson.java b/test/qdbp-json-test-jackson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForJackson.java index b4803b6..dd260c8 100644 --- a/test/qdbp-json-test-jackson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForJackson.java +++ b/test/qdbp-json-test-jackson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForJackson.java @@ -46,4 +46,9 @@ public class TestCase1ForJackson extends TestCase1 { public void test6() { super.test6(); } + + @Test + public void test7() { + super.test7(); + } } -- Gitee From e9d548b6767f6d1d589aedd673b7dd167524d350 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 23 Aug 2023 22:59:04 +0800 Subject: [PATCH 36/54] =?UTF-8?q?=E5=A2=9E=E5=8A=A0TreeNodes=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/able/beans/TreeNodesTest.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java b/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java index 244ba30..c323319 100644 --- a/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java +++ b/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java @@ -104,6 +104,12 @@ public class TreeNodesTest { "T0301", "T030101", "T030103", "T030104", "T030105", "T0303", "T030301", "T030303", "T030304", "T030305")); } + + tree.removeElements("T02"); + List currElements = tree.getAllLeafElements(); + AssertTools.assertDeepEquals(currElements, Arrays.asList( + "T010101", "T010103", "T010104", "T010105", "T010301", "T010303", "T010304", "T010305", + "T030101", "T030103", "T030104", "T030105", "T030301", "T030303", "T030304", "T030305")); } public void test2() { @@ -194,6 +200,12 @@ public class TreeNodesTest { "T0301", "T030101", "T030103", "T030104", "T030105", "T0303", "T030301", "T030303", "T030304", "T030305")); } + + tree.removeElements("T02"); + List currElements = tree.getAllLeafElements(); + AssertTools.assertDeepEquals(currElements, asTreeNodeList( + "T010101", "T010103", "T010104", "T010105", "T010301", "T010303", "T010304", "T010305", + "T030101", "T030103", "T030104", "T030105", "T030301", "T030303", "T030304", "T030305")); } @@ -213,7 +225,7 @@ public class TreeNodesTest { return beans; } - private List asTreeNodeList(String ... codes) { + private List asTreeNodeList(String... codes) { List beans = new ArrayList<>(); for (String item : codes) { beans.add(new TreeNode(item)); -- Gitee From c21923e2edc47f69600388d1836e134ad82f5b69 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 23 Aug 2023 23:00:15 +0800 Subject: [PATCH 37/54] 5.6.230820 --- README.md | 4 ++-- able/pom.xml | 2 +- json/pom.xml | 4 ++-- test/pom.xml | 2 +- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- test/qdbp-tools-test-jdk8/pom.xml | 2 +- tools/pom.xml | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 98bb1ac..adc0bae 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.6.230815 + 5.6.230820 ``` ```xml com.gitee.qdbp qdbp-tools - 5.6.230815 + 5.6.230820 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index a473a2c..2e07f68 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.6.230815 + 5.6.230820 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ diff --git a/json/pom.xml b/json/pom.xml index 77f42ab..987828f 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.6.230815 + 5.6.230820 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.6.230815 + 5.6.230820 diff --git a/test/pom.xml b/test/pom.xml index 8021f0e..2e54e0c 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.6.230815 + 5.6.230820 https://gitee.com/qdbp/qdbp-able/ qdbp json test diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index 2498d6e..d250b47 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230815 + 5.6.230820 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index 29e661c..11184c2 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230815 + 5.6.230820 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index 857ab51..f734508 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230815 + 5.6.230820 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index eb01039..71122cf 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230815 + 5.6.230820 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index 924f81e..2c0c6b2 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230815 + 5.6.230820 qdbp-tools-test-jdk7 diff --git a/test/qdbp-tools-test-jdk8/pom.xml b/test/qdbp-tools-test-jdk8/pom.xml index a09f689..d906897 100644 --- a/test/qdbp-tools-test-jdk8/pom.xml +++ b/test/qdbp-tools-test-jdk8/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230815 + 5.6.230820 qdbp-tools-test-jdk8 diff --git a/tools/pom.xml b/tools/pom.xml index 25117f4..4d6b05c 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.6.230815 + 5.6.230820 https://gitee.com/qdbp/qdbp-able/ qdbp tools library -- Gitee From f8ed26e00c27592c95143e2e643f16ab9cbcffd9 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 19:12:26 +0800 Subject: [PATCH 38/54] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=85=AC=E5=85=B1?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E8=BF=94=E5=9B=9E=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/gitee/qdbp/able/result/ResultCode.java | 6 ++++++ .../resources/settings/i18n/ResultCode_zh_CN.properties | 2 ++ 2 files changed, 8 insertions(+) diff --git a/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java b/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java index d4836d5..702996d 100644 --- a/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java +++ b/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java @@ -79,6 +79,12 @@ public enum ResultCode implements IResultMessage { /** 系统配置错误 **/ SYSTEM_CONFIG_ERROR, + /** 系统配置不存在 **/ + SYSTEM_CONFIG_NOT_FOUND, + + /** 数据转换失败 **/ + DATA_CONVERT_ERROR, + /** 不支持该操作 **/ UNSUPPORTED_OPERATION; diff --git a/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties b/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties index da5ddc3..627aa3d 100644 --- a/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties +++ b/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties @@ -22,4 +22,6 @@ FORBIDDEN = 没有权限 ACCESS_DENIED = 访问被拒绝 OPERATE_TIMEOUT = 操作已超时 SYSTEM_CONFIG_ERROR = 系统配置错误 +SYSTEM_CONFIG_NOT_FOUND = 系统配置不存在 +DATA_CONVERT_ERROR = 数据转换失败 UNSUPPORTED_OPERATION = 不支持该操作 -- Gitee From 6727b4f6f4d9da55e4793e1e8adbad18f053d847 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 19:14:11 +0800 Subject: [PATCH 39/54] tryCopyObject --- .../com/gitee/qdbp/tools/utils/ConvertTools.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java index 8ba11a7..8905d05 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java @@ -1686,6 +1686,20 @@ public class ConvertTools { return result; } + /** + * 深度复制对象
+ * 调用Copyable的copy()方法进行复制
+ * List/Set/Map容器将会循环递归复制其中的内容
+ * 与deepCopyObject的不同是, 这个方法不会抛出异常 + * + * @param value 原对象 + * @return 复制后的对象 + * @param 对象类型 + */ + public static T tryCopyObject(T value) { + return doDeepCopyObject(value); + } + @SuppressWarnings("unchecked") private static T doDeepCopyObject(T value) { if (value == null) { -- Gitee From 8d7f6471b3997a6b6e7571b1715b8484029f05bb Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 19:15:51 +0800 Subject: [PATCH 40/54] =?UTF-8?q?=E5=A2=9E=E5=8A=A0ClassTools?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/tools/utils/ClassTools.java | 317 ++++++++++++++++++ 1 file changed, 317 insertions(+) create mode 100644 able/src/main/java/com/gitee/qdbp/tools/utils/ClassTools.java diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ClassTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ClassTools.java new file mode 100644 index 0000000..89f5e71 --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ClassTools.java @@ -0,0 +1,317 @@ +/* + * Copyright 2002-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.gitee.qdbp.tools.utils; + +import java.io.Closeable; +import java.io.Externalizable; +import java.io.Serializable; +import java.lang.reflect.Array; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + + +/** + * Miscellaneous {@code java.lang.Class} utility methods. + * Mainly for internal use within the framework. + * + * @author Juergen Hoeller + * @author Keith Donald + * @author Rob Harrop + * @author Sam Brannen + * @since 1.1 + */ +public abstract class ClassTools { + + /** Suffix for array class names: {@code "[]"}. */ + public static final String ARRAY_SUFFIX = "[]"; + + /** Prefix for internal array class names: {@code "["}. */ + private static final String INTERNAL_ARRAY_PREFIX = "["; + + /** Prefix for internal non-primitive array class names: {@code "[L"}. */ + private static final String NON_PRIMITIVE_ARRAY_PREFIX = "[L"; + + /** The package separator character: {@code '.'}. */ + private static final char PACKAGE_SEPARATOR = '.'; + + /** The nested class separator character: {@code '$'}. */ + private static final char NESTED_CLASS_SEPARATOR = '$'; + + /** The CGLIB class separator: {@code "$$"}. */ + public static final String CGLIB_CLASS_SEPARATOR = "$$"; + + /** The ".class" file suffix. */ + public static final String CLASS_FILE_SUFFIX = ".class"; + + /** + * Map with primitive wrapper type as key and corresponding primitive + * type as value, for example: Integer.class -> int.class. + */ + private static final Map, Class> primitiveWrapperTypeMap = new IdentityHashMap<>(9); + + /** + * Map with primitive type name as key and corresponding primitive + * type as value, for example: "int" -> "int.class". + */ + private static final Map> primitiveTypeNameMap = new HashMap<>(32); + + /** + * Map with common Java language class name as key and corresponding Class as value. + * Primarily for efficient deserialization of remote invocations. + */ + private static final Map> commonClassCache = new HashMap<>(64); + + static { + primitiveWrapperTypeMap.put(Boolean.class, boolean.class); + primitiveWrapperTypeMap.put(Byte.class, byte.class); + primitiveWrapperTypeMap.put(Character.class, char.class); + primitiveWrapperTypeMap.put(Double.class, double.class); + primitiveWrapperTypeMap.put(Float.class, float.class); + primitiveWrapperTypeMap.put(Integer.class, int.class); + primitiveWrapperTypeMap.put(Long.class, long.class); + primitiveWrapperTypeMap.put(Short.class, short.class); + primitiveWrapperTypeMap.put(Void.class, void.class); + + Set> primitiveTypes = new HashSet<>(32); + primitiveTypes.addAll(primitiveWrapperTypeMap.values()); + Collections.addAll(primitiveTypes, boolean[].class, byte[].class, char[].class, + double[].class, float[].class, int[].class, long[].class, short[].class); + for (Class primitiveType : primitiveTypes) { + primitiveTypeNameMap.put(primitiveType.getName(), primitiveType); + } + + registerCommonClasses(Boolean[].class, Byte[].class, Character[].class, Double[].class, + Float[].class, Integer[].class, Long[].class, Short[].class); + registerCommonClasses(Number.class, Number[].class, String.class, String[].class, + Class.class, Class[].class, Object.class, Object[].class); + registerCommonClasses(Throwable.class, Exception.class, RuntimeException.class, + Error.class, StackTraceElement.class, StackTraceElement[].class); + registerCommonClasses(Enum.class, Iterable.class, Iterator.class, Enumeration.class, + Collection.class, List.class, Set.class, Map.class, Map.Entry.class, Optional.class); + + Class[] javaLanguageInterfaceArray = {Serializable.class, Externalizable.class, + Closeable.class, AutoCloseable.class, Cloneable.class, Comparable.class}; + registerCommonClasses(javaLanguageInterfaceArray); + } + + + /** + * Register the given common classes with the ClassUtils cache. + */ + private static void registerCommonClasses(Class... commonClasses) { + for (Class clazz : commonClasses) { + commonClassCache.put(clazz.getName(), clazz); + } + } + + /** + * Return the default ClassLoader to use: typically the thread context + * ClassLoader, if available; the ClassLoader that loaded the ClassUtils + * class will be used as fallback. + *

Call this method if you intend to use the thread context ClassLoader + * in a scenario where you clearly prefer a non-null ClassLoader reference: + * for example, for class path resource loading (but not necessarily for + * {@code Class.forName}, which accepts a {@code null} ClassLoader + * reference as well). + * @return the default ClassLoader (only {@code null} if even the system + * ClassLoader isn't accessible) + * @see Thread#getContextClassLoader() + * @see ClassLoader#getSystemClassLoader() + */ + public static ClassLoader getDefaultClassLoader() { + ClassLoader cl = null; + try { + cl = Thread.currentThread().getContextClassLoader(); + } + catch (Throwable ex) { + // Cannot access thread context ClassLoader - falling back... + } + if (cl == null) { + // getClassLoader() returning null indicates the bootstrap ClassLoader + try { + cl = ClassLoader.getSystemClassLoader(); + } + catch (Throwable ex) { + // Cannot access system ClassLoader - oh well, maybe the caller can live with null... + } + } + return cl; + } + + /** + * Replacement for {@code Class.forName()} that also returns Class instances + * for primitives (e.g. "int") and array class names (e.g. "String[]"). + * Furthermore, it is also capable of resolving nested class names in Java source + * style (e.g. "java.lang.Thread.State" instead of "java.lang.Thread$State"). + * @param name the name of the Class + * (may be {@code null}, which indicates the default class loader) + * @return a class instance for the supplied name + * @throws ClassNotFoundException if the class was not found + * @throws LinkageError if the class file could not be loaded + * @see Class#forName(String, boolean, ClassLoader) + */ + public static Class forName(String name) throws ClassNotFoundException, LinkageError { + return forName(name, null); + } + + /** + * Replacement for {@code Class.forName()} that also returns Class instances + * for primitives (e.g. "int") and array class names (e.g. "String[]"). + * Furthermore, it is also capable of resolving nested class names in Java source + * style (e.g. "java.lang.Thread.State" instead of "java.lang.Thread$State"). + * @param name the name of the Class + * @param classLoader the class loader to use + * (may be {@code null}, which indicates the default class loader) + * @return a class instance for the supplied name + * @throws ClassNotFoundException if the class was not found + * @throws LinkageError if the class file could not be loaded + * @see Class#forName(String, boolean, ClassLoader) + */ + public static Class forName(String name, ClassLoader classLoader) + throws ClassNotFoundException, LinkageError { + + VerifyTools.requireNonNull(name, "className"); + + Class clazz = resolvePrimitiveClassName(name); + if (clazz == null) { + clazz = commonClassCache.get(name); + } + if (clazz != null) { + return clazz; + } + + // "java.lang.String[]" style arrays + if (name.endsWith(ARRAY_SUFFIX)) { + String elementClassName = name.substring(0, name.length() - ARRAY_SUFFIX.length()); + Class elementClass = forName(elementClassName, classLoader); + return Array.newInstance(elementClass, 0).getClass(); + } + + // "[Ljava.lang.String;" style arrays + if (name.startsWith(NON_PRIMITIVE_ARRAY_PREFIX) && name.endsWith(";")) { + String elementName = name.substring(NON_PRIMITIVE_ARRAY_PREFIX.length(), name.length() - 1); + Class elementClass = forName(elementName, classLoader); + return Array.newInstance(elementClass, 0).getClass(); + } + + // "[[I" or "[[Ljava.lang.String;" style arrays + if (name.startsWith(INTERNAL_ARRAY_PREFIX)) { + String elementName = name.substring(INTERNAL_ARRAY_PREFIX.length()); + Class elementClass = forName(elementName, classLoader); + return Array.newInstance(elementClass, 0).getClass(); + } + + ClassLoader clToUse = classLoader; + if (clToUse == null) { + clToUse = getDefaultClassLoader(); + } + try { + return Class.forName(name, false, clToUse); + } + catch (ClassNotFoundException ex) { + int lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR); + if (lastDotIndex != -1) { + String nestedClassName = + name.substring(0, lastDotIndex) + NESTED_CLASS_SEPARATOR + name.substring(lastDotIndex + 1); + try { + return Class.forName(nestedClassName, false, clToUse); + } + catch (ClassNotFoundException ex2) { + // Swallow - let original exception get through + } + } + throw ex; + } + } + + /** + * Determine whether the {@link Class} identified by the supplied name is present + * and can be loaded. Will return {@code false} if either the class or + * one of its dependencies is not present or cannot be loaded. + * @param className the name of the class to check + * (may be {@code null} which indicates the default class loader) + * @return whether the specified class is present (including all of its + * superclasses and interfaces) + * @throws IllegalStateException if the corresponding class is resolvable but + * there was a readability mismatch in the inheritance hierarchy of the class + * (typically a missing dependency declaration in a Jigsaw module definition + * for a superclass or interface implemented by the class to be checked here) + */ + public static boolean isPresent(String className) { + return isPresent(className, null); + } + + /** + * Determine whether the {@link Class} identified by the supplied name is present + * and can be loaded. Will return {@code false} if either the class or + * one of its dependencies is not present or cannot be loaded. + * @param className the name of the class to check + * @param classLoader the class loader to use + * (may be {@code null} which indicates the default class loader) + * @return whether the specified class is present (including all of its + * superclasses and interfaces) + * @throws IllegalStateException if the corresponding class is resolvable but + * there was a readability mismatch in the inheritance hierarchy of the class + * (typically a missing dependency declaration in a Jigsaw module definition + * for a superclass or interface implemented by the class to be checked here) + */ + public static boolean isPresent(String className, ClassLoader classLoader) { + try { + forName(className, classLoader); + return true; + } + catch (IllegalAccessError err) { + throw new IllegalStateException("Readability mismatch in inheritance hierarchy of class [" + + className + "]: " + err.getMessage(), err); + } + catch (Throwable ex) { + // Typically ClassNotFoundException or NoClassDefFoundError... + return false; + } + } + + /** + * Resolve the given class name as primitive class, if appropriate, + * according to the JVM's naming rules for primitive classes. + *

Also supports the JVM's internal class names for primitive arrays. + * Does not support the "[]" suffix notation for primitive arrays; + * this is only supported by {@link #forName(String, ClassLoader)}. + * @param name the name of the potentially primitive class + * @return the primitive class, or {@code null} if the name does not denote + * a primitive class or primitive array class + */ + public static Class resolvePrimitiveClassName(String name) { + Class result = null; + // Most class names will be quite long, considering that they + // SHOULD sit in a package, so a length check is worthwhile. + if (name != null && name.length() <= 7) { + // Could be a primitive - likely. + result = primitiveTypeNameMap.get(name); + } + return result; + } + +} -- Gitee From 0947e557a7073dd82ff326893f7445bc62febb4e Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 19:29:01 +0800 Subject: [PATCH 41/54] =?UTF-8?q?=E5=B7=A5=E5=85=B7=E7=B1=BB=E5=A2=9E?= =?UTF-8?q?=E5=BC=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/tools/files/PathTools.java | 50 ++++++++++++------- .../gitee/qdbp/tools/utils/JsonFactory.java | 24 +++------ .../qdbp/tools/utils/ThrowableToStrings.java | 8 +-- .../{json-service.yml => JsonService.yml} | 0 4 files changed, 42 insertions(+), 40 deletions(-) rename able/src/main/resources/settings/global/{json-service.yml => JsonService.yml} (100%) diff --git a/able/src/main/java/com/gitee/qdbp/tools/files/PathTools.java b/able/src/main/java/com/gitee/qdbp/tools/files/PathTools.java index 9b3f925..9ee481b 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/files/PathTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/files/PathTools.java @@ -33,12 +33,16 @@ import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.regex.Pattern; import java.util.zip.ZipException; +import com.gitee.qdbp.able.beans.KeyString; +import com.gitee.qdbp.able.enums.FileErrorCode; import com.gitee.qdbp.able.exception.ResourceNotFoundException; +import com.gitee.qdbp.able.exception.ServiceException; import com.gitee.qdbp.able.matches.AntFileMatcher; import com.gitee.qdbp.able.matches.FileMatcher; import com.gitee.qdbp.able.matches.FileMatcher.Target; import com.gitee.qdbp.able.matches.StringMatcher.LogicType; import com.gitee.qdbp.able.matches.WrapFileMatcher; +import com.gitee.qdbp.tools.utils.ClassTools; import com.gitee.qdbp.tools.utils.StringTools; import com.gitee.qdbp.tools.utils.VerifyTools; @@ -205,23 +209,9 @@ public abstract class PathTools { } } + @Deprecated public static ClassLoader getDefaultClassLoader() { - ClassLoader cl = null; - try { - cl = Thread.currentThread().getContextClassLoader(); - } catch (Throwable ex) { - // Cannot access thread context ClassLoader - falling back... - } - if (cl == null) { - // No thread context class loader -> use class loader of this class. - // getClassLoader() returning null indicates the bootstrap ClassLoader - try { - cl = ClassLoader.getSystemClassLoader(); - } catch (Throwable ex) { - // Cannot access system ClassLoader - oh well, maybe the caller can live with null... - } - } - return cl; + return ClassTools.getDefaultClassLoader(); } /** @@ -563,6 +553,28 @@ public abstract class PathTools { } } + /** + * 按名称扫描文本资源并返回文件内容 + * + * @param resource 资源路径, 不支持通配符 + * @return 资源内容, key=文件路径, value=文件内容 + * @throws ResourceNotFoundException 资源查找失败, 资源不存在 + */ + public static KeyString scanTextResource(String resource) { + List urls = PathTools.scanResources(resource); + if (urls.isEmpty()) { + throw new ResourceNotFoundException().setDetails(resource); + } + URL url = urls.get(0); + String urlPath = PathTools.getJarRelativePath(url); + try { + String content = PathTools.downloadString(url); + return new KeyString(urlPath, content); + } catch (IOException e) { + throw new ServiceException(FileErrorCode.FILE_READ_ERROR, e).setDetails(urlPath); + } + } + /** * 查找资源
* classpath:/mmm/nnn.txt = classpath:mmm/nnn.txt -- 相对路径
@@ -863,7 +875,7 @@ public abstract class PathTools { } private static URL getClassLoaderResource(String path) { - ClassLoader cl = getDefaultClassLoader(); + ClassLoader cl = ClassTools.getDefaultClassLoader(); String temp = path; if (path.startsWith("/") || path.startsWith("\\")) { temp = path.substring(1); // 通过ClassLoader获取, 如果路径是/开头的, 会获取失败 @@ -872,7 +884,7 @@ public abstract class PathTools { } private static Enumeration getClassLoaderResources(String path) throws IOException { - ClassLoader cl = getDefaultClassLoader(); + ClassLoader cl = ClassTools.getDefaultClassLoader(); String temp = path; if (path.startsWith("/") || path.startsWith("\\")) { temp = path.substring(1); // 通过ClassLoader获取, 如果路径是/开头的, 会获取失败 @@ -881,7 +893,7 @@ public abstract class PathTools { } private static URL getClassPathUrl() { - ClassLoader cl = getDefaultClassLoader(); + ClassLoader cl = ClassTools.getDefaultClassLoader(); return cl != null ? cl.getResource("") : ClassLoader.getSystemResource(""); } diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/JsonFactory.java b/able/src/main/java/com/gitee/qdbp/tools/utils/JsonFactory.java index 3d06e73..62285b1 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/JsonFactory.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/JsonFactory.java @@ -1,12 +1,10 @@ package com.gitee.qdbp.tools.utils; -import java.io.IOException; -import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Map; +import com.gitee.qdbp.able.beans.KeyString; import com.gitee.qdbp.able.beans.StringWithAttrs; -import com.gitee.qdbp.able.enums.FileErrorCode; import com.gitee.qdbp.able.exception.ServiceException; import com.gitee.qdbp.able.result.ResultCode; import com.gitee.qdbp.json.JsonService; @@ -67,21 +65,13 @@ class JsonFactory { } private static synchronized JsonService findConfigJsonService() { - String configPath = "settings/global/json-service.yml"; - List urls = PathTools.scanResources(configPath); - - URL url = urls.get(0); - String string; - String path = PathTools.getJarRelativePath(url); - try { - string = PathTools.downloadString(url); - } catch (IOException e) { - throw new ServiceException(FileErrorCode.FILE_READ_ERROR, e).setDetails(path); - } - Map roots = RuleTools.splitRuleKeyValues(string).asMap(); + String configPath = "settings/global/JsonService.yml"; + KeyString resource = PathTools.scanTextResource(configPath); + String path = resource.getKey(); + Map roots = RuleTools.splitRuleKeyValues(resource.getValue()).asMap(); String rootValue = roots.get("json-service"); if (VerifyTools.isBlank(rootValue)) { - throw new ServiceException(ResultCode.SYSTEM_CONFIG_ERROR) + throw new ServiceException(ResultCode.SYSTEM_CONFIG_NOT_FOUND) .setDetails("json-service config missing --> " + path); } List contents = RuleTools.splitRuleWithAttrs(rootValue); @@ -138,6 +128,6 @@ class JsonFactory { // 所有requiredClass都不在jvm当中 String msg = "JsonService instance not found for [{}] --> {}"; String traces = ConvertTools.joinToString(names); - throw new ServiceException(ResultCode.SYSTEM_CONFIG_ERROR).setDetails(msg, traces, path); + throw new ServiceException(ResultCode.SERVER_INNER_ERROR).setDetails(msg, traces, path); } } diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ThrowableToStrings.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ThrowableToStrings.java index 33d6630..f518900 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ThrowableToStrings.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ThrowableToStrings.java @@ -34,11 +34,11 @@ public class ThrowableToStrings { StringMatcher matcher) { StackTraceElement[] ste = t.getStackTrace(); - final int numberOfcommonFrames = findNumberOfCommonFrames(ste, parentSTE); + final int numberOfCommonFrames = findNumberOfCommonFrames(ste, parentSTE); strList.add(formatFirstLine(t, parentSTE)); int size = 0; - for (int i = 0; i < (ste.length - numberOfcommonFrames); i++) { + for (int i = 0; i < (ste.length - numberOfCommonFrames); i++) { // size<1, 保留报错的那一行信息 String trace = ste[i].toString(); if (size < 1 || matcher == null || matcher.matches(trace)) { @@ -47,8 +47,8 @@ public class ThrowableToStrings { } } - // if (numberOfcommonFrames != 0) { - // strList.add("\t... " + numberOfcommonFrames + " common frames omitted"); + // if (numberOfCommonFrames != 0) { + // strList.add("\t... " + numberOfCommonFrames + " common frames omitted"); // } Throwable cause = t.getCause(); diff --git a/able/src/main/resources/settings/global/json-service.yml b/able/src/main/resources/settings/global/JsonService.yml similarity index 100% rename from able/src/main/resources/settings/global/json-service.yml rename to able/src/main/resources/settings/global/JsonService.yml -- Gitee From 700e309bcb2cdf923a89b0e53ddc74fbcb2e9915 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 19:29:26 +0800 Subject: [PATCH 42/54] convertObjectToMap --- .../com/gitee/qdbp/tools/utils/JsonTools.java | 55 +++++++++++++++++++ .../com/gitee/qdbp/tools/utils/MapTools.java | 21 +------ 2 files changed, 57 insertions(+), 19 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java index 9ce11ac..71ec29e 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java @@ -6,10 +6,14 @@ import java.math.BigInteger; import java.util.Collection; import java.util.Date; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import com.gitee.qdbp.able.beans.LinkedListMap; +import com.gitee.qdbp.able.exception.ServiceException; +import com.gitee.qdbp.able.result.ResultCode; import com.gitee.qdbp.json.JsonFeature; /** @@ -44,6 +48,12 @@ public class JsonTools extends JsonMaps { if (object instanceof String) { return convertStringValue((String) object, clazz); } + if (clazz == Map.class) { + return convertObjectToMap(object); + } + if (clazz == boolean.class || clazz == Boolean.class) { + return (T) convertObjectToBoolean(object, clazz); + } return findDefaultJsonService().convert(object, clazz); } @@ -95,6 +105,26 @@ public class JsonTools extends JsonMaps { } } + private static Boolean convertObjectToBoolean(Object object, Class clazz) { + if (object instanceof Boolean) { + return ((Boolean) object); + } + if (object instanceof Number) { + return ((Number) object).doubleValue() != 0; + } + if (object instanceof CharSequence || object instanceof Character) { + String string = object.toString(); + Boolean result = StringTools.isPositive(string, null); + if (result != null) { + return result; + } + throw new ServiceException(ResultCode.DATA_CONVERT_ERROR) + .setDetails(StringTools.ellipsis(string, 30) + " can't convert to " + clazz.getSimpleName()); + } + throw new ServiceException(ResultCode.DATA_CONVERT_ERROR) + .setDetails(object.getClass().getSimpleName() + " can't convert to " + clazz.getSimpleName()); + } + @SuppressWarnings("unchecked") private static T convertStringValue(String string, Class clazz) { if (clazz == Date.class) { @@ -115,6 +145,12 @@ public class JsonTools extends JsonMaps { if (clazz == boolean.class || clazz == Boolean.class) { return (T) Boolean.valueOf(ConvertTools.toBoolean(string)); } + if (clazz == byte.class || clazz == Byte.class) { + return (T) Byte.valueOf(string); + } + if (clazz == short.class || clazz == Short.class) { + return (T) Short.valueOf(string); + } if (VerifyTools.isJsonObjectString(string)) { if (clazz == Map.class) { return (T) parseAsMap(string); @@ -122,6 +158,9 @@ public class JsonTools extends JsonMaps { if (clazz == HashMap.class) { return (T) new HashMap<>(parseAsMap(string)); } + if (clazz == LinkedHashMap.class) { + return (T) new LinkedHashMap<>(parseAsMap(string)); + } if (!ReflectTools.isPrimitive(clazz, false) && !clazz.isArray() && !Collection.class.isAssignableFrom(clazz)) { Map map = parseAsMap(string); @@ -131,6 +170,22 @@ public class JsonTools extends JsonMaps { return findDefaultJsonService().convert(string, clazz); } + @SuppressWarnings("unchecked") + private static T convertObjectToMap(Object object) { + if (object instanceof Map) { + return (T) MapTools.toJsonMap((Map) object); + } else if (VerifyTools.isPlainObject(object)) { + return (T) beanToMap(object, true, false); + } else if (VerifyTools.isCollection(object)) { + // 如果结果是数组, 包装成Map返回 + List objects = ConvertTools.parseList(object); + return (T) new LinkedListMap(beanToMaps(objects, true, false)); + } else { + throw new ServiceException(ResultCode.DATA_CONVERT_ERROR) + .setDetails(object.getClass().getSimpleName() + " can't convert to Map"); + } + } + /** 对象转换为字符串 **/ public static String toJsonString(Object object) { return findDefaultJsonService().toJsonString(object); diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java index d422c93..85ee76e 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java @@ -12,7 +12,6 @@ import java.util.List; import java.util.Map; import java.util.Set; import com.gitee.qdbp.able.beans.DepthMap; -import com.gitee.qdbp.able.beans.LinkedListMap; import com.gitee.qdbp.able.exception.ServiceException; import com.gitee.qdbp.able.model.entry.EachEntry; import com.gitee.qdbp.able.model.entry.EntryItem; @@ -456,28 +455,12 @@ public class MapTools { return convertValue(value, null, clazz); } - @SuppressWarnings("unchecked") private static T convertValue(Object value, T defaults, Class clazz) { if (value == null && defaults != null) { return defaults; } else { - if (clazz == Map.class) { - List objects = ConvertTools.parseList(value); - if (objects.size() == 1 && objects.get(0) == value) { - // 如果列表容器只有value一个元素, 说明value不是列表 - return (T) toJsonMap((Map) value); - } else { - // 如果结果是数组, 包装成Map返回 - return (T) new LinkedListMap(JsonTools.beanToMaps(objects, true, false)); - } - } else { - try { - T result = JsonTools.convert(value, clazz); - return result != null ? result : defaults; - } catch (Exception e) { - return defaults; - } - } + T result = JsonTools.convert(value, clazz); + return result != null ? result : defaults; } } -- Gitee From 51eb50d9ec1863b85d0898d3792d720584c54226 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 19:30:43 +0800 Subject: [PATCH 43/54] =?UTF-8?q?=E8=BF=94=E5=9B=9E=E8=A7=A3=E5=8E=8B?= =?UTF-8?q?=E5=90=8E=E7=9A=84=E7=9B=B8=E5=AF=B9=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/tools/files/ZipTools.java | 45 +++++++++++++++---- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/files/ZipTools.java b/able/src/main/java/com/gitee/qdbp/tools/files/ZipTools.java index 6205e3f..152db18 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/files/ZipTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/files/ZipTools.java @@ -4,7 +4,6 @@ import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -13,6 +12,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; @@ -32,12 +32,13 @@ public class ZipTools { /** * ZIP文件解压 - * + * * @param srcPath 源文件 * @param saveFolder 保存文件的路径 + * @return 解压后的文件相对路径 */ - public static void decompression(String srcPath, String saveFolder) throws IOException { - decompression(srcPath, saveFolder, StandardCharsets.UTF_8); + public static List decompression(String srcPath, String saveFolder) throws IOException { + return decompression(new File(srcPath), saveFolder, StandardCharsets.UTF_8); } /** @@ -46,13 +47,37 @@ public class ZipTools { * @param srcPath 源文件 * @param saveFolder 保存文件的路径 * @param charset 编码格式 + * @return 解压后的文件相对路径 + */ + public static List decompression(String srcPath, String saveFolder, Charset charset) throws IOException { + return decompression(new File(srcPath), saveFolder, StandardCharsets.UTF_8); + } + + /** + * ZIP文件解压 + * + * @param srcFile 源文件 + * @param saveFolder 保存文件的路径 + * @return 解压后的文件相对路径 + */ + public static List decompression(File srcFile, String saveFolder) throws IOException { + return decompression(srcFile, saveFolder, StandardCharsets.UTF_8); + } + + /** + * ZIP文件解压 + * + * @param srcFile 源文件 + * @param saveFolder 保存文件的路径 + * @param charset 编码格式 + * @return 解压后的文件相对路径 */ - public static void decompression(String srcPath, String saveFolder, Charset charset) throws IOException { - File srcFile = new File(srcPath); + public static List decompression(File srcFile, String saveFolder, Charset charset) throws IOException { if (!srcFile.exists()) { // 判断源文件是否存在 - throw new ResourceNotFoundException(srcPath); + throw new ResourceNotFoundException(srcFile.getPath()); } - String fileName = PathTools.removeExtension(new File(srcPath).getName()) + '/'; + List relativePaths = new ArrayList<>(); + String fileName = PathTools.removeExtension(srcFile.getName()) + '/'; // 开始解压 try (ZipFile zipFile = new ZipFile(srcFile, charset)) { Enumeration entries = zipFile.entries(); @@ -76,9 +101,11 @@ public class ZipTools { // 将压缩文件内容写入文件中 try (InputStream is = zipFile.getInputStream(entry); FileOutputStream os = new FileOutputStream(file)) { FileTools.copy(is, os); + relativePaths.add(relativePath); } } } + return relativePaths; } /** @@ -311,7 +338,7 @@ public class ZipTools { @Override public InputStream getInputStream() throws IOException { - return new FileInputStream(file); + return Files.newInputStream(file.toPath()); } } -- Gitee From 5ce6164c0fed2adea085ed5b9acb2fb031ed327d Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 19:31:45 +0800 Subject: [PATCH 44/54] =?UTF-8?q?ClassLoader=E6=94=B9=E4=B8=BAClassTools?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- able/src/main/java/com/gitee/qdbp/able/i18n/LocaleTools.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/able/src/main/java/com/gitee/qdbp/able/i18n/LocaleTools.java b/able/src/main/java/com/gitee/qdbp/able/i18n/LocaleTools.java index 3adb669..f5fb22f 100644 --- a/able/src/main/java/com/gitee/qdbp/able/i18n/LocaleTools.java +++ b/able/src/main/java/com/gitee/qdbp/able/i18n/LocaleTools.java @@ -19,6 +19,7 @@ import java.util.ResourceBundle; import java.util.ResourceBundle.Control; import com.gitee.qdbp.able.exception.ResourceNotFoundException; import com.gitee.qdbp.tools.files.PathTools; +import com.gitee.qdbp.tools.utils.ClassTools; import com.gitee.qdbp.tools.utils.Config; import com.gitee.qdbp.tools.utils.StringTools; import com.gitee.qdbp.tools.utils.VerifyTools; @@ -257,7 +258,7 @@ public class LocaleTools { public InputStream run() throws IOException { List urls = PathTools.scanResources(resource); - ClassLoader threadLoader = PathTools.getDefaultClassLoader(); + ClassLoader threadLoader = ClassTools.getDefaultClassLoader(); if (threadLoader == null) { threadLoader = ClassLoader.getSystemClassLoader(); } -- Gitee From 02d755f5b1040f7116657992a0434b896ed27df5 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 19:32:27 +0800 Subject: [PATCH 45/54] =?UTF-8?q?VolatileData=E5=A2=9E=E5=8A=A0copy?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/able/beans/VolatileData.java | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/able/beans/VolatileData.java b/able/src/main/java/com/gitee/qdbp/able/beans/VolatileData.java index e2062b5..d597ed8 100644 --- a/able/src/main/java/com/gitee/qdbp/able/beans/VolatileData.java +++ b/able/src/main/java/com/gitee/qdbp/able/beans/VolatileData.java @@ -1,6 +1,7 @@ package com.gitee.qdbp.able.beans; import java.io.Serializable; +import com.gitee.qdbp.tools.utils.ConvertTools; /** * 带有过期时间的数据 @@ -8,7 +9,7 @@ import java.io.Serializable; * @author zhaohuihua * @version 180223 */ -public class VolatileData implements Serializable { +public class VolatileData implements Copyable, Serializable { /** serialVersionUID **/ private static final long serialVersionUID = 1L; @@ -33,7 +34,7 @@ public class VolatileData implements Serializable { return this.value; } - // 设置过期时间(相对时间) + /** 设置过期时间(相对时间) **/ public VolatileData expire(Long expire) { if (expire != null) { this.expireTime = System.currentTimeMillis() + expire; @@ -41,13 +42,33 @@ public class VolatileData implements Serializable { return this; } - // 移除过期时间 + /** 设置过期时间(绝对时间) **/ + public VolatileData setExpireTime(Long expireTime) { + this.expireTime = expireTime; + return this; + } + + /** 获取过期时间(绝对时间) **/ + public Long getExpireTime() { + return expireTime; + } + + /** 移除过期时间 **/ public VolatileData persist() { this.expireTime = null; return this; } + /** 判断是否已过期 **/ public boolean expired() { return this.expireTime != null && this.expireTime < System.currentTimeMillis(); } + + @Override + public VolatileData copy() { + VolatileData newer = new VolatileData<>(); + newer.value = ConvertTools.tryCopyObject(this.value); + newer.expireTime = this.expireTime; + return newer; + } } -- Gitee From bd7834913d6586d8e24c8bc37e5988e5515e054b Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 19:33:09 +0800 Subject: [PATCH 46/54] =?UTF-8?q?NetworkTools=E5=A2=9E=E5=8A=A0=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/tools/utils/NetworkTools.java | 146 +++++++++++++++++- .../settings/global/NetworkTools.yml | 13 ++ 2 files changed, 153 insertions(+), 6 deletions(-) create mode 100644 able/src/main/resources/settings/global/NetworkTools.yml diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/NetworkTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/NetworkTools.java index 8919445..62431a0 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/NetworkTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/NetworkTools.java @@ -1,5 +1,6 @@ package com.gitee.qdbp.tools.utils; +import java.io.IOException; import java.net.Inet4Address; import java.net.InetAddress; import java.net.NetworkInterface; @@ -7,7 +8,16 @@ import java.net.SocketException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Enumeration; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; +import com.gitee.qdbp.able.beans.KeyString; +import com.gitee.qdbp.able.beans.StringWithAttrs; +import com.gitee.qdbp.able.exception.ServiceException; +import com.gitee.qdbp.able.matches.StringMatcher; +import com.gitee.qdbp.able.matches.WrapStringMatcher; +import com.gitee.qdbp.able.result.ResultCode; +import com.gitee.qdbp.tools.files.PathTools; /** * 网络工具类 @@ -52,8 +62,18 @@ public class NetworkTools { return getLocalIpv4Addresses(); } + private static List CACHED_LOCAL_IPV4_ADDRESSES; + /** 获取本机IPv4地址 **/ public static List getLocalIpv4Addresses() { + // 查找NetworkTools.yml配置 + Map yaml = findYamlMaps(); + // 是否启用缓存 + boolean cacheEnabled = MapTools.getValue(yaml, "cacheEnabled", true, boolean.class); + if (cacheEnabled && CACHED_LOCAL_IPV4_ADDRESSES != null) { + return CACHED_LOCAL_IPV4_ADDRESSES; + } + String hostIp = findHostIp(yaml); // 遍历本机的所有网络接口 Enumeration networks; try { @@ -61,6 +81,10 @@ public class NetworkTools { } catch (SocketException e) { return new ArrayList<>(); } + // 忽略网卡的规则 + StringMatcher ignoreMatcher = findIgnoreRules(yaml); + // 可达检测等待毫秒数 + int reachableWaitMillis = findReachableWaitMillis(yaml); List iplist = new ArrayList<>(); List backup = new ArrayList<>(); while (networks.hasMoreElements()) { @@ -76,9 +100,8 @@ public class NetworkTools { continue; } String name = network.getDisplayName().toLowerCase(); - if (name.contains("virtual") || name.contains("veth") || name.contains("virbr") - || name.contains("docker")) { - continue; // 忽略虚拟机的IP地址 + if (ignoreMatcher != null && ignoreMatcher.matches(name)) { + continue; // 忽略指定的网卡 } // 遍历该网络接口绑定的IP地址 Enumeration addresses = network.getInetAddresses(); @@ -90,9 +113,16 @@ public class NetworkTools { if (address.isLoopbackAddress() || address.getHostAddress().startsWith("127")) { continue; // 忽略127.0.0.1地址, 127.xxx.xxx.xxx属于loopback, 只有本机可见 } - // if (!address.isReachable(50)) { - // continue; - // } + if (reachableWaitMillis > 0) { + // 检查是否可达 + try { + if (!address.isReachable(reachableWaitMillis)) { + continue; + } + } catch (IOException e) { + continue; + } + } if (address.isSiteLocalAddress()) { // 优先返回该地址 // 192.168.xxx.xxx属于private私有地址(SiteLocalAddress), 只能在本地局域网可见 // 公网地址一般都不会出现在网卡配置中, 都是通过映射访问的 @@ -104,6 +134,15 @@ public class NetworkTools { } } iplist.addAll(backup); + // 将配置的hostIp放在最前面 + if (hostIp != null) { + iplist.remove(hostIp); + iplist.add(0, hostIp); + } + if (cacheEnabled) { + // 缓存本机IP地址 + CACHED_LOCAL_IPV4_ADDRESSES = iplist; + } return iplist; } @@ -120,4 +159,99 @@ public class NetworkTools { } } } + + private static Map findYamlMaps() { + String configPath = "settings/global/NetworkTools.yml"; + KeyString resource = PathTools.scanTextResource(configPath); + String path = resource.getKey(); + Map roots = RuleTools.splitRuleKeyValues(resource.getValue()).asMap(); + String rootValue = roots.get("network-tools"); + if (VerifyTools.isBlank(rootValue)) { + throw new ServiceException(ResultCode.SYSTEM_CONFIG_NOT_FOUND) + .setDetails("network-tools config missing --> " + path); + } + List contents = RuleTools.splitRuleWithAttrs(rootValue); + if (contents.isEmpty()) { + throw new ServiceException(ResultCode.SYSTEM_CONFIG_ERROR) + .setDetails("network-tools config error --> " + path); + } + Map maps = new LinkedHashMap<>(); + for (StringWithAttrs content : contents) { + String name = StringTools.trimRight(content.getString(), ':', ' '); + if (VerifyTools.isBlank(content.getAttrs())) { + maps.put(name, null); + } else { + maps.putAll(content.getAttrs().asMap()); + } + } + return maps; + } + + private static String findHostIp(Map yaml) { + // 从NetworkTools.yml中获取hostIpKey(默认为host.ip) + String hostKey = MapTools.getString(yaml, "hostIpKey"); + if (VerifyTools.isBlank(hostKey)) { + return null; + } + // 从JVM环境变量中获取host.ip + String hostIp = getSystemProperty(hostKey); + if (VerifyTools.isBlank(hostIp)) { + return null; + } + try { + // host.ip可以配置IP或主机名, 转换为ip地址 + return InetAddress.getByName(hostIp).getHostAddress(); + } catch (UnknownHostException e) { + throw new ServiceException(ResultCode.SYSTEM_CONFIG_ERROR, e) + .setDetails(hostKey + "=" + hostIp); + } + } + + private static StringMatcher findIgnoreRules(Map yaml) { + // 从NetworkTools.yml中获取ignoreKey(默认为network.ignore) + String ignoreKey = MapTools.getString(yaml, "ignoreKey"); + if (VerifyTools.isBlank(ignoreKey)) { + return null; + } + // 从JVM环境变量中获取network.ignore + String configValue = getSystemProperty(ignoreKey); + if (VerifyTools.isBlank(configValue)) { + // 从NetworkTools.yml中获取ignoreNames + configValue = MapTools.getString(yaml, "ignoreNames"); + } + if (VerifyTools.isBlank(configValue)) { + return null; + } + List ignoreRules = StringTools.splits(configValue, ','); + return WrapStringMatcher.parseMatchers(ignoreRules, StringMatcher.LogicType.OR, "contains"); + } + + private static int findReachableWaitMillis(Map yaml) { + // 从NetworkTools.yml中获取reachableWaitKey(默认为network.reachable) + String reachableWaitKey = MapTools.getString(yaml, "reachableWaitKey"); + if (VerifyTools.isBlank(reachableWaitKey)) { + return 0; + } + // 从JVM环境变量中获取network.reachable + String propValue = getSystemProperty(reachableWaitKey); + if (VerifyTools.isBlank(propValue)) { + try { + return ConvertTools.toInteger(propValue); + } catch (NumberFormatException e) { + throw new ServiceException(ResultCode.SYSTEM_CONFIG_ERROR, e) + .setDetails(reachableWaitKey + '=' + propValue); + } + } else { + // 从NetworkTools.yml中获取reachableWaitMillis + String configKey = "reachableWaitMillis"; + return MapTools.getValue(yaml, configKey, int.class); + } + } + + private static String getSystemProperty(String name) { + // JVM环境变量, 可通过-D设置变量值 + String value = System.getProperty(name); + // 系统环境变量 + return value != null ? value : System.getenv(name); + } } diff --git a/able/src/main/resources/settings/global/NetworkTools.yml b/able/src/main/resources/settings/global/NetworkTools.yml new file mode 100644 index 0000000..a13e050 --- /dev/null +++ b/able/src/main/resources/settings/global/NetworkTools.yml @@ -0,0 +1,13 @@ +network-tools: + # 是否缓存IP地址 + cacheEnabled: true + # 忽略的网卡名 + ignoreNames: virtual,veth,virbr,docker + # 可达检测的等待时长(毫秒), 0表示不检测 + reachableWaitMillis: 0 + # -Dhost.ip=192.168.8.88 + hostIpKey: host.ip + # -Dnetwork.ignore=virtual,veth,virbr,docker + ignoreKey: network.ignore + # -Dnetwork.reachable=50 + reachableWaitKey: network.reachable -- Gitee From 40ff05c31a00c6a5c1f7b047d2dbc61afc237b3a Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 19:52:10 +0800 Subject: [PATCH 47/54] =?UTF-8?q?SqlScript=E5=B7=A5=E5=85=B7=E5=8D=87?= =?UTF-8?q?=E7=BA=A7=E5=B9=B6=E7=A7=BB=E8=87=B3qdbp-able?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../qdbp/able/jdbc/utils/SqlScriptTools.java | 775 ++++++++++++++++++ 1 file changed, 775 insertions(+) create mode 100644 able/src/main/java/com/gitee/qdbp/able/jdbc/utils/SqlScriptTools.java diff --git a/able/src/main/java/com/gitee/qdbp/able/jdbc/utils/SqlScriptTools.java b/able/src/main/java/com/gitee/qdbp/able/jdbc/utils/SqlScriptTools.java new file mode 100644 index 0000000..0fcbfa7 --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/jdbc/utils/SqlScriptTools.java @@ -0,0 +1,775 @@ +/* + * Copyright 2002-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.gitee.qdbp.able.jdbc.utils; + +import java.io.File; +import java.io.IOException; +import java.io.LineNumberReader; +import java.io.Reader; +import java.io.StringReader; +import java.net.URL; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.SQLWarning; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.gitee.qdbp.able.enums.FileErrorCode; +import com.gitee.qdbp.able.exception.ServiceException; +import com.gitee.qdbp.able.i18n.LocaleTools; +import com.gitee.qdbp.able.result.IResultMessage; +import com.gitee.qdbp.able.result.ResultCode; +import com.gitee.qdbp.tools.files.FileTools; +import com.gitee.qdbp.tools.files.PathTools; +import com.gitee.qdbp.tools.utils.ClassTools; +import com.gitee.qdbp.tools.utils.StringTools; +import com.gitee.qdbp.tools.utils.VerifyTools; + + +/** + * copy from spring-jdbc-5.3.23.jar ScriptUtils
+ * Generic utility methods for working with SQL scripts in conjunction with JDBC. + * + *

Mainly for internal use within the framework.

+ * + * @author Thomas Risberg + * @author Sam Brannen + * @author Juergen Hoeller + * @author Keith Donald + * @author Dave Syer + * @author Chris Beams + * @author Oliver Gierke + * @author Chris Baldwin + * @author Nicolas Debeissat + * @author Phillip Webb + */ +public abstract class SqlScriptTools { + + private static Logger log; + + static { + if (ClassTools.isPresent("org.slf4j.Logger")) { + log = LoggerFactory.getLogger(SqlScriptTools.class); + } + } + + /** + * Default statement separator within SQL scripts: {@code ";"}. + */ + public static final String DEFAULT_STATEMENT_SEPARATOR = ";"; + + /** + * Fallback statement separator within SQL scripts: {@code "\n"}. + *

Used if neither a custom separator nor the + * {@link #DEFAULT_STATEMENT_SEPARATOR} is present in a given script. + */ + public static final String FALLBACK_STATEMENT_SEPARATOR = "\n"; + + /** + * End of file (EOF) SQL statement separator: {@code "^^^ END OF SCRIPT ^^^"}. + *

This value may be supplied as the {@code separator} to {@link + * #executeSqlScript(Connection, String, String, boolean, boolean, String, String, String, String)} + * to denote that an SQL script contains a single statement (potentially + * spanning multiple lines) with no explicit statement separator. Note that + * such a script should not actually contain this value; it is merely a + * virtual statement separator. + */ + public static final String EOF_STATEMENT_SEPARATOR = "^^^ END OF SCRIPT ^^^"; + + /** + * Default prefix for single-line comments within SQL scripts: {@code "--"}. + */ + public static final String DEFAULT_COMMENT_PREFIX = "--"; + + /** + * Default prefixes for single-line comments within SQL scripts: {@code ["--"]}. + * @since 5.2 + */ + public static final String[] DEFAULT_COMMENT_PREFIXES = {DEFAULT_COMMENT_PREFIX}; + + /** + * Default start delimiter for block comments within SQL scripts: {@code "/*"}. + */ + public static final String DEFAULT_BLOCK_COMMENT_START_DELIMITER = "/*"; + + /** + * Default end delimiter for block comments within SQL scripts: "*/". + */ + public static final String DEFAULT_BLOCK_COMMENT_END_DELIMITER = "*/"; + + /** + * Execute the given SQL script using default settings for statement + * separators, comment delimiters, and exception handling flags. + *

Statement separators and comments will be removed before executing + * individual statements within the supplied script. + *

Warning: this method does not release the + * provided {@link Connection}. + * @param connection the JDBC connection to use to execute the script; already + * configured and ready to use + * @param resource resource content script + * @return all script fragments executed successfully will return true + * @throws ServiceException if an error occurred while executing the SQL script + * @see #executeSqlScript(Connection, String, String, boolean, boolean, String, String, String, String) + * @see #DEFAULT_STATEMENT_SEPARATOR + * @see #DEFAULT_COMMENT_PREFIX + * @see #DEFAULT_BLOCK_COMMENT_START_DELIMITER + * @see #DEFAULT_BLOCK_COMMENT_END_DELIMITER + */ + public static boolean executeSqlScript(Connection connection, URL resource) { + return executeSqlScript(connection, resource, false, false); + } + + /** + * Execute the given SQL script using default settings for statement + * separators, comment delimiters, and exception handling flags. + *

Statement separators and comments will be removed before executing + * individual statements within the supplied script. + *

Warning: this method does not release the + * provided {@link Connection}. + * @param connection the JDBC connection to use to execute the script; already + * configured and ready to use + * @param resource resource content script + * @param continueOnError whether to continue without throwing an exception + * in the event of an error + * @param ignoreFailedDrops whether to continue in the event of specifically + * an error on a {@code DROP} statement + * @return all script fragments executed successfully will return true + * @throws ServiceException if an error occurred while executing the SQL script + * @see #executeSqlScript(Connection, String, String, boolean, boolean, String, String, String, String) + * @see #DEFAULT_STATEMENT_SEPARATOR + * @see #DEFAULT_COMMENT_PREFIX + * @see #DEFAULT_BLOCK_COMMENT_START_DELIMITER + * @see #DEFAULT_BLOCK_COMMENT_END_DELIMITER + */ + public static boolean executeSqlScript(Connection connection, URL resource, + boolean continueOnError, boolean ignoreFailedDrops) { + String resourceName = PathTools.getFileName(resource.getPath()); + String resourceScript; + try { + resourceScript = PathTools.downloadString(resource); + } catch (IOException e) { + throw new ServiceException(FileErrorCode.FILE_READ_ERROR).setDetails(resource.toString()); + } + return executeSqlScript(connection, resourceName, resourceScript, continueOnError, ignoreFailedDrops, + DEFAULT_COMMENT_PREFIX, DEFAULT_STATEMENT_SEPARATOR, + DEFAULT_BLOCK_COMMENT_START_DELIMITER, DEFAULT_BLOCK_COMMENT_END_DELIMITER); + } + + /** + * Execute the given SQL script using default settings for statement + * separators, comment delimiters, and exception handling flags. + *

Statement separators and comments will be removed before executing + * individual statements within the supplied script. + *

Warning: this method does not release the + * provided {@link Connection}. + * @param connection the JDBC connection to use to execute the script; already + * configured and ready to use + * @param resource resource content script + * @return all script fragments executed successfully will return true + * @throws ServiceException if an error occurred while executing the SQL script + * @see #executeSqlScript(Connection, String, String, boolean, boolean, String, String, String, String) + * @see #DEFAULT_STATEMENT_SEPARATOR + * @see #DEFAULT_COMMENT_PREFIX + * @see #DEFAULT_BLOCK_COMMENT_START_DELIMITER + * @see #DEFAULT_BLOCK_COMMENT_END_DELIMITER + */ + public static boolean executeSqlScript(Connection connection, File resource) { + return executeSqlScript(connection, resource, false, false); + } + + /** + * Execute the given SQL script using default settings for statement + * separators, comment delimiters, and exception handling flags. + *

Statement separators and comments will be removed before executing + * individual statements within the supplied script. + *

Warning: this method does not release the + * provided {@link Connection}. + * @param connection the JDBC connection to use to execute the script; already + * configured and ready to use + * @param resource resource content script + * @param continueOnError whether to continue without throwing an exception + * in the event of an error + * @param ignoreFailedDrops whether to continue in the event of specifically + * an error on a {@code DROP} statement + * @return all script fragments executed successfully will return true + * @throws ServiceException if an error occurred while executing the SQL script + * @see #executeSqlScript(Connection, String, String, boolean, boolean, String, String, String, String) + * @see #DEFAULT_STATEMENT_SEPARATOR + * @see #DEFAULT_COMMENT_PREFIX + * @see #DEFAULT_BLOCK_COMMENT_START_DELIMITER + * @see #DEFAULT_BLOCK_COMMENT_END_DELIMITER + */ + public static boolean executeSqlScript(Connection connection, File resource, + boolean continueOnError, boolean ignoreFailedDrops) { + String resourceName = resource.getName(); + String resourceScript; + try { + resourceScript = FileTools.readTextContent(resource); + } catch (IOException e) { + throw new ServiceException(FileErrorCode.FILE_READ_ERROR).setDetails(resource.toString()); + } + return executeSqlScript(connection, resourceName, resourceScript, continueOnError, ignoreFailedDrops, + DEFAULT_COMMENT_PREFIX, DEFAULT_STATEMENT_SEPARATOR, + DEFAULT_BLOCK_COMMENT_START_DELIMITER, DEFAULT_BLOCK_COMMENT_END_DELIMITER); + } + + /** + * Execute the given SQL script using default settings for statement + * separators, comment delimiters, and exception handling flags. + *

Statement separators and comments will be removed before executing + * individual statements within the supplied script. + *

Warning: this method does not release the + * provided {@link Connection}. + * @param connection the JDBC connection to use to execute the script; already + * configured and ready to use + * @param resourceName resource name + * @param resourceScript resource content script + * @return all script fragments executed successfully will return true + * @throws ServiceException if an error occurred while executing the SQL script + * @see #executeSqlScript(Connection, String, String, boolean, boolean, String, String, String, String) + * @see #DEFAULT_STATEMENT_SEPARATOR + * @see #DEFAULT_COMMENT_PREFIX + * @see #DEFAULT_BLOCK_COMMENT_START_DELIMITER + * @see #DEFAULT_BLOCK_COMMENT_END_DELIMITER + */ + public static boolean executeSqlScript(Connection connection, String resourceName, String resourceScript) { + return executeSqlScript(connection, resourceName, resourceScript, false, false, + DEFAULT_COMMENT_PREFIX, DEFAULT_STATEMENT_SEPARATOR, + DEFAULT_BLOCK_COMMENT_START_DELIMITER, DEFAULT_BLOCK_COMMENT_END_DELIMITER); + } + + /** + * Execute the given SQL script using default settings for statement + * separators, comment delimiters, and exception handling flags. + *

Statement separators and comments will be removed before executing + * individual statements within the supplied script. + *

Warning: this method does not release the + * provided {@link Connection}. + * @param connection the JDBC connection to use to execute the script; already + * configured and ready to use + * @param resourceName resource name + * @param resourceScript resource content script + * @param continueOnError whether to continue without throwing an exception + * in the event of an error + * @param ignoreFailedDrops whether to continue in the event of specifically + * an error on a {@code DROP} statement + * @return all script fragments executed successfully will return true + * @throws ServiceException if an error occurred while executing the SQL script + * @see #executeSqlScript(Connection, String, String, boolean, boolean, String, String, String, String) + * @see #DEFAULT_STATEMENT_SEPARATOR + * @see #DEFAULT_COMMENT_PREFIX + * @see #DEFAULT_BLOCK_COMMENT_START_DELIMITER + * @see #DEFAULT_BLOCK_COMMENT_END_DELIMITER + */ + public static boolean executeSqlScript(Connection connection, String resourceName, String resourceScript, + boolean continueOnError, boolean ignoreFailedDrops) { + return executeSqlScript(connection, resourceName, resourceScript, continueOnError, ignoreFailedDrops, + DEFAULT_COMMENT_PREFIX, DEFAULT_STATEMENT_SEPARATOR, + DEFAULT_BLOCK_COMMENT_START_DELIMITER, DEFAULT_BLOCK_COMMENT_END_DELIMITER); + } + + /** + * Execute the given SQL script. + *

Statement separators and comments will be removed before executing + * individual statements within the supplied script. + *

Warning: this method does not release the + * provided {@link Connection}. + * @param connection the JDBC connection to use to execute the script; already + * configured and ready to use + * @param resourceName resource name + * @param resourceScript resource content script + * @param continueOnError whether to continue without throwing an exception + * in the event of an error + * @param ignoreFailedDrops whether to continue in the event of specifically + * an error on a {@code DROP} statement + * @param commentPrefix the prefix that identifies single-line comments in the + * SQL script (typically "--") + * @param separator the script statement separator; defaults to + * {@value #DEFAULT_STATEMENT_SEPARATOR} if not specified and falls back to + * {@value #FALLBACK_STATEMENT_SEPARATOR} as a last resort; may be set to + * {@value #EOF_STATEMENT_SEPARATOR} to signal that the script contains a + * single statement without a separator + * @param blockCommentStartDelimiter the start block comment delimiter + * @param blockCommentEndDelimiter the end block comment delimiter + * @return all script fragments executed successfully will return true + * @throws ServiceException if an error occurred while executing the SQL script + * @see #DEFAULT_STATEMENT_SEPARATOR + * @see #FALLBACK_STATEMENT_SEPARATOR + * @see #EOF_STATEMENT_SEPARATOR + */ + public static boolean executeSqlScript(Connection connection, String resourceName, String resourceScript, + boolean continueOnError, boolean ignoreFailedDrops, String commentPrefix, String separator, + String blockCommentStartDelimiter, String blockCommentEndDelimiter) { + return executeSqlScript(connection, resourceName, resourceScript, continueOnError, ignoreFailedDrops, + new String[] { commentPrefix }, separator, blockCommentStartDelimiter, blockCommentEndDelimiter); + } + + /** + * Execute the given SQL script. + *

Statement separators and comments will be removed before executing + * individual statements within the supplied script. + *

Warning: this method does not release the + * provided {@link Connection}. + * @param connection the JDBC connection to use to execute the script; already + * configured and ready to use + * @param resourceName resource name + * @param resourceScript resource content script + * @param continueOnError whether to continue without throwing an exception + * in the event of an error + * @param ignoreFailedDrops whether to continue in the event of specifically + * an error on a {@code DROP} statement + * @param commentPrefixes the prefixes that identify single-line comments in the + * SQL script (typically "--") + * @param separator the script statement separator; defaults to + * {@value #DEFAULT_STATEMENT_SEPARATOR} if not specified and falls back to + * {@value #FALLBACK_STATEMENT_SEPARATOR} as a last resort; may be set to + * {@value #EOF_STATEMENT_SEPARATOR} to signal that the script contains a + * single statement without a separator + * @param blockCommentStartDelimiter the start block comment delimiter + * @param blockCommentEndDelimiter the end block comment delimiter + * @return all script fragments executed successfully will return true + * @throws ServiceException if an error occurred while executing the SQL script + * @since 5.2 + * @see #DEFAULT_STATEMENT_SEPARATOR + * @see #FALLBACK_STATEMENT_SEPARATOR + * @see #EOF_STATEMENT_SEPARATOR + */ + public static boolean executeSqlScript(Connection connection, String resourceName, String resourceScript, + boolean continueOnError, boolean ignoreFailedDrops, String[] commentPrefixes, String separator, + String blockCommentStartDelimiter, String blockCommentEndDelimiter) { + try { + if (log != null && log.isDebugEnabled()) { + log.debug("Executing SQL script from " + resourceName); + } + long startTime = System.currentTimeMillis(); + + // clear comment + String script; + try { + script = readScript(resourceScript, separator, commentPrefixes, blockCommentEndDelimiter); + } catch (IOException e) { + throw new ServiceException(ScriptErrorCode.SCRIPT_READ_ERROR) + .setDetails("Cannot read SQL script from " + resourceName); + } + + if (separator == null) { + separator = DEFAULT_STATEMENT_SEPARATOR; + } + if (!EOF_STATEMENT_SEPARATOR.equals(separator) && + !containsStatementSeparator(resourceName, script, separator, commentPrefixes, + blockCommentStartDelimiter, blockCommentEndDelimiter)) { + separator = FALLBACK_STATEMENT_SEPARATOR; + } + + List statements = new ArrayList<>(); + splitSqlScript(resourceName, script, separator, commentPrefixes, blockCommentStartDelimiter, + blockCommentEndDelimiter, statements); + + int stmtNumber = 0; + boolean allSuccessfully = true; + Statement stmt = connection.createStatement(); + try { + for (String statement : statements) { + stmtNumber++; + try { + stmt.execute(statement); + int rowsAffected = stmt.getUpdateCount(); + if (log != null && log.isDebugEnabled()) { + String ellipsis = ellipsisScript(statement, 100); + log.debug(rowsAffected + " returned as update count for SQL[{}]: {}", stmtNumber, ellipsis); + SQLWarning warning = stmt.getWarnings(); + while (warning != null) { + log.debug("SQLWarning ignored: SQL state '{}', error code '{}', message [{}]", + warning.getSQLState(), warning.getErrorCode(), warning.getMessage()); + warning = warning.getNextWarning(); + } + } + } catch (SQLException e) { + boolean dropStatement = startsWithIgnoreCase(statement.trim(), "drop"); + if (!dropStatement || !ignoreFailedDrops) { + allSuccessfully = false; + } + if (continueOnError || (dropStatement && ignoreFailedDrops)) { + if (log != null && log.isDebugEnabled()) { + String ellipsis = ellipsisScript(statement, 100); + String message = buildExecuteMessage(ellipsis, stmtNumber, resourceName); + log.debug(message, e); + } + } else { + String ellipsis = ellipsisScript(statement, 100); + throw buildExecuteException(ellipsis, stmtNumber, resourceName, e); + } + } + } + } finally { + try { + stmt.close(); + } catch (Throwable e) { + if (log != null && log.isTraceEnabled()) { + log.trace("Could not close JDBC Statement", e); + } + } + } + + long elapsedTime = System.currentTimeMillis() - startTime; + if (log != null && log.isDebugEnabled()) { + log.debug("Executed {} SQL script statement from {} in {} ms.", stmtNumber, resourceName, elapsedTime); + } + return allSuccessfully; + } catch (Exception e) { + if (e instanceof ServiceException) { + throw (ServiceException) e; + } + throw new ServiceException(ResultCode.SERVER_INNER_ERROR, e) + .setDetails("Failed to execute database script from resource [{}]", resourceName); + } + } + + /** + * Read a script from the provided resource, using the supplied comment prefixes + * and statement separator, and build a {@code String} containing the lines. + *

Lines beginning with one of the comment prefixes are excluded + * from the results; however, line comments anywhere else — for example, + * within a statement — will be included in the results. + * @param resource the script string + * to be processed + * @param separator the statement separator in the SQL script (typically ";") + * @param commentPrefixes the prefixes that identify comments in the SQL script + * (typically "--") + * @param blockCommentEndDelimiter the end block comment delimiter + * @return a {@code String} containing the script lines + * @throws IOException in case of I/O errors + */ + static String readScript(String resource, String separator, + String[] commentPrefixes, String blockCommentEndDelimiter) throws IOException { + + Reader reader = new StringReader(resource); + try (LineNumberReader lnr = new LineNumberReader(reader)) { + return readScript(lnr, commentPrefixes, separator, blockCommentEndDelimiter); + } + } + + /** + * Read a script from the provided {@code LineNumberReader}, using the supplied + * comment prefixes and statement separator, and build a {@code String} containing + * the lines. + *

Lines beginning with one of the comment prefixes are excluded + * from the results; however, line comments anywhere else — for example, + * within a statement — will be included in the results. + * @param lineNumberReader the {@code LineNumberReader} containing the script + * to be processed + * @param commentPrefixes the prefixes that identify comments in the SQL script + * (typically "--") + * @param separator the statement separator in the SQL script (typically ";") + * @param blockCommentEndDelimiter the end block comment delimiter + * @return a {@code String} containing the script lines + * @throws IOException in case of I/O errors + * @since 5.2 + */ + private static String readScript(LineNumberReader lineNumberReader, String[] commentPrefixes, + String separator, String blockCommentEndDelimiter) throws IOException { + + String currentStatement = lineNumberReader.readLine(); + StringBuilder scriptBuilder = new StringBuilder(); + while (currentStatement != null) { + if ((blockCommentEndDelimiter != null && currentStatement.contains(blockCommentEndDelimiter)) || + (commentPrefixes != null && !startsWithAny(currentStatement, commentPrefixes, 0))) { + if (scriptBuilder.length() > 0) { + scriptBuilder.append('\n'); + } + scriptBuilder.append(currentStatement); + } + currentStatement = lineNumberReader.readLine(); + } + appendSeparatorToScriptIfNecessary(scriptBuilder, separator); + return scriptBuilder.toString(); + } + + private static void appendSeparatorToScriptIfNecessary(StringBuilder scriptBuilder, String separator) { + if (separator == null) { + return; + } + String trimmed = separator.trim(); + if (trimmed.length() == separator.length()) { + return; + } + // separator ends in whitespace, so we might want to see if the script is trying + // to end the same way + if (scriptBuilder.lastIndexOf(trimmed) == scriptBuilder.length() - trimmed.length()) { + scriptBuilder.append(separator.substring(trimmed.length())); + } + } + + /** + * Determine if the provided SQL script contains the specified statement separator. + *

This method is intended to be used to find the string separating each + * SQL statement — for example, a ';' character. + *

Any occurrence of the separator within the script will be ignored if it + * is within a literal block of text enclosed in single quotes + * ({@code '}) or double quotes ({@code "}), if it is escaped with a backslash + * ({@code \}), or if it is within a single-line comment or block comment. + * @param resource the resource from which the script was read, or {@code null} + * if unknown + * @param script the SQL script to search within + * @param separator the statement separator to search for + * @param commentPrefixes the prefixes that identify single-line comments + * (typically {@code "--"}) + * @param blockCommentStartDelimiter the start block comment delimiter + * (typically {@code "/*"}) + * @param blockCommentEndDelimiter the end block comment delimiter + * (typically "*/") + * @since 5.2.16 + */ + private static boolean containsStatementSeparator(String resource, String script, + String separator, String[] commentPrefixes, String blockCommentStartDelimiter, + String blockCommentEndDelimiter) { + + boolean inSingleQuote = false; + boolean inDoubleQuote = false; + boolean inEscape = false; + + for (int i = 0; i < script.length(); i++) { + char c = script.charAt(i); + if (inEscape) { + inEscape = false; + continue; + } + // MySQL style escapes + if (c == '\\') { + inEscape = true; + continue; + } + if (!inDoubleQuote && (c == '\'')) { + inSingleQuote = !inSingleQuote; + } + else if (!inSingleQuote && (c == '"')) { + inDoubleQuote = !inDoubleQuote; + } + if (!inSingleQuote && !inDoubleQuote) { + if (script.startsWith(separator, i)) { + return true; + } + else if (startsWithAny(script, commentPrefixes, i)) { + // Skip over any content from the start of the comment to the EOL + int indexOfNextNewline = script.indexOf('\n', i); + if (indexOfNextNewline > i) { + i = indexOfNextNewline; + continue; + } + else { + // If there's no EOL, we must be at the end of the script, so stop here. + break; + } + } + else if (script.startsWith(blockCommentStartDelimiter, i)) { + // Skip over any block comments + int indexOfCommentEnd = script.indexOf(blockCommentEndDelimiter, i); + if (indexOfCommentEnd > i) { + i = indexOfCommentEnd + blockCommentEndDelimiter.length() - 1; + continue; + } + else { + String cause = "Missing block comment end delimiter: " + blockCommentEndDelimiter; + throw buildParseException(cause, resource); + } + } + } + } + + return false; + } + + private static ServiceException buildParseException(String message, String resource) { + String details = String.format("Failed to parse SQL script from resource [%s]: %s", + (resource == null ? "" : resource), message); + return new ServiceException(ScriptErrorCode.SCRIPT_PARSE_ERROR).setDetails(details); + } + + private static String buildExecuteMessage(String stmt, int stmtNumber, String resource) { + return String.format("Failed to execute SQL script statement #%s of [%s]: %s", + stmtNumber, (resource == null ? "" : resource), stmt); + } + + private static ServiceException buildExecuteException(String stmt, int stmtNumber, String resource, Throwable e) { + String details = buildExecuteMessage(stmt, stmtNumber, resource); + return new ServiceException(ScriptErrorCode.SCRIPT_EXECUTE_ERROR, e).setDetails(details); + } + + private static String ellipsisScript(String script, int limit) { + String inline = StringTools.replace(script, "\r\n", " ", "\r", " ", "\n", " "); + return StringTools.ellipsis(inline, limit); + } + + /** + * Split an SQL script into separate statements delimited by the provided + * separator string. Each individual statement will be added to the provided + * {@code List}. + *

Within the script, the provided {@code commentPrefixes} will be honored: + * any text beginning with one of the comment prefixes and extending to the + * end of the line will be omitted from the output. Similarly, the provided + * {@code blockCommentStartDelimiter} and {@code blockCommentEndDelimiter} + * delimiters will be honored: any text enclosed in a block comment will be + * omitted from the output. In addition, multiple adjacent whitespace characters + * will be collapsed into a single space. + * @param resource the resource from which the script was read + * @param script the SQL script + * @param separator text separating each statement + * (typically a ';' or newline character) + * @param commentPrefixes the prefixes that identify SQL line comments + * (typically "--") + * @param blockCommentStartDelimiter the start block comment delimiter; + * never {@code null} or empty + * @param blockCommentEndDelimiter the end block comment delimiter; + * never {@code null} or empty + * @param statements the list that will contain the individual statements + * @throws ServiceException if an error occurred while splitting the SQL script + * @since 5.2 + */ + private static void splitSqlScript(String resource, String script, + String separator, String[] commentPrefixes, String blockCommentStartDelimiter, + String blockCommentEndDelimiter, List statements) { + + VerifyTools.requireNotBlank(script, "script"); + VerifyTools.requireNotBlank(separator, "separator"); + VerifyTools.requireNotBlank(commentPrefixes, "commentPrefixes"); + for (String commentPrefix : commentPrefixes) { + VerifyTools.requireNotBlank(commentPrefix, "commentPrefixes"); + } + VerifyTools.requireNotBlank(blockCommentStartDelimiter, "blockCommentStartDelimiter"); + VerifyTools.requireNotBlank(blockCommentEndDelimiter, "blockCommentEndDelimiter"); + + StringBuilder sb = new StringBuilder(); + boolean inSingleQuote = false; + boolean inDoubleQuote = false; + boolean inEscape = false; + + for (int i = 0; i < script.length(); i++) { + char c = script.charAt(i); + if (inEscape) { + inEscape = false; + sb.append(c); + continue; + } + // MySQL style escapes + if (c == '\\') { + inEscape = true; + sb.append(c); + continue; + } + if (!inDoubleQuote && (c == '\'')) { + inSingleQuote = !inSingleQuote; + } else if (!inSingleQuote && (c == '"')) { + inDoubleQuote = !inDoubleQuote; + } + if (!inSingleQuote && !inDoubleQuote) { + if (script.startsWith(separator, i)) { + // We've reached the end of the current statement + if (sb.length() > 0) { + statements.add(sb.toString()); + sb = new StringBuilder(); + } + i += separator.length() - 1; + continue; + } else if (startsWithAny(script, commentPrefixes, i)) { + // Skip over any content from the start of the comment to the EOL + int indexOfNextNewline = script.indexOf('\n', i); + if (indexOfNextNewline > i) { + i = indexOfNextNewline; + continue; + } else { + // If there's no EOL, we must be at the end of the script, so stop here. + break; + } + } else if (script.startsWith(blockCommentStartDelimiter, i)) { + // Skip over any block comments + int indexOfCommentEnd = script.indexOf(blockCommentEndDelimiter, i); + if (indexOfCommentEnd > i) { + i = indexOfCommentEnd + blockCommentEndDelimiter.length() - 1; + continue; + } else { + String cause = "Missing block comment end delimiter: " + blockCommentEndDelimiter; + throw buildParseException(cause, resource); + } + } else if (c == ' ' || c == '\r' || c == '\n' || c == '\t') { + // Avoid multiple adjacent whitespace characters + if (sb.length() > 0 && sb.charAt(sb.length() - 1) != ' ') { + c = ' '; + } else { + continue; + } + } + } + sb.append(c); + } + + if (sb.length() > 0) { + statements.add(sb.toString()); + } + } + + private static boolean startsWithAny(String script, String[] prefixes, int offset) { + for (String prefix : prefixes) { + if (script.startsWith(prefix, offset)) { + return true; + } + } + return false; + } + + /** + * Test if the given {@code String} starts with the specified prefix, + * ignoring upper/lower case. + * @param str the {@code String} to check + * @param prefix the prefix to look for + * @see String#startsWith + */ + private static boolean startsWithIgnoreCase(String str, String prefix) { + return (str != null && prefix != null && str.length() >= prefix.length() && + str.regionMatches(true, 0, prefix, 0, prefix.length())); + } + + + /** + * 脚本错误枚举 + * + * @author zhaohuihua + * @version 20211127 + */ + private enum ScriptErrorCode implements IResultMessage { + + /** 脚本读取异常 **/ + SCRIPT_READ_ERROR, + /** 脚本解析异常 **/ + SCRIPT_PARSE_ERROR, + /** 脚本执行失败 **/ + SCRIPT_EXECUTE_ERROR; + + /** {@inheritDoc} **/ + @Override + public String getCode() { + return this.name(); + } + + /** {@inheritDoc} **/ + @Override + public String getMessage() { + return LocaleTools.getMessage(this); + } + } +} -- Gitee From 91cc1dd31780287df31aea7429700866104b03fd Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 20:06:27 +0800 Subject: [PATCH 48/54] 5.6.231114 --- README.md | 4 ++-- able/pom.xml | 11 ++++++++++- json/pom.xml | 4 ++-- test/pom.xml | 3 ++- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- test/qdbp-tools-test-jdk8/pom.xml | 2 +- tools/pom.xml | 2 +- 11 files changed, 23 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index adc0bae..b289bfa 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.6.230820 + 5.6.231114 ``` ```xml com.gitee.qdbp qdbp-tools - 5.6.230820 + 5.6.231114 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index 2e07f68..18fad33 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.6.230820 + 5.6.231114 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ @@ -20,4 +20,13 @@ https://gitee.com/qdbp/qdbp-able/ + + + org.slf4j + slf4j-api + 1.7.36 + true + + + diff --git a/json/pom.xml b/json/pom.xml index 987828f..39138b2 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.6.230820 + 5.6.231114 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.6.230820 + 5.6.231114 diff --git a/test/pom.xml b/test/pom.xml index 2e54e0c..83be4e1 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.6.230820 + 5.6.231114 https://gitee.com/qdbp/qdbp-able/ qdbp json test @@ -22,6 +22,7 @@ qdbp-json-test-base qdbp-json-test-fastjson + qdbp-json-test-fastjson2 qdbp-json-test-gson qdbp-json-test-jackson qdbp-tools-test-jdk7 diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index d250b47..ec707ee 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230820 + 5.6.231114 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index 11184c2..7a2f37b 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230820 + 5.6.231114 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index f734508..52d9b1f 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230820 + 5.6.231114 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index 71122cf..aa6d861 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230820 + 5.6.231114 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index 2c0c6b2..3df57da 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230820 + 5.6.231114 qdbp-tools-test-jdk7 diff --git a/test/qdbp-tools-test-jdk8/pom.xml b/test/qdbp-tools-test-jdk8/pom.xml index d906897..12bf95b 100644 --- a/test/qdbp-tools-test-jdk8/pom.xml +++ b/test/qdbp-tools-test-jdk8/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230820 + 5.6.231114 qdbp-tools-test-jdk8 diff --git a/tools/pom.xml b/tools/pom.xml index 4d6b05c..404ed99 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.6.230820 + 5.6.231114 https://gitee.com/qdbp/qdbp-able/ qdbp tools library -- Gitee From b9e9c3ce7449e9b552c424e864a166287f8af5d8 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 20:14:08 +0800 Subject: [PATCH 49/54] VolatileData.expireAt --- able/src/main/java/com/gitee/qdbp/able/beans/VolatileData.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/able/src/main/java/com/gitee/qdbp/able/beans/VolatileData.java b/able/src/main/java/com/gitee/qdbp/able/beans/VolatileData.java index d597ed8..ab6664e 100644 --- a/able/src/main/java/com/gitee/qdbp/able/beans/VolatileData.java +++ b/able/src/main/java/com/gitee/qdbp/able/beans/VolatileData.java @@ -43,7 +43,7 @@ public class VolatileData implements Copyable, Serializable { } /** 设置过期时间(绝对时间) **/ - public VolatileData setExpireTime(Long expireTime) { + public VolatileData expireAt(Long expireTime) { this.expireTime = expireTime; return this; } -- Gitee From eb04303d687b858827807fe59495ca3529176070 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Thu, 16 Nov 2023 19:19:48 +0800 Subject: [PATCH 50/54] =?UTF-8?q?pom=E7=9A=84profile=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- json/pom.xml | 2 +- pom.xml | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/json/pom.xml b/json/pom.xml index 39138b2..87e96fc 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-parent - 5.0.1 + 5.0.2 qdbp-json diff --git a/pom.xml b/pom.xml index 55de679..2600de9 100644 --- a/pom.xml +++ b/pom.xml @@ -100,17 +100,6 @@ - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.8 - true - - sonatype-qdbp - https://oss.sonatype.org/ - true - - @@ -147,6 +136,17 @@ + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.8 + true + + sonatype-qdbp + https://oss.sonatype.org/ + true + + org.apache.maven.plugins maven-gpg-plugin -- Gitee From d0b1724fb40277a8caaaa0aba658d62b845943d5 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 26 Nov 2023 19:34:22 +0800 Subject: [PATCH 51/54] =?UTF-8?q?ExtraBase.getExtra=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E6=B3=9B=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/gitee/qdbp/able/model/reusable/ExtraBase.java | 2 +- .../java/com/gitee/qdbp/able/model/reusable/ExtraData.java | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/able/model/reusable/ExtraBase.java b/able/src/main/java/com/gitee/qdbp/able/model/reusable/ExtraBase.java index 2fdf49c..b6a39dc 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/reusable/ExtraBase.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/reusable/ExtraBase.java @@ -20,7 +20,7 @@ public interface ExtraBase { boolean containsExtra(String key); /** 获取指定的附加数据 **/ - Object getExtra(String key); + T getExtra(String key); /** 获取指定类型的附加数据 **/ T getExtra(String key, Class clazz); diff --git a/able/src/main/java/com/gitee/qdbp/able/model/reusable/ExtraData.java b/able/src/main/java/com/gitee/qdbp/able/model/reusable/ExtraData.java index 144c235..2423549 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/reusable/ExtraData.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/reusable/ExtraData.java @@ -46,8 +46,9 @@ public class ExtraData implements Serializable, ExtraBase { /** 获取指定的附加数据 **/ @Override - public Object getExtra(String key) { - return this.extra == null ? null : this.extra.get(key); + @SuppressWarnings("unchecked") + public T getExtra(String key) { + return this.extra == null ? null : (T) this.extra.get(key); } /** 获取指定类型的附加数据 **/ -- Gitee From 1b4e3fca6441af5b751d6391a63ea7bd2184172f Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 26 Nov 2023 19:34:59 +0800 Subject: [PATCH 52/54] =?UTF-8?q?isLikeDateFormat=E6=8F=90=E5=8F=96?= =?UTF-8?q?=E4=B8=BA=E5=85=AC=E5=85=B1=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/tools/utils/ConvertTools.java | 51 ++----------------- .../com/gitee/qdbp/tools/utils/DateTools.java | 43 ++++++++++++++++ 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java index 8905d05..fe0b827 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java @@ -1294,22 +1294,21 @@ public class ConvertTools { } } else if (fieldName != null) { try { - if (fieldName.endsWith("OfMinInDay") || fieldName.endsWith("OfMinDay")) { + if (fieldName.endsWith("OfMinWithDay") || fieldName.endsWith("OfMinDay")) { Date date = DateTools.parse(fieldValue); return DateTools.toStartTime(date); - } else if (fieldName.endsWith("OfMaxInDay") || fieldName.endsWith("OfMaxDay")) { + } else if (fieldName.endsWith("OfMaxWithDay") || fieldName.endsWith("OfMaxDay")) { Date date = DateTools.parse(fieldValue); return DateTools.toEndTime(date); } else if (fieldName.endsWith("Date") || fieldName.endsWith("_DATE")) { return DateTools.parse(fieldValue); } else if (fieldName.endsWith("Time") || fieldName.endsWith("_TIME")) { return DateTools.parse(fieldValue); - } else if (isLikeDateFormat(fieldValue)) { - return DateTools.parse(fieldValue); } } catch (IllegalArgumentException ignore) { } - } else if (isLikeDateFormat(fieldValue)) { + } + if (DateTools.isLikeDateFormat(fieldValue)) { try { return DateTools.parse(fieldValue); } catch (IllegalArgumentException ignore) { @@ -1319,48 +1318,6 @@ public class ConvertTools { return fieldValue; } - /** 支持哪些日期格式 **/ - private static final List DATE_FORMATS = Arrays.asList( - "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss.SSS" - ); - - private static boolean isLikeDateFormat(String source) { - for (String format : DATE_FORMATS) { - if (isDateFormatMatches(source, format)) { - return true; - } - } - return false; - } - - // 检查字符串是不是日期时间格式 - private static boolean isDateFormatMatches(String source, String format) { - if (VerifyTools.isAnyBlank(source, format)) { - return false; - } - int sLength = source.length(); - int fLength = format.length(); - if (sLength != fLength) { - return false; - } - for (int i = 0; i < fLength; i++) { - char s = source.charAt(i); - char c = format.charAt(i); - if (c == 'y' || c == 'M' || c == 'd' || c == 'H' || c == 'h' || c == 'm' || c == 's' || c == 'S') { - // 遇到yyyy MM dd HH mm ss SSS之类的字符, 则原字符必须是数字 - if (s < '0' || s > '9') { - return false; - } - } else { - // 遇到其他字符, 则原字符必须与该字符相等 - if (s != c) { - return false; - } - } - } - return true; - } - /** * 压缩列表, 保留指定数目 * diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/DateTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/DateTools.java index 8b4a3e5..34dd016 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/DateTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/DateTools.java @@ -1294,4 +1294,47 @@ public class DateTools { return d.getTime(); } } + + /** 检查字符串是不是日期时间格式 **/ + public static boolean isLikeDateFormat(String source) { + return isLikeDateFormat(source, PATTERN_GENERAL_DATE, PATTERN_GENERAL_DATETIME, PATTERN_GENERAL_NORMATIVE); + } + + /** 检查字符串是不是日期时间格式 **/ + public static boolean isLikeDateFormat(String source, String... formats) { + for (String format : formats) { + if (isDateFormatMatches(source, format)) { + return true; + } + } + return false; + } + + /** 检查字符串是不是日期时间格式 **/ + private static boolean isDateFormatMatches(String source, String format) { + if (VerifyTools.isAnyBlank(source, format)) { + return false; + } + int sLength = source.length(); + int fLength = format.length(); + if (sLength != fLength) { + return false; + } + for (int i = 0; i < fLength; i++) { + char s = source.charAt(i); + char c = format.charAt(i); + if (c == 'y' || c == 'M' || c == 'd' || c == 'H' || c == 'h' || c == 'm' || c == 's' || c == 'S') { + // 遇到yyyy MM dd HH mm ss SSS之类的字符, 则原字符必须是数字 + if (s < '0' || s > '9') { + return false; + } + } else { + // 遇到其他字符, 则原字符必须与该字符相等 + if (s != c) { + return false; + } + } + } + return true; + } } -- Gitee From 34c1fd2b93bb0fce9cbc2a742076bc5b0f16e55f Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 26 Nov 2023 19:35:57 +0800 Subject: [PATCH 53/54] =?UTF-8?q?beanToMap=E6=94=B9=E4=B8=BA=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E4=B8=8D=E6=B8=85=E9=99=A4=E7=A9=BA=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java index f67e211..cc1ba68 100644 --- a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java +++ b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java @@ -74,7 +74,7 @@ public abstract class JsonServiceForBase implements JsonService { if (bean == null) { return null; } - return beanToMap(bean, true, true); + return beanToMap(bean, true, false); } /** -- Gitee From 2fba497b6174bd64a220cb1c2d713184efbcb9c9 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 26 Nov 2023 19:46:16 +0800 Subject: [PATCH 54/54] 5.6.231125 --- README.md | 4 ++-- able/pom.xml | 2 +- json/pom.xml | 4 ++-- test/pom.xml | 2 +- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- test/qdbp-tools-test-jdk8/pom.xml | 2 +- tools/pom.xml | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index b289bfa..35b11f6 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.6.231114 + 5.6.231125 ``` ```xml com.gitee.qdbp qdbp-tools - 5.6.231114 + 5.6.231125 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index 18fad33..68630f4 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.6.231114 + 5.6.231125 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ diff --git a/json/pom.xml b/json/pom.xml index 87e96fc..c647960 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.6.231114 + 5.6.231125 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.6.231114 + 5.6.231125 diff --git a/test/pom.xml b/test/pom.xml index 83be4e1..a6b4941 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.6.231114 + 5.6.231125 https://gitee.com/qdbp/qdbp-able/ qdbp json test diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index ec707ee..5f15217 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.231114 + 5.6.231125 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index 7a2f37b..a32e9d0 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.231114 + 5.6.231125 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index 52d9b1f..ec12c46 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.231114 + 5.6.231125 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index aa6d861..e6c9267 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.231114 + 5.6.231125 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index 3df57da..bcf96e9 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.231114 + 5.6.231125 qdbp-tools-test-jdk7 diff --git a/test/qdbp-tools-test-jdk8/pom.xml b/test/qdbp-tools-test-jdk8/pom.xml index 12bf95b..01c624c 100644 --- a/test/qdbp-tools-test-jdk8/pom.xml +++ b/test/qdbp-tools-test-jdk8/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.231114 + 5.6.231125 qdbp-tools-test-jdk8 diff --git a/tools/pom.xml b/tools/pom.xml index 404ed99..9bff829 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.6.231114 + 5.6.231125 https://gitee.com/qdbp/qdbp-able/ qdbp tools library -- Gitee