diff --git a/pom.xml b/pom.xml index 39a0400..8a1a2cd 100644 --- a/pom.xml +++ b/pom.xml @@ -25,12 +25,6 @@ ${guava.version} - - org.apache.commons - commons-lang3 - ${commons-lang3.version} - - joda-time joda-time @@ -40,6 +34,13 @@ + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + test + + ch.qos.logback logback-classic diff --git a/src/main/java/xyz/zhouxy/plusone/commons/base/JRE.java b/src/main/java/xyz/zhouxy/plusone/commons/base/JRE.java index a4ae6cf..fa0d3d4 100644 --- a/src/main/java/xyz/zhouxy/plusone/commons/base/JRE.java +++ b/src/main/java/xyz/zhouxy/plusone/commons/base/JRE.java @@ -17,8 +17,7 @@ package xyz.zhouxy.plusone.commons.base; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.reflect.MethodUtils; +import xyz.zhouxy.plusone.commons.util.StringTools; /** * JRE version @@ -35,23 +34,30 @@ public class JRE { private static int getJre() { String version = System.getProperty("java.version"); - boolean isBlank = StringUtils.isBlank(version); - if (!isBlank && version.startsWith("1.8")) { + boolean isNotBlank = StringTools.isNotBlank(version); + if (isNotBlank && version.startsWith("1.8")) { return JAVA_8; } // if JRE version is 9 or above, we can get version from // java.lang.Runtime.version() try { - Object javaRunTimeVersion = MethodUtils.invokeMethod(Runtime.getRuntime(), "version"); - return (int) MethodUtils.invokeMethod(javaRunTimeVersion, "major"); + return getMajorVersion(version); } catch (Exception e) { - // Can't determine current JRE version (maybe java.version is null), // assuming that JRE version is 8. } // default java 8 return JAVA_8; } + private static int getMajorVersion(String version) { + if (version.startsWith("1.")) { + return Integer.parseInt(version.substring(2, 3)); + } else { + int dotIndex = version.indexOf("."); + return (dotIndex != -1) ? Integer.parseInt(version.substring(0, dotIndex)) : Integer.parseInt(version); + } + } + private JRE() { throw new IllegalStateException("Utility class"); } diff --git a/src/main/java/xyz/zhouxy/plusone/commons/model/dto/PagingAndSortingQueryParams.java b/src/main/java/xyz/zhouxy/plusone/commons/model/dto/PagingAndSortingQueryParams.java index 9db260a..2ad3374 100644 --- a/src/main/java/xyz/zhouxy/plusone/commons/model/dto/PagingAndSortingQueryParams.java +++ b/src/main/java/xyz/zhouxy/plusone/commons/model/dto/PagingAndSortingQueryParams.java @@ -23,12 +23,11 @@ import java.util.stream.Collectors; import javax.annotation.Nullable; -import org.apache.commons.lang3.StringUtils; - import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; import xyz.zhouxy.plusone.commons.annotation.Virtual; +import xyz.zhouxy.plusone.commons.util.StringTools; /** * 分页排序查询参数 @@ -57,7 +56,7 @@ public class PagingAndSortingQueryParams { Preconditions.checkArgument(sortableProperties != null && !sortableProperties.isEmpty(), "Sortable properties can not be empty."); sortableProperties.forEach((k, v) -> - Preconditions.checkArgument(StringUtils.isNotBlank(k) && StringUtils.isNotBlank(v), + Preconditions.checkArgument(StringTools.isNotBlank(k) && StringTools.isNotBlank(v), "Property name must not be blank.")); this.sortableProperties = ImmutableMap.copyOf(sortableProperties); } diff --git a/src/main/java/xyz/zhouxy/plusone/commons/util/BigDecimals.java b/src/main/java/xyz/zhouxy/plusone/commons/util/BigDecimals.java index f56a998..e502a77 100644 --- a/src/main/java/xyz/zhouxy/plusone/commons/util/BigDecimals.java +++ b/src/main/java/xyz/zhouxy/plusone/commons/util/BigDecimals.java @@ -1,11 +1,10 @@ package xyz.zhouxy.plusone.commons.util; import java.math.BigDecimal; +import java.math.RoundingMode; import javax.annotation.Nullable; -import org.apache.commons.lang3.StringUtils; - import com.google.common.base.Preconditions; public class BigDecimals { @@ -37,7 +36,171 @@ public class BigDecimals { } public static BigDecimal of(final String val) { - return (StringUtils.isBlank(val)) ? ZERO : new BigDecimal(val); + return (StringTools.isNotBlank(val)) ? new BigDecimal(val) : ZERO; + } + + /** + * 默认除法运算精度 + */ + private static final int DEF_DIV_SCALE = 10; + + /** + * 提供精确的加法运算。 + * + * @param v1 被加数 + * @param v2 加数 + * @return 两个参数的和 + */ + public static double add(double v1, double v2) { + BigDecimal b1 = BigDecimal.valueOf(v1); + BigDecimal b2 = BigDecimal.valueOf(v2); + return b1.add(b2).doubleValue(); + } + + /** + * 提供精确的减法运算。 + * + * @param v1 被减数 + * @param v2 减数 + * @return 两个参数的差 + */ + public static double subtract(double v1, double v2) { + BigDecimal b1 = BigDecimal.valueOf(v1); + BigDecimal b2 = BigDecimal.valueOf(v2); + return b1.subtract(b2).doubleValue(); + } + + /** + * 提供精确的乘法运算。 + * + * @param v1 被乘数 + * @param v2 乘数 + * @return 两个参数的积 + */ + public static double multiply(double v1, double v2) { + BigDecimal b1 = BigDecimal.valueOf(v1); + BigDecimal b2 = BigDecimal.valueOf(v2); + return b1.multiply(b2).doubleValue(); + } + + /** + * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 + * 小数点以后10位,以后的数字四舍五入。 + * + * @param v1 被除数 + * @param v2 除数 + * @return 两个参数的商 + */ + public static double divide(double v1, double v2) { + return divide(v1, v2, DEF_DIV_SCALE); + } + + /** + * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 + * 定精度,以后的数字四舍五入。 + * + * @param v1 被除数 + * @param v2 除数 + * @param scale 表示表示需要精确到小数点以后几位。 + * @return 两个参数的商 + */ + public static double divide(double v1, double v2, int scale) { + if (scale < 0) { + throw new IllegalArgumentException( + "The scale must be a positive integer or zero"); + } + BigDecimal b1 = BigDecimal.valueOf(v1); + BigDecimal b2 = BigDecimal.valueOf(v2); + return b1.divide(b2, scale, RoundingMode.HALF_EVEN).doubleValue(); + } + + /** + * 提供精确的小数位四舍五入处理。 + * + * @param v 需要四舍五入的数字 + * @param scale 小数点后保留几位 + * @return 四舍五入后的结果 + */ + public static double round(double v, int scale) { + if (scale < 0) { + throw new IllegalArgumentException( + "The scale must be a positive integer or zero"); + } + BigDecimal b = BigDecimal.valueOf(v); + BigDecimal one = new BigDecimal("1"); + return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue(); + } + + /** + * 提供精确的类型转换(Float) + * + * @param v 需要被转换的数字 + * @return 返回转换结果 + */ + public static float convertToFloat(double v) { + BigDecimal b = BigDecimal.valueOf(v); + return b.floatValue(); + } + + /** + * 提供精确的类型转换(Int)不进行四舍五入 + * + * @param v 需要被转换的数字 + * @return 返回转换结果 + */ + public static int convertsToInt(double v) { + BigDecimal b = BigDecimal.valueOf(v); + return b.intValue(); + } + + /** + * 提供精确的类型转换(Long) + * + * @param v 需要被转换的数字 + * @return 返回转换结果 + */ + public static long convertsToLong(double v) { + BigDecimal b = BigDecimal.valueOf(v); + return b.longValue(); + } + + /** + * 返回两个数中大的一个值 + * + * @param v1 需要被对比的第一个数 + * @param v2 需要被对比的第二个数 + * @return 返回两个数中大的一个值 + */ + public static double returnMax(double v1, double v2) { + BigDecimal b1 = BigDecimal.valueOf(v1); + BigDecimal b2 = BigDecimal.valueOf(v2); + return b1.max(b2).doubleValue(); + } + + /** + * 返回两个数中小的一个值 + * + * @param v1 需要被对比的第一个数 + * @param v2 需要被对比的第二个数 + * @return 返回两个数中小的一个值 + */ + public static double returnMin(double v1, double v2) { + BigDecimal b1 = BigDecimal.valueOf(v1); + BigDecimal b2 = BigDecimal.valueOf(v2); + return b1.min(b2).doubleValue(); + } + + /** + * 精确对比两个数字 + * + * @param v1 需要被对比的第一个数 + * @param v2 需要被对比的第二个数 + * @return 如果两个数一样则返回0,如果第一个数比第二个数大则返回1,反之返回-1 + */ + public static int compareTo(double v1, double v2) { + BigDecimal b1 = BigDecimal.valueOf(v1); + BigDecimal b2 = BigDecimal.valueOf(v2); + return b1.compareTo(b2); } private BigDecimals() { diff --git a/src/main/java/xyz/zhouxy/plusone/commons/util/Enumeration.java b/src/main/java/xyz/zhouxy/plusone/commons/util/Enumeration.java index d4ea36b..5357e9c 100644 --- a/src/main/java/xyz/zhouxy/plusone/commons/util/Enumeration.java +++ b/src/main/java/xyz/zhouxy/plusone/commons/util/Enumeration.java @@ -24,8 +24,6 @@ import java.util.Objects; import java.util.function.Function; import java.util.stream.Collectors; -import org.apache.commons.lang3.StringUtils; - import com.google.common.base.Preconditions; import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod; @@ -45,7 +43,7 @@ public abstract class Enumeration> // NOSONAR 暂不移 protected final String name; protected Enumeration(final int id, final String name) { - Preconditions.checkArgument(StringUtils.isNotBlank(name), "Name of enumeration must has text."); + Preconditions.checkArgument(StringTools.isNotBlank(name), "Name of enumeration must has text."); this.id = id; this.name = name; } diff --git a/src/main/java/xyz/zhouxy/plusone/commons/util/StringTools.java b/src/main/java/xyz/zhouxy/plusone/commons/util/StringTools.java new file mode 100644 index 0000000..2016d83 --- /dev/null +++ b/src/main/java/xyz/zhouxy/plusone/commons/util/StringTools.java @@ -0,0 +1,20 @@ +package xyz.zhouxy.plusone.commons.util; + +public class StringTools { + + public static boolean isNotBlank(final String cs) { + if (cs == null || cs.isEmpty()) { + return false; + } + for (int i = 0; i < cs.length(); i++) { + if (!Character.isWhitespace(cs.charAt(i))) { + return true; + } + } + return false; + } + + private StringTools() { + throw new IllegalStateException("Utility class"); + } +} diff --git a/src/test/java/xyz/zhouxy/plusone/commons/util/DateTimeToolsTests.java b/src/test/java/xyz/zhouxy/plusone/commons/util/DateTimeToolsTests.java index 4ebab7f..9166e61 100644 --- a/src/test/java/xyz/zhouxy/plusone/commons/util/DateTimeToolsTests.java +++ b/src/test/java/xyz/zhouxy/plusone/commons/util/DateTimeToolsTests.java @@ -6,6 +6,7 @@ import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import org.junit.jupiter.api.Test; import org.slf4j.Logger; @@ -47,15 +48,14 @@ class DateTimeToolsTests { void testToJodaDateTime() { ZonedDateTime dt = ZonedDateTime.of(2008, 1, 8, 10, 23, 50, 108000000, ZoneId.systemDefault()); Instant instant = DateTimeTools.toInstant(dt.toInstant().toEpochMilli()); - + org.joda.time.format.DateTimeFormatter f = org.joda.time.format.DateTimeFormat .forPattern("yyyy-MM-dd HH:mm:ss.SSS"); org.joda.time.DateTime jodaDateTime = DateTimeTools.toJodaDateTime(instant, ZoneId.of("+08:00")); log.info("jodaDateTime: {}", jodaDateTime); assertEquals("2008-01-08 10:23:50.108", f.print(jodaDateTime)); - - + jodaDateTime = DateTimeTools.toJodaDateTime(instant, ZoneId.of("+02:00")); log.info("jodaDateTime: {}", jodaDateTime); assertEquals("2008-01-08 04:23:50.108", f.print(jodaDateTime)); @@ -65,8 +65,8 @@ class DateTimeToolsTests { void test() { java.time.Instant now = java.time.Instant.now(); org.joda.time.DateTime jodaDateTime = DateTimeTools.toJodaDateTime(now, ZoneId.of("America/New_York")); - org.joda.time.format.DateTimeFormatter formatter = - org.joda.time.format.DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS"); + org.joda.time.format.DateTimeFormatter formatter = org.joda.time.format.DateTimeFormat + .forPattern("yyyy-MM-dd HH:mm:ss.SSS"); log.info(formatter.print(jodaDateTime)); log.info(jodaDateTime.getZone().toString()); log.info(jodaDateTime.toString()); @@ -74,7 +74,8 @@ class DateTimeToolsTests { org.joda.time.Instant instant = new org.joda.time.Instant(System.currentTimeMillis() - 500000); log.info(instant.toString()); log.info(DateTimeTools.toJavaInstant(instant).toString()); - log.info(DateTimeTools.toZonedDateTime(instant, org.joda.time.DateTimeZone.forID("America/New_York")).toString()); + log.info(DateTimeTools.toZonedDateTime(instant, org.joda.time.DateTimeZone.forID("America/New_York")) + .toString()); } @Test @@ -84,5 +85,10 @@ class DateTimeToolsTests { org.joda.time.Instant jodaInstant = DateTimeTools.toJodaInstant(javaInstant); log.info("jodaInstant: {}", jodaInstant); + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); + DateTimeFormatter formatter2 = formatter.withZone(ZoneId.systemDefault()); + log.info("{}", formatter); + log.info("{}", formatter2); } } diff --git a/src/test/java/xyz/zhouxy/plusone/commons/util/TreeBuilderTests.java b/src/test/java/xyz/zhouxy/plusone/commons/util/TreeBuilderTests.java index a1f56f6..197ca89 100644 --- a/src/test/java/xyz/zhouxy/plusone/commons/util/TreeBuilderTests.java +++ b/src/test/java/xyz/zhouxy/plusone/commons/util/TreeBuilderTests.java @@ -1,7 +1,9 @@ package xyz.zhouxy.plusone.commons.util; +import java.io.Serializable; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; import org.junit.jupiter.api.Test; import org.slf4j.Logger; @@ -10,6 +12,7 @@ import org.slf4j.LoggerFactory; import com.google.common.collect.Lists; import com.google.gson.Gson; +import cn.hutool.core.util.ObjectUtil; import lombok.ToString; class TreeBuilderTests { @@ -37,11 +40,15 @@ class TreeBuilderTests { /**//**/MenuItem.of("C1", "C1002", "三级菜单C1002", "/c/c1/c1002", 2), /**/MenuItem.of("C", "C2", "二级菜单C2", "/c/c2", 1)); - List menuTreeSortedByOrderNum = treeBuilder.buildTree(menus); + List clonedMenus; + + clonedMenus = menus.stream().map(m -> ObjectUtil.clone(m)).collect(Collectors.toList()); + List menuTreeSortedByOrderNum = treeBuilder.buildTree(clonedMenus); log.info("menuTreeSortedByOrderNum: {}", new Gson().toJson(menuTreeSortedByOrderNum)); + clonedMenus = menus.stream().map(m -> ObjectUtil.clone(m)).collect(Collectors.toList()); List menuTreeSortedByMenuCode = treeBuilder.buildTree( - menus, + clonedMenus, (a, b) -> a.getMenuCode().compareTo(b.getMenuCode()) ); log.info("menuTreeSortedByMenuCode: {}", new Gson().toJson(menuTreeSortedByMenuCode)); @@ -49,7 +56,7 @@ class TreeBuilderTests { } @ToString -abstract class Menu { +abstract class Menu implements Serializable { protected final String parentMenuCode; protected final String menuCode; protected final String title; @@ -77,6 +84,8 @@ abstract class Menu { public int getOrderNum() { return orderNum; } + + private static final long serialVersionUID = 20240917181424L; } @ToString(callSuper = true) @@ -100,6 +109,8 @@ class MenuItem extends Menu { public String getUrl() { return url; } + + private static final long serialVersionUID = 20240917181910L; } @ToString(callSuper = true) @@ -135,4 +146,6 @@ class MenuList extends Menu { } this.children.add(child); } + + private static final long serialVersionUID = 20240917181917L; }