diff --git a/CHANGELOG.md b/CHANGELOG.md index 983da7d72..e94076896 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------------------------------------- -# 5.5.0 (2020-11-09) +# 5.5.0 (2020-11-11) ### 新特性 * 【core 】 NumberUtil.parseInt等支持123,2.00这类数字(issue#I23ORQ@Gitee) @@ -14,6 +14,7 @@ * 【poi 】 ExcelWriter增加setCurrentRowToEnd方法(issue#I24A2R@Gitee) * 【core 】 ExcelWriter增加setCurrentRowToEnd方法(issue#I24A2R@Gitee) * 【extra 】 增加表达式引擎封装(ExpressionUtil)(pr#1203@Github) +* 【core 】 增加enum转数字支持(issue#I24QZY@Gitee) ### Bug修复 * 【core 】 修复DateUtil.current使用System.nanoTime的问题(issue#1198@Github) @@ -24,6 +25,7 @@ * 【poi 】 修复Excel07SaxReader读取公式的错误的问题(issue#I23VFL@Gitee) * 【http 】 修复HttpUtil.isHttp判断问题(pr#1208@Github) * 【http 】 修复Snowflake时间回拨导致ID重复的bug(issue#1206@Github) +* 【core 】 修复StrUtil.lastIndexOf查找位于首位的字符串找不到的bug(issue#I24RSV@Gitee) ------------------------------------------------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/NumberConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/NumberConverter.java index 1f366f4ad..7d41bbb4c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/NumberConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/NumberConverter.java @@ -15,6 +15,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.DoubleAdder; import java.util.concurrent.atomic.LongAdder; +import java.util.function.Function; /** * 数字转换器
@@ -54,17 +55,31 @@ public class NumberConverter extends AbstractConverter { @Override protected Number convertInternal(Object value) { - return convertInternal(value, this.targetType); + return convert(value, this.targetType, this::convertToStr); } - private Number convertInternal(Object value, Class targetType) { + /** + * 转换对象为数字 + * + * @param value 对象值 + * @param targetType 目标的数字类型 + * @param toStrFunc 转换为字符串的函数 + * @return 转换后的数字 + * @since 5.5.0 + */ + protected static Number convert(Object value, Class targetType, Function toStrFunc) { + // 枚举转换为数字默认为其顺序 + if (value instanceof Enum) { + return convert(((Enum) value).ordinal(), targetType, toStrFunc); + } + if (Byte.class == targetType) { if (value instanceof Number) { return ((Number) value).byteValue(); } else if (value instanceof Boolean) { return BooleanUtil.toByteObj((Boolean) value); } - final String valueStr = convertToStr(value); + final String valueStr = toStrFunc.apply(value); return StrUtil.isBlank(valueStr) ? null : Byte.valueOf(valueStr); } else if (Short.class == targetType) { if (value instanceof Number) { @@ -72,7 +87,7 @@ public class NumberConverter extends AbstractConverter { } else if (value instanceof Boolean) { return BooleanUtil.toShortObj((Boolean) value); } - final String valueStr = convertToStr(value); + final String valueStr = toStrFunc.apply((value)); return StrUtil.isBlank(valueStr) ? null : Short.valueOf(valueStr); } else if (Integer.class == targetType) { if (value instanceof Number) { @@ -80,16 +95,16 @@ public class NumberConverter extends AbstractConverter { } else if (value instanceof Boolean) { return BooleanUtil.toInteger((Boolean) value); } else if (value instanceof Date) { - return (int)((Date) value).getTime(); + return (int) ((Date) value).getTime(); } else if (value instanceof Calendar) { - return (int)((Calendar) value).getTimeInMillis(); + return (int) ((Calendar) value).getTimeInMillis(); } else if (value instanceof TemporalAccessor) { - return (int)DateUtil.toInstant((TemporalAccessor) value).toEpochMilli(); + return (int) DateUtil.toInstant((TemporalAccessor) value).toEpochMilli(); } - final String valueStr = convertToStr(value); + final String valueStr = toStrFunc.apply((value)); return StrUtil.isBlank(valueStr) ? null : NumberUtil.parseInt(valueStr); } else if (AtomicInteger.class == targetType) { - final Number number = convertInternal(value, Integer.class); + final Number number = convert(value, Integer.class, toStrFunc); if (null != number) { final AtomicInteger intValue = new AtomicInteger(); intValue.set(number.intValue()); @@ -107,18 +122,18 @@ public class NumberConverter extends AbstractConverter { } else if (value instanceof TemporalAccessor) { return DateUtil.toInstant((TemporalAccessor) value).toEpochMilli(); } - final String valueStr = convertToStr(value); + final String valueStr = toStrFunc.apply((value)); return StrUtil.isBlank(valueStr) ? null : NumberUtil.parseLong(valueStr); } else if (AtomicLong.class == targetType) { - final Number number = convertInternal(value, Long.class); + final Number number = convert(value, Long.class, toStrFunc); if (null != number) { final AtomicLong longValue = new AtomicLong(); longValue.set(number.longValue()); return longValue; } - }else if (LongAdder.class == targetType) { + } else if (LongAdder.class == targetType) { //jdk8 新增 - final Number number = convertInternal(value, Long.class); + final Number number = convert(value, Long.class, toStrFunc); if (null != number) { final LongAdder longValue = new LongAdder(); longValue.add(number.longValue()); @@ -130,7 +145,7 @@ public class NumberConverter extends AbstractConverter { } else if (value instanceof Boolean) { return BooleanUtil.toFloatObj((Boolean) value); } - final String valueStr = convertToStr(value); + final String valueStr = toStrFunc.apply((value)); return StrUtil.isBlank(valueStr) ? null : Float.valueOf(valueStr); } else if (Double.class == targetType) { @@ -139,31 +154,31 @@ public class NumberConverter extends AbstractConverter { } else if (value instanceof Boolean) { return BooleanUtil.toDoubleObj((Boolean) value); } - final String valueStr = convertToStr(value); + final String valueStr = toStrFunc.apply((value)); return StrUtil.isBlank(valueStr) ? null : Double.valueOf(valueStr); - }else if (DoubleAdder.class == targetType) { + } else if (DoubleAdder.class == targetType) { //jdk8 新增 - final Number number = convertInternal(value, Long.class); + final Number number = convert(value, Long.class, toStrFunc); if (null != number) { final DoubleAdder doubleAdder = new DoubleAdder(); doubleAdder.add(number.doubleValue()); return doubleAdder; } } else if (BigDecimal.class == targetType) { - return toBigDecimal(value); + return toBigDecimal(value, toStrFunc); } else if (BigInteger.class == targetType) { - return toBigInteger(value); + return toBigInteger(value, toStrFunc); } else if (Number.class == targetType) { if (value instanceof Number) { return (Number) value; } else if (value instanceof Boolean) { return BooleanUtil.toInteger((Boolean) value); } - final String valueStr = convertToStr(value); + final String valueStr = toStrFunc.apply((value)); return StrUtil.isBlank(valueStr) ? null : NumberUtil.parseNumber(valueStr); } - throw new UnsupportedOperationException(StrUtil.format("Unsupport Number type: {}", this.targetType.getName())); + throw new UnsupportedOperationException(StrUtil.format("Unsupport Number type: {}", targetType.getName())); } /** @@ -171,10 +186,11 @@ public class NumberConverter extends AbstractConverter { * 如果给定的值为空,或者转换失败,返回默认值
* 转换失败不会报错 * - * @param value 被转换的值 + * @param value 被转换的值 + * @param toStrFunc 转换为字符串的函数规则 * @return 结果 */ - private BigDecimal toBigDecimal(Object value) { + private static BigDecimal toBigDecimal(Object value, Function toStrFunc) { if (value instanceof Number) { return NumberUtil.toBigDecimal((Number) value); } else if (value instanceof Boolean) { @@ -182,7 +198,7 @@ public class NumberConverter extends AbstractConverter { } //对于Double类型,先要转换为String,避免精度问题 - return NumberUtil.toBigDecimal(convertToStr(value)); + return NumberUtil.toBigDecimal(toStrFunc.apply(value)); } /** @@ -190,25 +206,26 @@ public class NumberConverter extends AbstractConverter { * 如果给定的值为空,或者转换失败,返回默认值
* 转换失败不会报错 * - * @param value 被转换的值 + * @param value 被转换的值 + * @param toStrFunc 转换为字符串的函数规则 * @return 结果 */ - private BigInteger toBigInteger(Object value) { + private static BigInteger toBigInteger(Object value, Function toStrFunc) { if (value instanceof Long) { return BigInteger.valueOf((Long) value); } else if (value instanceof Boolean) { return BigInteger.valueOf((boolean) value ? 1 : 0); } - return NumberUtil.toBigInteger(convertToStr(value)); + return NumberUtil.toBigInteger(toStrFunc.apply(value)); } @Override protected String convertToStr(Object value) { String result = StrUtil.trim(super.convertToStr(value)); - if(StrUtil.isNotEmpty(result)){ + if (StrUtil.isNotEmpty(result)) { final char c = Character.toUpperCase(result.charAt(result.length() - 1)); - if(c == 'D' || c == 'L' || c == 'F'){ + if (c == 'D' || c == 'L' || c == 'F') { // 类型标识形式(例如123.6D) return StrUtil.subPre(result, -1); } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/PrimitiveConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/PrimitiveConverter.java index d039056cd..475bbd54d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/PrimitiveConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/PrimitiveConverter.java @@ -1,15 +1,12 @@ package cn.hutool.core.convert.impl; import cn.hutool.core.convert.AbstractConverter; +import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.ConvertException; -import cn.hutool.core.date.DateUtil; -import cn.hutool.core.util.BooleanUtil; -import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; -import java.time.temporal.TemporalAccessor; -import java.util.Calendar; -import java.util.Date; +import java.util.function.Function; /** * 原始类型转换器
@@ -49,114 +46,7 @@ public class PrimitiveConverter extends AbstractConverter { @Override protected Object convertInternal(Object value) { - if (byte.class == this.targetType) { - if (value instanceof Number) { - return ((Number) value).byteValue(); - } else if (value instanceof Boolean) { - return BooleanUtil.toByte((Boolean) value); - } - final String valueStr = convertToStr(value); - if (StrUtil.isBlank(valueStr)) { - return 0; - } - return Byte.parseByte(valueStr); - - } else if (short.class == this.targetType) { - if (value instanceof Number) { - return ((Number) value).shortValue(); - } else if (value instanceof Boolean) { - return BooleanUtil.toShort((Boolean) value); - } - final String valueStr = convertToStr(value); - if (StrUtil.isBlank(valueStr)) { - return 0; - } - return Short.parseShort(valueStr); - - } else if (int.class == this.targetType) { - if (value instanceof Number) { - return ((Number) value).intValue(); - } else if (value instanceof Boolean) { - return BooleanUtil.toInt((Boolean) value); - } else if (value instanceof Date) { - return ((Date) value).getTime(); - } else if (value instanceof Calendar) { - return ((Calendar) value).getTimeInMillis(); - } else if (value instanceof TemporalAccessor) { - return DateUtil.toInstant((TemporalAccessor) value).toEpochMilli(); - } - - final String valueStr = convertToStr(value); - if (StrUtil.isBlank(valueStr)) { - return 0; - } - return NumberUtil.parseInt(valueStr); - - } else if (long.class == this.targetType) { - if (value instanceof Number) { - return ((Number) value).longValue(); - } else if (value instanceof Boolean) { - return BooleanUtil.toLong((Boolean) value); - } else if (value instanceof Date) { - return ((Date) value).getTime(); - } else if (value instanceof Calendar) { - return ((Calendar) value).getTimeInMillis(); - } else if (value instanceof TemporalAccessor) { - return DateUtil.toInstant((TemporalAccessor) value).toEpochMilli(); - } - - final String valueStr = convertToStr(value); - if (StrUtil.isBlank(valueStr)) { - return 0; - } - return NumberUtil.parseLong(valueStr); - - } else if (float.class == this.targetType) { - if (value instanceof Number) { - return ((Number) value).floatValue(); - } else if (value instanceof Boolean) { - return BooleanUtil.toFloat((Boolean) value); - } - final String valueStr = convertToStr(value); - if (StrUtil.isBlank(valueStr)) { - return 0; - } - return Float.parseFloat(valueStr); - - } else if (double.class == this.targetType) { - if (value instanceof Number) { - return ((Number) value).doubleValue(); - } else if (value instanceof Boolean) { - return BooleanUtil.toDouble((Boolean) value); - } - final String valueStr = convertToStr(value); - if (StrUtil.isBlank(valueStr)) { - return 0; - } - return Double.parseDouble(valueStr); - - } else if (char.class == this.targetType) { - if (value instanceof Character) { - //noinspection UnnecessaryUnboxing - return ((Character) value).charValue(); - } else if (value instanceof Boolean) { - return BooleanUtil.toChar((Boolean) value); - } - final String valueStr = convertToStr(value); - if (StrUtil.isBlank(valueStr)) { - return 0; - } - return valueStr.charAt(0); - } else if (boolean.class == this.targetType) { - if (value instanceof Boolean) { - //noinspection UnnecessaryUnboxing - return ((Boolean) value).booleanValue(); - } - final String valueStr = convertToStr(value); - return BooleanUtil.toBoolean(valueStr); - } - - throw new ConvertException("Unsupported target type: {}", this.targetType); + return PrimitiveConverter.convert(value, this.targetType, this::convertToStr); } @Override @@ -169,4 +59,34 @@ public class PrimitiveConverter extends AbstractConverter { public Class getTargetType() { return (Class) this.targetType; } + + /** + * 将指定值转换为原始类型的值 + * @param value 值 + * @param primitiveClass 原始类型 + * @param toStringFunc 当无法直接转换时,转为字符串后再转换的函数 + * @return 转换结果 + * @since 5.5.0 + */ + protected static Object convert(Object value, Class primitiveClass, Function toStringFunc) { + if (byte.class == primitiveClass) { + return ObjectUtil.defaultIfNull(NumberConverter.convert(value, Byte.class, toStringFunc), 0); + } else if (short.class == primitiveClass) { + return ObjectUtil.defaultIfNull(NumberConverter.convert(value, Short.class, toStringFunc), 0); + } else if (int.class == primitiveClass) { + return ObjectUtil.defaultIfNull(NumberConverter.convert(value, Integer.class, toStringFunc), 0); + } else if (long.class == primitiveClass) { + return ObjectUtil.defaultIfNull(NumberConverter.convert(value, Long.class, toStringFunc), 0); + } else if (float.class == primitiveClass) { + return ObjectUtil.defaultIfNull(NumberConverter.convert(value, Float.class, toStringFunc), 0); + } else if (double.class == primitiveClass) { + return ObjectUtil.defaultIfNull(NumberConverter.convert(value, Double.class, toStringFunc), 0); + } else if (char.class == primitiveClass) { + return Convert.convert(Character.class, value); + } else if (boolean.class == primitiveClass) { + return Convert.convert(Boolean.class, value); + } + + throw new ConvertException("Unsupported target type: {}", primitiveClass); + } } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java index 891a41ca6..6ddb37c70 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java @@ -4019,7 +4019,7 @@ public class StrUtil { return str.toString().lastIndexOf(searchStr.toString(), fromIndex); } - for (int i = fromIndex; i > 0; i--) { + for (int i = fromIndex; i >= 0; i--) { if (isSubEquals(str, i, searchStr, 0, searchStr.length(), true)) { return i; } diff --git a/hutool-core/src/test/java/cn/hutool/core/bean/BeanUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/bean/BeanUtilTest.java index 56ec38dac..fa7a0aead 100644 --- a/hutool-core/src/test/java/cn/hutool/core/bean/BeanUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/bean/BeanUtilTest.java @@ -4,6 +4,7 @@ import cn.hutool.core.annotation.Alias; import cn.hutool.core.bean.copier.CopyOptions; import cn.hutool.core.bean.copier.ValueProvider; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Console; import cn.hutool.core.map.MapUtil; import lombok.Data; import lombok.Getter; diff --git a/hutool-core/src/test/java/cn/hutool/core/convert/ConvertTest.java b/hutool-core/src/test/java/cn/hutool/core/convert/ConvertTest.java index c55dcf783..0f076f9d0 100644 --- a/hutool-core/src/test/java/cn/hutool/core/convert/ConvertTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/convert/ConvertTest.java @@ -2,6 +2,7 @@ package cn.hutool.core.convert; import lombok.AllArgsConstructor; import lombok.Data; +import lombok.Getter; import org.junit.Assert; import org.junit.Test; @@ -253,4 +254,28 @@ public class ConvertTest { private String cName; private String version; } + + @Test + public void enumToIntTest(){ + final Integer integer = Convert.toInt(BuildingType.CUO); + Assert.assertEquals(1, integer.intValue()); + } + + @Getter + public enum BuildingType { + PING(1, "平层"), + CUO(2, "错层"), + YUE(3, "跃层"), + FUSHI(4, "复式"), + KAIJIAN(5, "开间"), + OTHER(6, "其他"); + + private final int id; + private final String name; + + BuildingType(int id, String name){ + this.id = id; + this.name = name; + } + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java index 260238a6c..3479a5d8a 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java @@ -164,6 +164,7 @@ public class StrUtilTest { Assert.assertEquals(-1, StrUtil.lastIndexOfIgnoreCase("aabaabaa", "B", -1)); Assert.assertEquals(2, StrUtil.lastIndexOfIgnoreCase("aabaabaa", "", 2)); Assert.assertEquals(3, StrUtil.lastIndexOfIgnoreCase("abc", "", 9)); + Assert.assertEquals(0, StrUtil.lastIndexOfIgnoreCase("AAAcsd", "aaa")); } @Test