diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b942835d..3d30a07b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ### 🐣新特性 ### 🐞Bug修复 * 【core 】 LineReadWatcher#onModify文件清空判断问题(issue#2013@Github) +* 【core 】 修复4位bytes转换float问题(issue#I4M0E4@Github) ------------------------------------------------------------------------------------------------------------- # 5.7.17 (2021-12-09) 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 25d05fe8c..36242cab9 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 @@ -54,13 +54,40 @@ public class NumberConverter extends AbstractConverter { this.targetType = (null == clazz) ? Number.class : clazz; } + @Override + @SuppressWarnings("unchecked") + public Class getTargetType() { + return (Class) this.targetType; + } + @Override protected Number convertInternal(Object value) { return convert(value, this.targetType, this::convertToStr); } + @Override + protected String convertToStr(Object value) { + String result = StrUtil.trim(super.convertToStr(value)); + if (StrUtil.isNotEmpty(result)) { + final char c = Character.toUpperCase(result.charAt(result.length() - 1)); + if (c == 'D' || c == 'L' || c == 'F') { + // 类型标识形式(例如123.6D) + return StrUtil.subPre(result, -1); + } + } + + return result; + } + /** - * 转换对象为数字 + * 转换对象为数字,支持的对象包括: + *
    + *
  • Number对象
  • + *
  • Boolean
  • + *
  • byte[]
  • + *
  • String
  • + *
+ * * * @param value 对象值 * @param targetType 目标的数字类型 @@ -68,12 +95,17 @@ public class NumberConverter extends AbstractConverter { * @return 转换后的数字 * @since 5.5.0 */ - protected static Number convert(Object value, Class targetType, Function toStrFunc) { + protected static Number convert(Object value, Class targetType, Function toStrFunc) { // 枚举转换为数字默认为其顺序 if (value instanceof Enum) { return convert(((Enum) value).ordinal(), targetType, toStrFunc); } + // since 5.7.18 + if(value instanceof byte[]){ + return ByteUtil.bytesToNumber((byte[])value, targetType, ByteUtil.DEFAULT_ORDER); + } + if (Byte.class == targetType) { if (value instanceof Number) { return ((Number) value).byteValue(); @@ -91,8 +123,6 @@ public class NumberConverter extends AbstractConverter { return ((Number) value).shortValue(); } else if (value instanceof Boolean) { return BooleanUtil.toShortObj((Boolean) value); - } else if (value instanceof byte[]){ - return ByteUtil.bytesToShort((byte[]) value); } final String valueStr = toStrFunc.apply((value)); try{ @@ -111,17 +141,13 @@ public class NumberConverter extends AbstractConverter { return (int) ((Calendar) value).getTimeInMillis(); } else if (value instanceof TemporalAccessor) { return (int) DateUtil.toInstant((TemporalAccessor) value).toEpochMilli(); - } else if (value instanceof byte[]){ - return ByteUtil.bytesToInt((byte[]) value); } final String valueStr = toStrFunc.apply((value)); return StrUtil.isBlank(valueStr) ? null : NumberUtil.parseInt(valueStr); } else if (AtomicInteger.class == targetType) { final Number number = convert(value, Integer.class, toStrFunc); if (null != number) { - final AtomicInteger intValue = new AtomicInteger(); - intValue.set(number.intValue()); - return intValue; + return new AtomicInteger(number.intValue()); } } else if (Long.class == targetType) { if (value instanceof Number) { @@ -134,17 +160,13 @@ public class NumberConverter extends AbstractConverter { return ((Calendar) value).getTimeInMillis(); } else if (value instanceof TemporalAccessor) { return DateUtil.toInstant((TemporalAccessor) value).toEpochMilli(); - }else if (value instanceof byte[]){ - return ByteUtil.bytesToLong((byte[]) value); } final String valueStr = toStrFunc.apply((value)); return StrUtil.isBlank(valueStr) ? null : NumberUtil.parseLong(valueStr); } else if (AtomicLong.class == targetType) { final Number number = convert(value, Long.class, toStrFunc); if (null != number) { - final AtomicLong longValue = new AtomicLong(); - longValue.set(number.longValue()); - return longValue; + return new AtomicLong(number.longValue()); } } else if (LongAdder.class == targetType) { //jdk8 新增 @@ -159,8 +181,6 @@ public class NumberConverter extends AbstractConverter { return ((Number) value).floatValue(); } else if (value instanceof Boolean) { return BooleanUtil.toFloatObj((Boolean) value); - } else if (value instanceof byte[]){ - return (float)ByteUtil.bytesToDouble((byte[]) value); } final String valueStr = toStrFunc.apply((value)); return StrUtil.isBlank(valueStr) ? null : NumberUtil.parseFloat(valueStr); @@ -169,8 +189,6 @@ public class NumberConverter extends AbstractConverter { return ((Number) value).doubleValue(); } else if (value instanceof Boolean) { return BooleanUtil.toDoubleObj((Boolean) value); - } else if (value instanceof byte[]){ - return ByteUtil.bytesToDouble((byte[]) value); } final String valueStr = toStrFunc.apply((value)); return StrUtil.isBlank(valueStr) ? null : NumberUtil.parseDouble(valueStr); @@ -212,9 +230,7 @@ public class NumberConverter extends AbstractConverter { if (value instanceof Number) { return NumberUtil.toBigDecimal((Number) value); } else if (value instanceof Boolean) { - return new BigDecimal((boolean) value ? 1 : 0); - } else if (value instanceof byte[]){ - return NumberUtil.toBigDecimal(ByteUtil.bytesToDouble((byte[]) value)); + return ((boolean) value) ? BigDecimal.ONE : BigDecimal.ZERO; } //对于Double类型,先要转换为String,避免精度问题 @@ -234,31 +250,9 @@ public class NumberConverter extends AbstractConverter { if (value instanceof Long) { return BigInteger.valueOf((Long) value); } else if (value instanceof Boolean) { - return BigInteger.valueOf((boolean) value ? 1 : 0); - } else if (value instanceof byte[]){ - return BigInteger.valueOf(ByteUtil.bytesToLong((byte[]) value)); + return (boolean) value ? BigInteger.ONE : BigInteger.ZERO; } return NumberUtil.toBigInteger(toStrFunc.apply(value)); } - - @Override - protected String convertToStr(Object value) { - String result = StrUtil.trim(super.convertToStr(value)); - if (StrUtil.isNotEmpty(result)) { - final char c = Character.toUpperCase(result.charAt(result.length() - 1)); - if (c == 'D' || c == 'L' || c == 'F') { - // 类型标识形式(例如123.6D) - return StrUtil.subPre(result, -1); - } - } - - return result; - } - - @Override - @SuppressWarnings("unchecked") - public Class getTargetType() { - return (Class) this.targetType; - } } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ByteUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ByteUtil.java index 8002704bb..f20d26914 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/ByteUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ByteUtil.java @@ -1,6 +1,12 @@ package cn.hutool.core.util; +import java.math.BigDecimal; +import java.math.BigInteger; import java.nio.ByteOrder; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.DoubleAdder; +import java.util.concurrent.atomic.LongAdder; /** * 对数字和字节进行转换。
@@ -21,6 +27,8 @@ import java.nio.ByteOrder; */ public class ByteUtil { + public static ByteOrder DEFAULT_ORDER = ByteOrder.LITTLE_ENDIAN; + /** * int转byte * @@ -51,14 +59,14 @@ public class ByteUtil { * @return short值 */ public static short bytesToShort(byte[] bytes) { - return bytesToShort(bytes, ByteOrder.LITTLE_ENDIAN); + return bytesToShort(bytes, DEFAULT_ORDER); } /** * byte数组转short
* 自定义端序 * - * @param bytes byte数组 + * @param bytes byte数组,长度必须为2 * @param byteOrder 端序 * @return short值 */ @@ -79,7 +87,7 @@ public class ByteUtil { * @return byte数组 */ public static byte[] shortToBytes(short shortValue) { - return shortToBytes(shortValue, ByteOrder.LITTLE_ENDIAN); + return shortToBytes(shortValue, DEFAULT_ORDER); } /** @@ -110,7 +118,7 @@ public class ByteUtil { * @return int值 */ public static int bytesToInt(byte[] bytes) { - return bytesToInt(bytes, ByteOrder.LITTLE_ENDIAN); + return bytesToInt(bytes, DEFAULT_ORDER); } /** @@ -144,7 +152,7 @@ public class ByteUtil { * @return byte数组 */ public static byte[] intToBytes(int intValue) { - return intToBytes(intValue, ByteOrder.LITTLE_ENDIAN); + return intToBytes(intValue, DEFAULT_ORDER); } /** @@ -185,7 +193,7 @@ public class ByteUtil { * @return byte数组 */ public static byte[] longToBytes(long longValue) { - return longToBytes(longValue, ByteOrder.LITTLE_ENDIAN); + return longToBytes(longValue, DEFAULT_ORDER); } /** @@ -222,7 +230,7 @@ public class ByteUtil { * @return long值 */ public static long bytesToLong(byte[] bytes) { - return bytesToLong(bytes, ByteOrder.LITTLE_ENDIAN); + return bytesToLong(bytes, DEFAULT_ORDER); } /** @@ -251,6 +259,54 @@ public class ByteUtil { return values; } + /** + * float转byte数组,默认以小端序转换
+ * + * @param floatValue float值 + * @return byte数组 + * @since 5.7.18 + */ + public static byte[] floatToBytes(float floatValue) { + return floatToBytes(floatValue, DEFAULT_ORDER); + } + + /** + * float转byte数组,自定义端序
+ * + * @param floatValue float值 + * @param byteOrder 端序 + * @return byte数组 + * @since 5.7.18 + */ + public static byte[] floatToBytes(float floatValue, ByteOrder byteOrder) { + return intToBytes(Float.floatToIntBits(floatValue), byteOrder); + } + + /** + * byte数组转float
+ * 默认以小端序转换
+ * + * @param bytes byte数组 + * @return float值 + * @since 5.7.18 + */ + public static double bytesToFloat(byte[] bytes) { + return bytesToFloat(bytes, DEFAULT_ORDER); + } + + /** + * byte数组转float
+ * 自定义端序
+ * + * @param bytes byte数组 + * @param byteOrder 端序 + * @return float值 + * @since 5.7.18 + */ + public static float bytesToFloat(byte[] bytes, ByteOrder byteOrder) { + return Float.intBitsToFloat(bytesToInt(bytes, byteOrder)); + } + /** * double转byte数组
* 默认以小端序转换
@@ -259,7 +315,7 @@ public class ByteUtil { * @return byte数组 */ public static byte[] doubleToBytes(double doubleValue) { - return doubleToBytes(doubleValue, ByteOrder.LITTLE_ENDIAN); + return doubleToBytes(doubleValue, DEFAULT_ORDER); } /** @@ -283,7 +339,7 @@ public class ByteUtil { * @return long值 */ public static double bytesToDouble(byte[] bytes) { - return bytesToDouble(bytes, ByteOrder.LITTLE_ENDIAN); + return bytesToDouble(bytes, DEFAULT_ORDER); } /** @@ -305,7 +361,7 @@ public class ByteUtil { * @return bytes */ public static byte[] numberToBytes(Number number) { - return numberToBytes(number, ByteOrder.LITTLE_ENDIAN); + return numberToBytes(number, DEFAULT_ORDER); } /** @@ -324,8 +380,62 @@ public class ByteUtil { return intToBytes((Integer) number, byteOrder); } else if (number instanceof Short) { return shortToBytes((Short) number, byteOrder); + } else if (number instanceof Float) { + return floatToBytes((Float) number, byteOrder); } else { return doubleToBytes(number.doubleValue(), byteOrder); } } + + /** + * byte数组转换为指定类型数字 + * + * @param 数字类型 + * @param bytes byte数组 + * @param targetClass 目标数字类型 + * @param byteOrder 端序 + * @return 转换后的数字 + * @throws IllegalArgumentException 不支持的数字类型,如用户自定义数字类型 + */ + @SuppressWarnings("unchecked") + public static T bytesToNumber(byte[] bytes, Class targetClass, ByteOrder byteOrder) throws IllegalArgumentException { + Number number; + if (Byte.class == targetClass) { + number = bytes[0]; + } else if (Short.class == targetClass) { + number = bytesToShort(bytes, byteOrder); + } else if (Integer.class == targetClass) { + number = bytesToInt(bytes, byteOrder); + } else if (AtomicInteger.class == targetClass) { + number = new AtomicInteger(bytesToInt(bytes, byteOrder)); + } else if (Long.class == targetClass) { + number = bytesToLong(bytes, byteOrder); + } else if (AtomicLong.class == targetClass) { + number = new AtomicLong(bytesToLong(bytes, byteOrder)); + } else if (LongAdder.class == targetClass) { + final LongAdder longValue = new LongAdder(); + longValue.add(bytesToLong(bytes, byteOrder)); + number = longValue; + } else if (Float.class == targetClass) { + number = bytesToFloat(bytes, byteOrder); + } else if (Double.class == targetClass) { + number = bytesToDouble(bytes, byteOrder); + } else if (DoubleAdder.class == targetClass) { + final DoubleAdder doubleAdder = new DoubleAdder(); + doubleAdder.add(bytesToDouble(bytes, byteOrder)); + number = doubleAdder; + } else if (BigDecimal.class == targetClass) { + number = NumberUtil.toBigDecimal(bytesToDouble(bytes, byteOrder)); + } else if (BigInteger.class == targetClass) { + number = BigInteger.valueOf(bytesToLong(bytes, byteOrder)); + } else if (Number.class == targetClass) { + // 用户没有明确类型具体类型,默认Double + number = bytesToDouble(bytes, byteOrder); + } else { + // 用户自定义类型不支持 + throw new IllegalArgumentException("Unsupported Number type: " + targetClass.getName()); + } + + return (T) number; + } } 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 beb6b0d4d..d07478cb5 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 @@ -6,6 +6,7 @@ import cn.hutool.core.date.DateUtil; import cn.hutool.core.lang.TypeReference; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ByteUtil; +import cn.hutool.core.util.HexUtil; import lombok.AllArgsConstructor; import lombok.Data; import lombok.Getter; @@ -343,4 +344,13 @@ public class ConvertTest { final BigDecimal bigDecimal = Convert.toBigDecimal(str); Assert.assertEquals(str, bigDecimal.toPlainString()); } + + @Test + public void toFloatTest(){ + // https://gitee.com/dromara/hutool/issues/I4M0E4 + String hex2 = "CD0CCB43"; + final byte[] value = HexUtil.decodeHex(hex2); + final float f = Convert.toFloat(value); + Assert.assertEquals(406.1F, f, 2); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/util/ByteUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/ByteUtilTest.java index b1cf436e5..b68b95ce9 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/ByteUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/ByteUtilTest.java @@ -10,7 +10,7 @@ public class ByteUtilTest { @Test public void intAndBytesLittleEndianTest() { // 测试 int 转小端序 byte 数组 - int int1 = 1417; + int int1 = RandomUtil.randomInt(); byte[] bytesInt = ByteUtil.intToBytes(int1, ByteOrder.LITTLE_ENDIAN); int int2 = ByteUtil.bytesToInt(bytesInt, ByteOrder.LITTLE_ENDIAN); @@ -28,7 +28,7 @@ public class ByteUtilTest { @Test public void intAndBytesBigEndianTest() { // 测试 int 转大端序 byte 数组 - int int2 = 1417; + int int2 = RandomUtil.randomInt(); byte[] bytesInt = ByteUtil.intToBytes(int2, ByteOrder.BIG_ENDIAN); // 测试大端序 byte 数组转 int @@ -65,9 +65,30 @@ public class ByteUtilTest { Assert.assertEquals(long1, long2); } + @Test + public void floatAndBytesLittleEndianTest() { + // 测试 long 转 byte 数组 + float f1 = (float) RandomUtil.randomDouble(); + + byte[] bytesLong = ByteUtil.floatToBytes(f1, ByteOrder.LITTLE_ENDIAN); + float f2 = ByteUtil.bytesToFloat(bytesLong, ByteOrder.LITTLE_ENDIAN); + Assert.assertEquals(f1, f2, 2); + } + + @Test + public void floatAndBytesBigEndianTest() { + // 测试大端序 long 转 byte 数组 + float f1 = (float) RandomUtil.randomDouble(); + + byte[] bytesLong = ByteUtil.floatToBytes(f1, ByteOrder.BIG_ENDIAN); + float f2 = ByteUtil.bytesToFloat(bytesLong, ByteOrder.BIG_ENDIAN); + + Assert.assertEquals(f1, f2, 2); + } + @Test public void shortAndBytesLittleEndianTest() { - short short1 = 122; + short short1 = (short) RandomUtil.randomInt(); byte[] bytes = ByteUtil.shortToBytes(short1, ByteOrder.LITTLE_ENDIAN); short short2 = ByteUtil.bytesToShort(bytes, ByteOrder.LITTLE_ENDIAN);