Browse Source

fix convert

Looly 5 years ago
parent
commit
c646ba04ef

+ 3 - 1
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)
 
 -------------------------------------------------------------------------------------------------------------
 

+ 46 - 29
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;
 
 /**
  * 数字转换器<br>
@@ -54,17 +55,31 @@ public class NumberConverter extends AbstractConverter<Number> {
 
 	@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<Object, String> 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<Number> {
 			} 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<Number> {
 			} 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<Number> {
 			} 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<Number> {
 			} 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<Number> {
 			} 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<Number> {
 	 * 如果给定的值为空,或者转换失败,返回默认值<br>
 	 * 转换失败不会报错
 	 *
-	 * @param value 被转换的值
+	 * @param value     被转换的值
+	 * @param toStrFunc 转换为字符串的函数规则
 	 * @return 结果
 	 */
-	private BigDecimal toBigDecimal(Object value) {
+	private static BigDecimal toBigDecimal(Object value, Function<Object, String> toStrFunc) {
 		if (value instanceof Number) {
 			return NumberUtil.toBigDecimal((Number) value);
 		} else if (value instanceof Boolean) {
@@ -182,7 +198,7 @@ public class NumberConverter extends AbstractConverter<Number> {
 		}
 
 		//对于Double类型,先要转换为String,避免精度问题
-		return NumberUtil.toBigDecimal(convertToStr(value));
+		return NumberUtil.toBigDecimal(toStrFunc.apply(value));
 	}
 
 	/**
@@ -190,25 +206,26 @@ public class NumberConverter extends AbstractConverter<Number> {
 	 * 如果给定的值为空,或者转换失败,返回默认值<br>
 	 * 转换失败不会报错
 	 *
-	 * @param value 被转换的值
+	 * @param value     被转换的值
+	 * @param toStrFunc 转换为字符串的函数规则
 	 * @return 结果
 	 */
-	private BigInteger toBigInteger(Object value) {
+	private static BigInteger toBigInteger(Object value, Function<Object, String> 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);
 			}

+ 34 - 114
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;
 
 /**
  * 原始类型转换器<br>
@@ -49,114 +46,7 @@ public class PrimitiveConverter extends AbstractConverter<Object> {
 
 	@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<Object> {
 	public Class<Object> getTargetType() {
 		return (Class<Object>) this.targetType;
 	}
+
+	/**
+	 * 将指定值转换为原始类型的值
+	 * @param value 值
+	 * @param primitiveClass 原始类型
+	 * @param toStringFunc 当无法直接转换时,转为字符串后再转换的函数
+	 * @return 转换结果
+	 * @since 5.5.0
+	 */
+	protected static Object convert(Object value, Class<?> primitiveClass, Function<Object, String> 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);
+	}
 }

+ 1 - 1
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;
 			}

+ 1 - 0
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;

+ 25 - 0
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;
+		}
+	}
 }

+ 1 - 0
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