Bläddra i källkod

优化数字范围对象处理逻辑;优化自定义枚举对象处理逻辑;

Woody 6 dagar sedan
förälder
incheckning
fd4f7ffa7b

+ 67 - 45
framework-common/src/main/java/com/chelvc/framework/common/model/Enumeration.java

@@ -5,6 +5,7 @@ import java.io.Serializable;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -74,12 +75,12 @@ public abstract class Enumeration implements Serializable {
     }
 
     /**
-     * 枚举对象/值列表映射表
+     * 枚举对象/编码/排序/是否动态映射表
      */
-    private static final Map<Class<?>, List<Pair<String, Boolean>>> VALUES = Maps.newConcurrentMap();
+    private static final Map<Class<?>, List<BiPair<String, Integer, Boolean>>> VALUES = Maps.newConcurrentMap();
 
     /**
-     * 枚举对象//实例映射表
+     * 枚举对象/编码/实例映射表
      */
     private static final Map<Class<?>, Map<String, Enumeration>> INSTANCES = Maps.newConcurrentMap();
 
@@ -88,6 +89,11 @@ public abstract class Enumeration implements Serializable {
      */
     private final String code;
 
+    /**
+     * 排序数字
+     */
+    private final int ordinal;
+
     /**
      * 是否动态
      */
@@ -99,52 +105,55 @@ public abstract class Enumeration implements Serializable {
     private final String description;
 
     protected Enumeration() {
-        this(null);
+        this(null, null);
+    }
+
+    protected Enumeration(Integer ordinal) {
+        this(ordinal, null);
     }
 
     protected Enumeration(String description) {
+        this(null, description);
+    }
+
+    protected Enumeration(Integer ordinal, String description) {
         Class<?> clazz = this.getClass();
         synchronized (clazz.getName().intern()) {
-            List<Pair<String, Boolean>> values = VALUES.get(clazz);
+            List<BiPair<String, Integer, Boolean>> values = VALUES.get(clazz);
             if (ObjectUtils.isEmpty(values) && INSTANCES.containsKey(clazz)) {
                 throw new IllegalStateException("Invalid enumeration instance");
             } else if (ObjectUtils.isEmpty(values)) {
                 values = VALUES.computeIfAbsent(clazz, Enumeration::getValues);
             }
-            Pair<String, Boolean> pair = values.remove(0);
-            this.code = Objects.requireNonNull(pair.getKey());
-            this.dynamic = Boolean.TRUE.equals(pair.getValue());
+            BiPair<String, Integer, Boolean> pair = values.remove(0);
+            this.code = Objects.requireNonNull(pair.getLeft());
+            this.ordinal = ObjectUtils.ifNull(ordinal, pair::getMiddle);
+            this.dynamic = Boolean.TRUE.equals(pair.getRight());
             if (ObjectUtils.isEmpty(values)) {
                 VALUES.remove(clazz);
             }
         }
 
-        // 设置枚举描述信息
         this.description = ObjectUtils.ifNull(description, this.code);
-
-        // 保存枚举值/实例映射
         INSTANCES.computeIfAbsent(clazz, k -> Maps.newConcurrentMap()).putIfAbsent(this.code, this);
     }
 
     /**
-     * 获取枚举值
+     * 获取枚举值,需要返回一个可更新列表
      *
      * @param clazz 枚举对象
-     * @return 枚举/是否动态信息列表
+     * @return 枚举编码/排序/是否动态信息列表
      */
-    private static List<Pair<String, Boolean>> getValues(Class<?> clazz) {
-        Field[] fields = clazz.getDeclaredFields();
-        List<Pair<String, Boolean>> values = Lists.newLinkedList();
+    private static List<BiPair<String, Integer, Boolean>> getValues(Class<?> clazz) {
+        Field[] fields = clazz.getFields();
+        List<BiPair<String, Integer, Boolean>> values = Lists.newLinkedList();
         if (ObjectUtils.notEmpty(fields)) {
             for (Field field : fields) {
                 Class<?> type = field.getType();
-                if (type.isAssignableFrom(clazz) || clazz.isAssignableFrom(type)) {
-                    int modifiers = field.getModifiers();
-                    if (!(type == clazz && Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)
-                            && Modifier.isFinal(modifiers))) {
-                        throw new IllegalStateException("Invalid enumeration field: " + field);
-                    }
-                    values.add(Pair.of(field.getName(), false));
+                int modifiers = field.getModifiers();
+                if (type == clazz && Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)
+                        && Modifier.isFinal(modifiers)) {
+                    values.add(BiPair.of(field.getName(), values.size(), false));
                 }
             }
         }
@@ -172,36 +181,26 @@ public abstract class Enumeration implements Serializable {
             synchronized (type.getName().intern()) {
                 if ((instances = INSTANCES.get(type)) == null) {
                     // 枚举字段尚未初始化
-                    List<Pair<String, Boolean>> values = VALUES.computeIfAbsent(type, Enumeration::getValues);
-                    dynamic = values.stream().noneMatch(pair -> Objects.equals(pair.getKey(), value));
-                    values.add(Pair.of(value, dynamic));
+                    List<BiPair<String, Integer, Boolean>> values =
+                            VALUES.computeIfAbsent(type, Enumeration::getValues);
+                    BiPair<String, Integer, Boolean> found =
+                            values.stream().filter(p -> Objects.equals(p.getLeft(), value)).findAny().orElse(null);
+                    int ordinal = (dynamic = Objects.isNull(found)) ? 0 : found.getMiddle();
+                    values.add(BiPair.of(value, ordinal, dynamic));
                 } else if ((instance = instances.get(value)) == null) {
                     // 枚举字段已经初始化
-                    VALUES.put(type, Lists.newArrayList(Pair.of(value, dynamic = true)));
+                    VALUES.put(type, Lists.newArrayList(BiPair.of(value, 0, dynamic = true)));
                 } else {
                     return (T) instance;
                 }
 
-                // 优先使用无参构造函数初始化枚举实例,如果函数不存在则使用枚举描述构造函数
-                Constructor<T> constructor;
+                // 使用无参构造方法初始化枚举实例
                 try {
-                    constructor = type.getDeclaredConstructor();
-                } catch (NoSuchMethodException e) {
-                    try {
-                        constructor = type.getDeclaredConstructor(String.class);
-                    } catch (NoSuchMethodException ignore) {
-                        throw new RuntimeException(e);
-                    }
-                }
-                if (!constructor.isAccessible()) {
-                    constructor.setAccessible(true);
-                }
-                try {
-                    if (constructor.getParameterCount() > 0) {
-                        instance = constructor.newInstance(value);
-                    } else {
-                        instance = constructor.newInstance();
+                    Constructor<T> constructor = type.getDeclaredConstructor();
+                    if (!constructor.isAccessible()) {
+                        constructor.setAccessible(true);
                     }
+                    instance = constructor.newInstance();
                 } catch (ReflectiveOperationException e) {
                     throw new RuntimeException(e);
                 }
@@ -215,6 +214,29 @@ public abstract class Enumeration implements Serializable {
         return (T) instance;
     }
 
+    /**
+     * 获取枚举实例
+     *
+     * @param type 枚举类型
+     * @param <T>  对象类型
+     * @return 枚举编码/实例映射表
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends Enumeration> Map<String, T> getInstances(@NonNull Class<T> type) {
+        Map<String, T> instances = (Map<String, T>) INSTANCES.get(type);
+        if (instances == null) {
+            synchronized (type.getName().intern()) {
+                if ((instances = (Map<String, T>) INSTANCES.get(type)) == null) {
+                    // 临时设置一个无效枚举实例,待枚举对象实例初始化完成后移除
+                    parse(type, StringUtils.SPACE);
+                    instances = (Map<String, T>) INSTANCES.get(type);
+                    instances.remove(StringUtils.SPACE);
+                }
+            }
+        }
+        return Collections.unmodifiableMap(instances);
+    }
+
     @Override
     public int hashCode() {
         return this.code.hashCode();

+ 11 - 12
framework-common/src/main/java/com/chelvc/framework/common/model/Range.java

@@ -3,6 +3,7 @@ package com.chelvc.framework.common.model;
 import java.io.Serializable;
 import java.util.function.Function;
 
+import com.chelvc.framework.common.util.NumberUtils;
 import com.chelvc.framework.common.util.ObjectUtils;
 import com.chelvc.framework.common.util.StringUtils;
 import lombok.Builder;
@@ -23,19 +24,19 @@ public final class Range implements Serializable {
     /**
      * 最小值
      */
-    private Double min;
+    private Number min;
 
     /**
      * 最大值
      */
-    private Double max;
+    private Number max;
 
     public Range() {
     }
 
     public Range(Number min, Number max) {
-        this.min = ObjectUtils.ifNull(min, Number::doubleValue);
-        this.max = ObjectUtils.ifNull(max, Number::doubleValue);
+        this.min = min;
+        this.max = max;
     }
 
     /**
@@ -50,7 +51,7 @@ public final class Range implements Serializable {
                 return new Range(l == null ? r : l, r == null ? l : r);
             }
             return new Range(l, r);
-        }, Double::parseDouble);
+        }, number -> number.indexOf('.') > -1 ? Double.parseDouble(number) : Long.parseLong(number));
     }
 
     /**
@@ -60,11 +61,9 @@ public final class Range implements Serializable {
      * @return true/false
      */
     public boolean contains(Number number) {
-        if (number != null && (this.min != null || this.max != null)) {
-            double value = number.doubleValue();
-            return (this.min == null || value >= this.min) && (this.max == null || value <= this.max);
-        }
-        return false;
+        return number != null && (this.min != null || this.max != null)
+                && (this.min == null || NumberUtils.compare(this.min, number) <= 0)
+                && (this.max == null || NumberUtils.compare(this.max, number) >= 0);
     }
 
     /**
@@ -74,7 +73,7 @@ public final class Range implements Serializable {
      * @param <R>      返回值类型
      * @return 最小值
      */
-    public <R> R getMin(@NonNull Function<Double, R> function) {
+    public <R> R getMin(@NonNull Function<Number, R> function) {
         return ObjectUtils.ifNull(this.min, function);
     }
 
@@ -85,7 +84,7 @@ public final class Range implements Serializable {
      * @param <R>      返回值类型
      * @return 最大值
      */
-    public <R> R getMax(@NonNull Function<Double, R> function) {
+    public <R> R getMax(@NonNull Function<Number, R> function) {
         return ObjectUtils.ifNull(this.max, function);
     }
 

+ 33 - 3
framework-common/src/main/java/com/chelvc/framework/common/util/NumberUtils.java

@@ -3,6 +3,7 @@ package com.chelvc.framework.common.util;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.math.RoundingMode;
+import java.util.Objects;
 
 import lombok.NonNull;
 
@@ -42,6 +43,35 @@ public final class NumberUtils {
     private NumberUtils() {
     }
 
+    /**
+     * 比较数字大小
+     *
+     * @param a 比较数
+     * @param b 比较数
+     * @return 比较结果
+     */
+    public static int compare(Number a, Number b) {
+        if (Objects.equals(a, b)) {
+            return 0;
+        } else if (a == null) {
+            return -1;
+        } else if (b == null) {
+            return 1;
+        } else if (a instanceof BigInteger && b instanceof BigInteger) {
+            return ((BigInteger) a).compareTo((BigInteger) b);
+        } else if (a instanceof BigDecimal && b instanceof BigDecimal) {
+            return ((BigDecimal) a).compareTo((BigDecimal) b);
+        } else if ((a instanceof Byte || a instanceof Short || a instanceof Integer || a instanceof Long)
+                && (b instanceof Byte || b instanceof Short || b instanceof Integer || b instanceof Long)) {
+            return Long.compare(a.longValue(), b.longValue());
+        } else if (a instanceof BigDecimal) {
+            return ((BigDecimal) a).compareTo(new BigDecimal(b.toString()));
+        } else if (b instanceof BigDecimal) {
+            return new BigDecimal(a.toString()).compareTo((BigDecimal) b);
+        }
+        return new BigDecimal(a.toString()).compareTo(new BigDecimal(b.toString()));
+    }
+
     /**
      * 判断数字是否等于0
      *
@@ -54,7 +84,7 @@ public final class NumberUtils {
         } else if (number instanceof BigDecimal) {
             return number.equals(BigDecimal.ZERO);
         }
-        return number != null && number.doubleValue() == 0;
+        return number != null && compare(number, 0) == 0;
     }
 
     /**
@@ -69,7 +99,7 @@ public final class NumberUtils {
         } else if (number instanceof BigDecimal) {
             return ((BigDecimal) number).compareTo(BigDecimal.ZERO) < 0;
         }
-        return number == null || number.doubleValue() < 0;
+        return number == null || compare(number, 0) < 0;
     }
 
     /**
@@ -84,7 +114,7 @@ public final class NumberUtils {
         } else if (number instanceof BigDecimal) {
             return ((BigDecimal) number).compareTo(BigDecimal.ZERO) > 0;
         }
-        return number != null && number.doubleValue() > 0;
+        return number != null && compare(number, 0) > 0;
     }
 
     /**