diff --git a/CHANGELOG.md b/CHANGELOG.md index de4f0537d..b26cbf06b 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------------------------------------- -# 6.0.0.M1 (2022-06-06) +# 6.0.0.M1 (2022-06-07) ### 计划实现 * 【poi 】 PDF相关(基于PdfBox) @@ -12,9 +12,7 @@ * 【core 】 针对JDK8+的日期,统一归档到TimeUtil * 【core 】 CopyOptions参数重构 * 【db 】 增加DDL封装 -* 【json 】 删除JSONNull * 【json 】 实现自定义的类型转换,不影响全局的转换器 -* 【core 】 Converter设计缺陷,需要改造,使用TypeConverter可以更好的兼容细化类型的转换 ### ❌不兼容特性 diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/BeanUtil.java b/hutool-core/src/main/java/cn/hutool/core/bean/BeanUtil.java index ccdb00b65..e55c5a446 100755 --- a/hutool-core/src/main/java/cn/hutool/core/bean/BeanUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/BeanUtil.java @@ -7,6 +7,7 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.SetUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.lang.func.Editor; +import cn.hutool.core.lang.mutable.MutableEntry; import cn.hutool.core.map.CaseInsensitiveMap; import cn.hutool.core.map.MapUtil; import cn.hutool.core.reflect.ClassUtil; @@ -399,7 +400,7 @@ public class BeanUtil { * @return Bean */ public static T fillBeanWithMap(final Map map, final T bean, final boolean isToCamelCase, final boolean isIgnoreError) { - return fillBeanWithMap(map, bean, isToCamelCase, CopyOptions.create().setIgnoreError(isIgnoreError)); + return fillBeanWithMap(map, bean, isToCamelCase, CopyOptions.of().setIgnoreError(isIgnoreError)); } /** @@ -412,7 +413,7 @@ public class BeanUtil { * @return Bean */ public static T fillBeanWithMapIgnoreCase(final Map map, final T bean, final boolean isIgnoreError) { - return fillBeanWithMap(map, bean, CopyOptions.create().setIgnoreCase(true).setIgnoreError(isIgnoreError)); + return fillBeanWithMap(map, bean, CopyOptions.of().setIgnoreCase(true).setIgnoreError(isIgnoreError)); } /** @@ -527,15 +528,19 @@ public class BeanUtil { */ public static Map beanToMap(final Object bean, final String... properties) { int mapSize = 16; - Editor keyEditor = null; + Editor> editor = null; if (ArrayUtil.isNotEmpty(properties)) { mapSize = properties.length; final Set propertiesSet = SetUtil.of(properties); - keyEditor = property -> propertiesSet.contains(property) ? property : null; + editor = entry -> { + final String key = entry.getKey(); + entry.setKey(propertiesSet.contains(key) ? key : null); + return entry; + }; } // 指明了要复制的属性 所以不忽略null值 - return beanToMap(bean, new LinkedHashMap<>(mapSize, 1), false, keyEditor); + return beanToMap(bean, new LinkedHashMap<>(mapSize, 1), false, editor); } /** @@ -568,7 +573,11 @@ public class BeanUtil { return null; } - return beanToMap(bean, targetMap, ignoreNullValue, key -> isToUnderlineCase ? StrUtil.toUnderlineCase(key) : key); + return beanToMap(bean, targetMap, ignoreNullValue, entry -> { + final String key = entry.getKey(); + entry.setKey(isToUnderlineCase ? StrUtil.toUnderlineCase(key) : key); + return entry; + }); } /** @@ -588,15 +597,16 @@ public class BeanUtil { * @return Map * @since 4.0.5 */ - public static Map beanToMap(final Object bean, final Map targetMap, final boolean ignoreNullValue, final Editor keyEditor) { + public static Map beanToMap(final Object bean, final Map targetMap, + final boolean ignoreNullValue, final Editor> keyEditor) { if (null == bean) { return null; } return BeanCopier.create(bean, targetMap, - CopyOptions.create() + CopyOptions.of() .setIgnoreNullValue(ignoreNullValue) - .setFieldNameEditor(keyEditor) + .setFieldEditor(keyEditor) ).copy(); } @@ -642,7 +652,7 @@ public class BeanUtil { return null; } final T target = ConstructorUtil.newInstanceIfPossible(tClass); - copyProperties(source, target, CopyOptions.create().setIgnoreProperties(ignoreProperties)); + copyProperties(source, target, CopyOptions.of().setIgnoreProperties(ignoreProperties)); return target; } @@ -655,7 +665,7 @@ public class BeanUtil { * @param ignoreProperties 不拷贝的的属性列表 */ public static void copyProperties(final Object source, final Object target, final String... ignoreProperties) { - copyProperties(source, target, CopyOptions.create().setIgnoreProperties(ignoreProperties)); + copyProperties(source, target, CopyOptions.of().setIgnoreProperties(ignoreProperties)); } /** @@ -666,7 +676,7 @@ public class BeanUtil { * @param ignoreCase 是否忽略大小写 */ public static void copyProperties(final Object source, final Object target, final boolean ignoreCase) { - BeanCopier.create(source, target, CopyOptions.create().setIgnoreCase(ignoreCase)).copy(); + BeanCopier.create(source, target, CopyOptions.of().setIgnoreCase(ignoreCase)).copy(); } /** @@ -681,7 +691,7 @@ public class BeanUtil { if (null == source || null == target) { return; } - BeanCopier.create(source, target, ObjUtil.defaultIfNull(copyOptions, CopyOptions::create)).copy(); + BeanCopier.create(source, target, ObjUtil.defaultIfNull(copyOptions, CopyOptions::of)).copy(); } /** @@ -720,7 +730,7 @@ public class BeanUtil { * @since 5.6.6 */ public static List copyToList(final Collection collection, final Class targetType) { - return copyToList(collection, targetType, CopyOptions.create()); + return copyToList(collection, targetType, CopyOptions.of()); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/copier/AbsCopier.java b/hutool-core/src/main/java/cn/hutool/core/bean/copier/AbsCopier.java index 673d78c5a..7f6d49215 100755 --- a/hutool-core/src/main/java/cn/hutool/core/bean/copier/AbsCopier.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/copier/AbsCopier.java @@ -23,6 +23,6 @@ public abstract class AbsCopier implements Copier { public AbsCopier(final S source, final T target, final CopyOptions copyOptions) { this.source = source; this.target = target; - this.copyOptions = ObjUtil.defaultIfNull(copyOptions, CopyOptions::create); + this.copyOptions = ObjUtil.defaultIfNull(copyOptions, CopyOptions::of); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanToBeanCopier.java b/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanToBeanCopier.java index 620d5b63d..fe6047cf9 100755 --- a/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanToBeanCopier.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanToBeanCopier.java @@ -3,6 +3,7 @@ package cn.hutool.core.bean.copier; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.PropDesc; import cn.hutool.core.lang.Assert; +import cn.hutool.core.lang.mutable.MutableEntry; import cn.hutool.core.reflect.TypeUtil; import java.lang.reflect.Type; @@ -53,30 +54,36 @@ public class BeanToBeanCopier extends AbsCopier { return; } - sFieldName = copyOptions.editFieldName(sFieldName); + // 检查源对象属性是否过滤属性 + Object sValue = sDesc.getValue(this.source); + if (false == copyOptions.testPropertyFilter(sDesc.getField(), sValue)) { + return; + } + + // 编辑键值对 + final MutableEntry entry = copyOptions.editField(sFieldName, sValue); + if(null == entry){ + return; + } + sFieldName = entry.getKey(); // 对key做转换,转换后为null的跳过 if (null == sFieldName) { return; } + sValue = entry.getValue(); // 检查目标字段可写性 + // 目标字段检查放在键值对编辑之后,因为键可能被编辑修改 final PropDesc tDesc = targetPropDescMap.get(sFieldName); if (null == tDesc || false == tDesc.isWritable(this.copyOptions.transientSupport)) { // 字段不可写,跳过之 return; } - // 检查源对象属性是否过滤属性 - Object sValue = sDesc.getValue(this.source); - if (false == copyOptions.testPropertyFilter(sDesc.getField(), sValue)) { - return; - } - // 获取目标字段真实类型并转换源值 final Type fieldType = TypeUtil.getActualType(this.targetType, tDesc.getFieldType()); //sValue = Convert.convertWithCheck(fieldType, sValue, null, this.copyOptions.ignoreError); sValue = this.copyOptions.convertField(fieldType, sValue); - sValue = copyOptions.editFieldValue(sFieldName, sValue); // 目标赋值 tDesc.setValue(this.target, sValue, copyOptions.ignoreNullValue, copyOptions.ignoreError, copyOptions.override); diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanToMapCopier.java b/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanToMapCopier.java index c49c777f6..72647f8a0 100755 --- a/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanToMapCopier.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanToMapCopier.java @@ -3,6 +3,7 @@ package cn.hutool.core.bean.copier; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.PropDesc; import cn.hutool.core.lang.Assert; +import cn.hutool.core.lang.mutable.MutableEntry; import cn.hutool.core.reflect.TypeUtil; import java.lang.reflect.Type; @@ -52,24 +53,29 @@ public class BeanToMapCopier extends AbsCopier { return; } - sFieldName = copyOptions.editFieldName(sFieldName); - // 对key做转换,转换后为null的跳过 - if (null == sFieldName) { - return; - } - // 检查源对象属性是否过滤属性 Object sValue = sDesc.getValue(this.source); if (false == copyOptions.testPropertyFilter(sDesc.getField(), sValue)) { return; } + // 编辑键值对 + final MutableEntry entry = copyOptions.editField(sFieldName, sValue); + if(null == entry){ + return; + } + sFieldName = entry.getKey(); + // 对key做转换,转换后为null的跳过 + if (null == sFieldName) { + return; + } + sValue = entry.getValue(); + // 获取目标值真实类型并转换源值 final Type[] typeArguments = TypeUtil.getTypeArguments(this.targetType); if(null != typeArguments){ //sValue = Convert.convertWithCheck(typeArguments[1], sValue, null, this.copyOptions.ignoreError); sValue = this.copyOptions.convertField(typeArguments[1], sValue); - sValue = copyOptions.editFieldValue(sFieldName, sValue); } // 目标赋值 diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/copier/CopyOptions.java b/hutool-core/src/main/java/cn/hutool/core/bean/copier/CopyOptions.java index a012ffcc6..d0c3fc874 100755 --- a/hutool-core/src/main/java/cn/hutool/core/bean/copier/CopyOptions.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/copier/CopyOptions.java @@ -1,10 +1,11 @@ package cn.hutool.core.bean.copier; import cn.hutool.core.convert.Convert; -import cn.hutool.core.convert.TypeConverter; +import cn.hutool.core.convert.Converter; import cn.hutool.core.lang.func.Editor; import cn.hutool.core.lang.func.Func1; import cn.hutool.core.lang.func.LambdaUtil; +import cn.hutool.core.lang.mutable.MutableEntry; import cn.hutool.core.util.ArrayUtil; import java.io.Serializable; @@ -12,7 +13,6 @@ import java.lang.reflect.Field; import java.lang.reflect.Type; import java.util.Map; import java.util.Set; -import java.util.function.BiFunction; import java.util.function.BiPredicate; /** @@ -36,11 +36,6 @@ public class CopyOptions implements Serializable { * 是否忽略空值,当源对象的值为null时,true: 忽略而不注入此值,false: 注入null */ protected boolean ignoreNullValue; - /** - * 属性过滤器,断言通过的属性才会被复制
- * 断言参数中Field为源对象的字段对象,如果源对象为Map,使用目标对象,Object为源对象的对应值 - */ - private BiPredicate propertiesFilter; /** * 是否忽略字段注入错误 */ @@ -50,14 +45,16 @@ public class CopyOptions implements Serializable { */ protected boolean ignoreCase; /** - * 字段属性编辑器,用于自定义属性转换规则,例如驼峰转下划线等
- * 规则为,{@link Editor#edit(Object)}属性为源对象的字段名称或key,返回值为目标对象的字段名称或key + * 属性过滤器,断言通过的属性才会被复制
+ * 断言参数中Field为源对象的字段对象,如果源对象为Map,使用目标对象,Object为源对象的对应值 */ - private Editor fieldNameEditor; + private BiPredicate propertiesFilter; + /** - * 字段属性值编辑器,用于自定义属性值转换规则,例如null转""等 + * 字段属性名和属性值编辑器,,用于自定义属性转换规则(例如驼峰转下划线等),自定义属性值转换规则(例如null转""等) */ - protected BiFunction fieldValueEditor; + protected Editor> fieldEditor; + /** * 是否支持transient关键字修饰和@Transient注解,如果支持,被修饰的字段或方法对应的字段将被忽略。 */ @@ -70,7 +67,7 @@ public class CopyOptions implements Serializable { /** * 自定义类型转换器,默认使用全局万能转换器转换 */ - protected TypeConverter converter = (type, value) -> + protected Converter converter = (type, value) -> Convert.convertWithCheck(type, value, null, ignoreError); //region create @@ -80,7 +77,7 @@ public class CopyOptions implements Serializable { * * @return 拷贝选项 */ - public static CopyOptions create() { + public static CopyOptions of() { return new CopyOptions(); } @@ -92,7 +89,7 @@ public class CopyOptions implements Serializable { * @param ignoreProperties 忽略的属性列表,设置一个属性列表,不拷贝这些属性值 * @return 拷贝选项 */ - public static CopyOptions create(final Class editable, final boolean ignoreNullValue, final String... ignoreProperties) { + public static CopyOptions of(final Class editable, final boolean ignoreNullValue, final String... ignoreProperties) { return new CopyOptions(editable, ignoreNullValue, ignoreProperties); } //endregion @@ -235,7 +232,11 @@ public class CopyOptions implements Serializable { * @return CopyOptions */ public CopyOptions setFieldMapping(final Map fieldMapping) { - return setFieldNameEditor((key -> fieldMapping.getOrDefault(key, key))); + return setFieldEditor(entry -> { + final String key = entry.getKey(); + entry.setKey(fieldMapping.getOrDefault(key, key)); + return entry; + }); } /** @@ -243,24 +244,12 @@ public class CopyOptions implements Serializable { * 此转换器只针对源端的字段做转换,请确认转换后与目标端字段一致
* 当转换后的字段名为null时忽略这个字段 * - * @param fieldNameEditor 字段属性编辑器,用于自定义属性转换规则,例如驼峰转下划线等 + * @param editor 字段属性编辑器,用于自定义属性转换规则,例如驼峰转下划线等 * @return CopyOptions * @since 5.4.2 */ - public CopyOptions setFieldNameEditor(final Editor fieldNameEditor) { - this.fieldNameEditor = fieldNameEditor; - return this; - } - - /** - * 设置字段属性值编辑器,用于自定义属性值转换规则,例如null转""等
- * - * @param fieldValueEditor 字段属性值编辑器,用于自定义属性值转换规则,例如null转""等 - * @return CopyOptions - * @since 5.7.15 - */ - public CopyOptions setFieldValueEditor(final BiFunction fieldValueEditor) { - this.fieldValueEditor = fieldValueEditor; + public CopyOptions setFieldEditor(final Editor> editor) { + this.fieldEditor = editor; return this; } @@ -272,9 +261,10 @@ public class CopyOptions implements Serializable { * @return 编辑后的字段值 * @since 5.7.15 */ - protected Object editFieldValue(final String fieldName, final Object fieldValue) { - return (null != this.fieldValueEditor) ? - this.fieldValueEditor.apply(fieldName, fieldValue) : fieldValue; + protected MutableEntry editField(final String fieldName, final Object fieldValue) { + final MutableEntry entry = new MutableEntry<>(fieldName, fieldValue); + return (null != this.fieldEditor) ? + this.fieldEditor.edit(entry) : entry; } /** @@ -308,7 +298,7 @@ public class CopyOptions implements Serializable { * @return this * @since 5.8.0 */ - public CopyOptions setConverter(final TypeConverter converter) { + public CopyOptions setConverter(final Converter converter) { this.converter = converter; return this; } @@ -327,17 +317,6 @@ public class CopyOptions implements Serializable { this.converter.convert(targetType, fieldValue) : fieldValue; } - /** - * 转换字段名为编辑后的字段名 - * - * @param fieldName 字段名 - * @return 编辑后的字段名 - * @since 5.4.2 - */ - protected String editFieldName(final String fieldName) { - return (null != this.fieldNameEditor) ? this.fieldNameEditor.edit(fieldName) : fieldName; - } - /** * 测试是否保留字段,{@code true}保留,{@code false}不保留 * diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/copier/MapToBeanCopier.java b/hutool-core/src/main/java/cn/hutool/core/bean/copier/MapToBeanCopier.java index 574589468..c1333de48 100755 --- a/hutool-core/src/main/java/cn/hutool/core/bean/copier/MapToBeanCopier.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/copier/MapToBeanCopier.java @@ -3,6 +3,7 @@ package cn.hutool.core.bean.copier; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.PropDesc; import cn.hutool.core.lang.Assert; +import cn.hutool.core.lang.mutable.MutableEntry; import cn.hutool.core.map.CaseInsensitiveMap; import cn.hutool.core.map.MapWrapper; import cn.hutool.core.text.StrUtil; @@ -61,30 +62,35 @@ public class MapToBeanCopier extends AbsCopier, T> { if (null == sKey) { return; } - String sKeyStr = copyOptions.editFieldName(sKey.toString()); + + // 编辑键值对 + final MutableEntry entry = copyOptions.editField(sKey.toString(), sValue); + if(null == entry){ + return; + } + String sFieldName = entry.getKey(); // 对key做转换,转换后为null的跳过 - if (null == sKeyStr) { + if (null == sFieldName) { return; } // 检查目标字段可写性 - final PropDesc tDesc = findPropDesc(targetPropDescMap, sKeyStr); + // 目标字段检查放在键值对编辑之后,因为键可能被编辑修改 + final PropDesc tDesc = findPropDesc(targetPropDescMap, sFieldName); if (null == tDesc || false == tDesc.isWritable(this.copyOptions.transientSupport)) { // 字段不可写,跳过之 return; } - sKeyStr = tDesc.getFieldName(); + Object newValue = entry.getValue(); // 检查目标是否过滤属性 - if (false == copyOptions.testPropertyFilter(tDesc.getField(), sValue)) { + if (false == copyOptions.testPropertyFilter(tDesc.getField(), newValue)) { return; } // 获取目标字段真实类型并转换源值 final Type fieldType = TypeUtil.getActualType(this.targetType, tDesc.getFieldType()); - //Object newValue = Convert.convertWithCheck(fieldType, sValue, null, this.copyOptions.ignoreError); - Object newValue = this.copyOptions.convertField(fieldType, sValue); - newValue = copyOptions.editFieldValue(sKeyStr, newValue); + newValue = this.copyOptions.convertField(fieldType, newValue); // 目标赋值 tDesc.setValue(this.target, newValue, copyOptions.ignoreNullValue, copyOptions.ignoreError, copyOptions.override); diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/copier/MapToMapCopier.java b/hutool-core/src/main/java/cn/hutool/core/bean/copier/MapToMapCopier.java index a9cb20944..f0457a0e0 100755 --- a/hutool-core/src/main/java/cn/hutool/core/bean/copier/MapToMapCopier.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/copier/MapToMapCopier.java @@ -1,5 +1,6 @@ package cn.hutool.core.bean.copier; +import cn.hutool.core.lang.mutable.MutableEntry; import cn.hutool.core.reflect.TypeUtil; import java.lang.reflect.Type; @@ -37,13 +38,20 @@ public class MapToMapCopier extends AbsCopier { if (null == sKey) { return; } - final String sKeyStr = copyOptions.editFieldName(sKey.toString()); - // 对key做转换,转换后为null的跳过 - if (null == sKeyStr) { + + // 编辑键值对 + final MutableEntry entry = copyOptions.editField(sKey.toString(), sValue); + if(null == entry){ return; } + sKey = entry.getKey(); + // 对key做转换,转换后为null的跳过 + if (null == sKey) { + return; + } + sValue = entry.getValue(); - final Object targetValue = target.get(sKeyStr); + final Object targetValue = target.get(sKey); // 非覆盖模式下,如果目标值存在,则跳过 if (false == copyOptions.override && null != targetValue) { return; @@ -52,13 +60,11 @@ public class MapToMapCopier extends AbsCopier { // 获取目标值真实类型并转换源值 final Type[] typeArguments = TypeUtil.getTypeArguments(this.targetType); if(null != typeArguments){ - //sValue = Convert.convertWithCheck(typeArguments[1], sValue, null, this.copyOptions.ignoreError); sValue = this.copyOptions.convertField(typeArguments[1], sValue); - sValue = copyOptions.editFieldValue(sKeyStr, sValue); } // 目标赋值 - target.put(sKeyStr, sValue); + target.put(sKey, sValue); }); return this.target; } diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/copier/ValueProviderToBeanCopier.java b/hutool-core/src/main/java/cn/hutool/core/bean/copier/ValueProviderToBeanCopier.java index 0277d2dc7..02ae48fcb 100755 --- a/hutool-core/src/main/java/cn/hutool/core/bean/copier/ValueProviderToBeanCopier.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/copier/ValueProviderToBeanCopier.java @@ -3,6 +3,7 @@ package cn.hutool.core.bean.copier; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.PropDesc; import cn.hutool.core.lang.Assert; +import cn.hutool.core.lang.mutable.MutableEntry; import cn.hutool.core.reflect.TypeUtil; import java.lang.reflect.Type; @@ -63,13 +64,23 @@ public class ValueProviderToBeanCopier extends AbsCopier entry = copyOptions.editField(tFieldName, sValue); + if(null == entry){ + return; + } + tFieldName = entry.getKey(); + // 对key做转换,转换后为null的跳过 + if (null == tFieldName) { + return; + } + sValue = entry.getValue(); // 检查目标对象属性是否过滤属性 - Object sValue = source.value(tFieldName, fieldType); if (false == copyOptions.testPropertyFilter(tDesc.getField(), sValue)) { return; } - sValue = copyOptions.editFieldValue(tFieldName, sValue); // 目标赋值 tDesc.setValue(this.target, sValue, copyOptions.ignoreNullValue, copyOptions.ignoreError, copyOptions.override); diff --git a/hutool-core/src/main/java/cn/hutool/core/classloader/ClassLoaderUtil.java b/hutool-core/src/main/java/cn/hutool/core/classloader/ClassLoaderUtil.java index c42529bc4..1e9437272 100644 --- a/hutool-core/src/main/java/cn/hutool/core/classloader/ClassLoaderUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/classloader/ClassLoaderUtil.java @@ -140,7 +140,7 @@ public class ClassLoaderUtil { * 3、内部类,例如:java.lang.Thread.State会被转为java.lang.Thread$State加载 * * - * @param 目标类的类型 + * @param 目标类的类型 * @param name 类名 * @return 类名对应的类 * @throws UtilException 包装{@link ClassNotFoundException},没有类名对应的类时抛出此异常 @@ -159,7 +159,7 @@ public class ClassLoaderUtil { * 3、内部类,例如:java.lang.Thread.State会被转为java.lang.Thread$State加载 * * - * @param 目标类的类型 + * @param 目标类的类型 * @param name 类名 * @param isInitialized 是否初始化类(调用static模块内容和初始化static属性) * @return 类名对应的类 @@ -181,6 +181,7 @@ public class ClassLoaderUtil { * 3、内部类,例如:java.lang.Thread.State会被转为java.lang.Thread$State加载 * * + * @param 加载的类的类型 * @param name 类名 * @param classLoader {@link ClassLoader},{@code null} 则使用{@link #getClassLoader()}获取 * @param isInitialized 是否初始化类(调用static模块内容和初始化static属性) @@ -193,7 +194,7 @@ public class ClassLoaderUtil { // 自动将包名中的"/"替换为"." name = name.replace(CharPool.SLASH, CharPool.DOT); - if(null == classLoader){ + if (null == classLoader) { classLoader = getClassLoader(); } @@ -202,7 +203,7 @@ public class ClassLoaderUtil { if (clazz == null) { final String finalName = name; final ClassLoader finalClassLoader = classLoader; - clazz = CLASS_CACHE.computeIfAbsent(MapUtil.entry(name, classLoader), (key)-> doLoadClass(finalName, finalClassLoader, isInitialized)); + clazz = CLASS_CACHE.computeIfAbsent(MapUtil.entry(name, classLoader), (key) -> doLoadClass(finalName, finalClassLoader, isInitialized)); } return (Class) clazz; } @@ -284,14 +285,16 @@ public class ClassLoaderUtil { } // ----------------------------------------------------------------------------------- Private method start + /** * 加载非原始类类,无缓存 - * @param name 类名 - * @param classLoader {@link ClassLoader} + * + * @param name 类名 + * @param classLoader {@link ClassLoader} * @param isInitialized 是否初始化 * @return 类 */ - private static Class doLoadClass(final String name, ClassLoader classLoader, final boolean isInitialized){ + private static Class doLoadClass(final String name, ClassLoader classLoader, final boolean isInitialized) { Class clazz; if (name.endsWith(ARRAY_SUFFIX)) { // 对象数组"java.lang.String[]"风格 diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java b/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java index b5bfc2cb2..aafcdcd63 100755 --- a/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java @@ -750,10 +750,11 @@ public class CollUtil { * 根据函数生成的KEY去重集合,如根据Bean的某个或者某些字段完成去重。
* 去重可选是保留最先加入的值还是后加入的值 * - * @param 集合元素类型 - * @param 唯一键类型 - * @param collection 集合 - * @param override 是否覆盖模式,如果为{@code true},加入的新值会覆盖相同key的旧值,否则会忽略新加值 + * @param 集合元素类型 + * @param 唯一键类型 + * @param collection 集合 + * @param uniqueGenerator 唯一键生成器 + * @param override 是否覆盖模式,如果为{@code true},加入的新值会覆盖相同key的旧值,否则会忽略新加值 * @return {@link ArrayList} * @since 5.8.0 */ diff --git a/hutool-core/src/main/java/cn/hutool/core/comparator/CompareUtil.java b/hutool-core/src/main/java/cn/hutool/core/comparator/CompareUtil.java index 520a9a4bf..945045668 100644 --- a/hutool-core/src/main/java/cn/hutool/core/comparator/CompareUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/comparator/CompareUtil.java @@ -11,6 +11,86 @@ import java.util.function.Function; */ public class CompareUtil { + // ------------------------------------------------------------------------------------------- compare + + /** + * 比较两个值的大小 + * + * @param x 第一个值 + * @param y 第二个值 + * @return x==y返回0,x<y返回小于0的数,x>y返回大于0的数 + * @see Character#compare(char, char) + * @since 3.0.1 + */ + public static int compare(final char x, final char y) { + return Character.compare(x, y); + } + + /** + * 比较两个值的大小 + * + * @param x 第一个值 + * @param y 第二个值 + * @return x==y返回0,x<y返回小于0的数,x>y返回大于0的数 + * @see Double#compare(double, double) + * @since 3.0.1 + */ + public static int compare(final double x, final double y) { + return Double.compare(x, y); + } + + /** + * 比较两个值的大小 + * + * @param x 第一个值 + * @param y 第二个值 + * @return x==y返回0,x<y返回小于0的数,x>y返回大于0的数 + * @see Integer#compare(int, int) + * @since 3.0.1 + */ + public static int compare(final int x, final int y) { + return Integer.compare(x, y); + } + + /** + * 比较两个值的大小 + * + * @param x 第一个值 + * @param y 第二个值 + * @return x==y返回0,x<y返回小于0的数,x>y返回大于0的数 + * @see Long#compare(long, long) + * @since 3.0.1 + */ + public static int compare(final long x, final long y) { + return Long.compare(x, y); + } + + /** + * 比较两个值的大小 + * + * @param x 第一个值 + * @param y 第二个值 + * @return x==y返回0,x<y返回小于0的数,x>y返回大于0的数 + * @see Short#compare(short, short) + * @since 3.0.1 + */ + public static int compare(final short x, final short y) { + return Short.compare(x, y); + } + + /** + * 比较两个值的大小 + * + * @param x 第一个值 + * @param y 第二个值 + * @return x==y返回0,x<y返回-1,x>y返回1 + * @see Byte#compare(byte, byte) + * @since 3.0.1 + */ + public static int compare(final byte x, final byte y) { + return Byte.compare(x, y); + } + /** * 获取自然排序器,即默认排序器 * diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/AbstractConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/AbstractConverter.java index c66d4f247..39e80f59a 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/AbstractConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/AbstractConverter.java @@ -1,11 +1,12 @@ package cn.hutool.core.convert; -import cn.hutool.core.reflect.ClassUtil; -import cn.hutool.core.text.StrUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.reflect.TypeUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.CharUtil; import java.io.Serializable; +import java.lang.reflect.Type; import java.util.Map; /** @@ -13,58 +14,30 @@ import java.util.Map; * 转换器不会抛出转换异常,转换失败时会返回{@code null} * * @author Looly - * */ -public abstract class AbstractConverter implements Converter, Serializable { +public abstract class AbstractConverter implements Converter, Serializable { private static final long serialVersionUID = 1L; - /** - * 不抛异常转换
- * 当转换失败时返回默认值 - * - * @param value 被转换的值 - * @param defaultValue 默认值 - * @return 转换后的值 - * @since 4.5.7 - */ - public T convertQuietly(final Object value, final T defaultValue) { - try { - return convert(value, defaultValue); - } catch (final Exception e) { - return defaultValue; - } - } - @Override - @SuppressWarnings("unchecked") - public T convert(final Object value, final T defaultValue) { - Class targetType = getTargetType(); - if (null == targetType && null == defaultValue) { - throw new NullPointerException(StrUtil.format("[type] and [defaultValue] are both null for Converter [{}], we can not know what type to convert !", this.getClass().getName())); - } - if (null == targetType) { - // 目标类型不确定时使用默认值的类型 - targetType = (Class) defaultValue.getClass(); - } + public Object convert(Type targetType, final Object value) { + Assert.notNull(targetType); if (null == value) { - return defaultValue; + return null; } - if (null == defaultValue || targetType.isInstance(defaultValue)) { - if (targetType.isInstance(value) && false == Map.class.isAssignableFrom(targetType)) { - // 除Map外,已经是目标类型,不需要转换(Map类型涉及参数类型,需要单独转换) - return targetType.cast(value); - } - final T result = convertInternal(value); - return ((null == result) ? defaultValue : result); - } else { - throw new IllegalArgumentException( - StrUtil.format("Default value [{}]({}) is not the instance of [{}]", defaultValue, defaultValue.getClass(), targetType)); + Class targetClass = TypeUtil.getClass(targetType); + Assert.notNull(targetClass, "Target type is not a class!"); + + // 尝试强转 + if (targetClass.isInstance(value) && false == Map.class.isAssignableFrom(targetClass)) { + // 除Map外,已经是目标类型,不需要转换(Map类型涉及参数类型,需要单独转换) + return CastUtil.castTo(targetClass, value); } + return convertInternal(targetClass, value); } /** - * 内部转换器,被 {@link AbstractConverter#convert(Object, Object)} 调用,实现基本转换逻辑
+ * 内部转换器,被 {@link AbstractConverter#convert(Type, Object)} 调用,实现基本转换逻辑
* 内部转换器转换后如果转换失败可以做如下操作,处理结果都为返回默认值: * *
@@ -72,10 +45,11 @@ public abstract class AbstractConverter implements Converter, Serializable
 	 * 2、抛出一个{@link RuntimeException}异常
 	 * 
* + * @param targetClass 目标类型 * @param value 值 * @return 转换后的类型 */ - protected abstract T convertInternal(Object value); + protected abstract Object convertInternal(Class targetClass, Object value); /** * 值转为String,用于内部转换中需要使用String中转的情况
@@ -98,20 +72,10 @@ public abstract class AbstractConverter implements Converter, Serializable return value.toString(); } else if (ArrayUtil.isArray(value)) { return ArrayUtil.toString(value); - } else if(CharUtil.isChar(value)) { + } else if (CharUtil.isChar(value)) { //对于ASCII字符使用缓存加速转换,减少空间创建 - return CharUtil.toString((char)value); + return CharUtil.toString((char) value); } return value.toString(); } - - /** - * 获得此类实现类的泛型类型 - * - * @return 此类的泛型类型,可能为{@code null} - */ - @SuppressWarnings("unchecked") - public Class getTargetType() { - return (Class) ClassUtil.getTypeArgument(getClass()); - } } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/CastUtil.java b/hutool-core/src/main/java/cn/hutool/core/convert/CastUtil.java index 482de45c1..e200daa7a 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/CastUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/CastUtil.java @@ -1,5 +1,7 @@ package cn.hutool.core.convert; +import cn.hutool.core.lang.Assert; + import java.util.Collection; import java.util.List; import java.util.Map; @@ -13,6 +15,18 @@ import java.util.Set; */ public class CastUtil { + /** + * 将指定对象强制转换为指定类型 + * + * @param 目标类型 + * @param targetType 指定目标类型 + * @param value 被转换的对象 + * @return 转换后的对象 + */ + public static T castTo(Class targetType, final Object value) { + return Assert.notNull(targetType).cast(value); + } + /** * 泛型集合向上转型。例如将Collection<Integer>转换为Collection<Number> * diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/Convert.java b/hutool-core/src/main/java/cn/hutool/core/convert/Convert.java index cdda385cc..4e650eae6 100755 --- a/hutool-core/src/main/java/cn/hutool/core/convert/Convert.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/Convert.java @@ -532,7 +532,11 @@ public class Convert { */ @SuppressWarnings("unchecked") public static > E toEnum(final Class clazz, final Object value, final E defaultValue) { - return (E) (new EnumConverter(clazz)).convertQuietly(value, defaultValue); + try{ + return (E) (new EnumConverter()).convert(clazz, value); + } catch (final Exception ignore){ + return defaultValue; + } } /** @@ -558,7 +562,7 @@ public class Convert { * @since 3.0.8 */ public static Collection toCollection(final Class collectionType, final Class elementType, final Object value) { - return new CollectionConverter(collectionType, elementType).convert(value, null); + return new CollectionConverter().convert(collectionType, elementType, value); } /** @@ -613,7 +617,7 @@ public class Convert { */ @SuppressWarnings("unchecked") public static Map toMap(final Class keyType, final Class valueType, final Object value) { - return (Map) new MapConverter(HashMap.class, keyType, valueType).convert(value, null); + return (Map) new MapConverter().convert(HashMap.class, keyType, valueType, value); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/Converter.java b/hutool-core/src/main/java/cn/hutool/core/convert/Converter.java index e92c4d169..dcd4d1cd3 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/Converter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/Converter.java @@ -1,43 +1,41 @@ package cn.hutool.core.convert; +import cn.hutool.core.util.ObjUtil; + +import java.lang.reflect.Type; + /** - * 转换器接口,实现类型转换 + * 类型转换接口函数,根据给定的值和目标类型,由用户自定义转换规则。 * - * @param 转换到的目标类型 - * @author Looly + * @author looly + * @since 5.8.0 */ -public interface Converter { +@FunctionalInterface +public interface Converter { /** * 转换为指定类型
* 如果类型无法确定,将读取默认值的类型做为目标类型 * - * @param value 原始值 - * @param defaultValue 默认值 + * @param targetType 目标Type,非泛型类使用 + * @param value 原始值 * @return 转换后的值 - * @throws IllegalArgumentException 无法确定目标类型,且默认值为{@code null},无法确定类型 + * @throws ConvertException 转换无法正常完成或转换异常时抛出此异常 */ - T convert(Object value, T defaultValue) throws IllegalArgumentException; + Object convert(Type targetType, Object value) throws ConvertException; /** * 转换值为指定类型,可选是否不抛异常转换
* 当转换失败时返回默认值 * - * @param value 值 + * @param 目标类型 + * @param targetType 目标类型 + * @param value 值 * @param defaultValue 默认值 - * @param quietly 是否静默转换,true不抛异常 * @return 转换后的值 - * @since 5.8.0 - * @see #convert(Object, Object) */ - default T convertWithCheck(final Object value, final T defaultValue, final boolean quietly) { - try { - return convert(value, defaultValue); - } catch (final Exception e) { - if(quietly){ - return defaultValue; - } - throw e; - } + @SuppressWarnings("unchecked") + default T convert(final Type targetType, final Object value, final T defaultValue) { + return ObjUtil.defaultIfNull((T) convert(targetType, value), defaultValue); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java b/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java index 79e169b49..c17acd639 100755 --- a/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java @@ -36,7 +36,6 @@ import cn.hutool.core.convert.impl.UUIDConverter; import cn.hutool.core.date.DateTime; import cn.hutool.core.lang.Opt; import cn.hutool.core.reflect.ClassUtil; -import cn.hutool.core.reflect.ConstructorUtil; import cn.hutool.core.reflect.TypeReference; import cn.hutool.core.reflect.TypeUtil; import cn.hutool.core.util.ObjUtil; @@ -46,8 +45,6 @@ import java.io.Serializable; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import java.lang.reflect.Type; -import java.math.BigDecimal; -import java.math.BigInteger; import java.net.URI; import java.net.URL; import java.nio.charset.Charset; @@ -72,13 +69,9 @@ import java.util.TimeZone; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicIntegerArray; -import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLongArray; import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.atomic.DoubleAdder; -import java.util.concurrent.atomic.LongAdder; /** * 转换器登记中心 @@ -97,11 +90,11 @@ public class ConverterRegistry implements Serializable { /** * 默认类型转换器 */ - private Map> defaultConverterMap; + private Map defaultConverterMap; /** * 用户自定义类型转换器 */ - private volatile Map> customConverterMap; + private volatile Map customConverterMap; /** * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载 @@ -126,35 +119,8 @@ public class ConverterRegistry implements Serializable { * 构造 */ public ConverterRegistry() { - defaultConverter(); - putCustomBySpi(); - } - - /** - * 使用SPI加载转换器 - */ - private void putCustomBySpi() { - ServiceLoaderUtil.load(Converter.class).forEach(converter -> { - try { - final Type type = TypeUtil.getTypeArgument(ClassUtil.getClass(converter)); - if (null != type) { - putCustom(type, converter); - } - } catch (final Exception e) { - // 忽略注册失败的 - } - }); - } - - /** - * 登记自定义转换器 - * - * @param type 转换的目标类型 - * @param converterClass 转换器类,必须有默认构造方法 - * @return ConverterRegistry - */ - public ConverterRegistry putCustom(final Type type, final Class> converterClass) { - return putCustom(type, ConstructorUtil.newInstance(converterClass)); + registerDefault(); + registerCustomBySpi(); } /** @@ -164,7 +130,7 @@ public class ConverterRegistry implements Serializable { * @param converter 转换器 * @return ConverterRegistry */ - public ConverterRegistry putCustom(final Type type, final Converter converter) { + public ConverterRegistry putCustom(final Type type, final Converter converter) { if (null == customConverterMap) { synchronized (this) { if (null == customConverterMap) { @@ -179,13 +145,12 @@ public class ConverterRegistry implements Serializable { /** * 获得转换器
* - * @param 转换的目标类型 * @param type 类型 * @param isCustomFirst 是否自定义转换器优先 * @return 转换器 */ - public Converter getConverter(final Type type, final boolean isCustomFirst) { - Converter converter; + public Converter getConverter(final Type type, final boolean isCustomFirst) { + Converter converter; if (isCustomFirst) { converter = this.getCustomConverter(type); if (null == converter) { @@ -203,25 +168,21 @@ public class ConverterRegistry implements Serializable { /** * 获得默认转换器 * - * @param 转换的目标类型(转换器转换到的类型) * @param type 类型 * @return 转换器 */ - @SuppressWarnings("unchecked") - public Converter getDefaultConverter(final Type type) { - return (null == defaultConverterMap) ? null : (Converter) defaultConverterMap.get(type); + public Converter getDefaultConverter(final Type type) { + return (null == defaultConverterMap) ? null : defaultConverterMap.get(type); } /** * 获得自定义转换器 * - * @param 转换的目标类型(转换器转换到的类型) * @param type 类型 * @return 转换器 */ - @SuppressWarnings("unchecked") - public Converter getCustomConverter(final Type type) { - return (null == customConverterMap) ? null : (Converter) customConverterMap.get(type); + public Converter getCustomConverter(final Type type) { + return (null == customConverterMap) ? null : customConverterMap.get(type); } /** @@ -245,6 +206,9 @@ public class ConverterRegistry implements Serializable { return defaultValue; } if (TypeUtil.isUnknown(type)) { + if(null == defaultValue){ + throw new ConvertException("Unsupported convert to unknow type: {}", type); + } type = defaultValue.getClass(); } @@ -253,19 +217,17 @@ public class ConverterRegistry implements Serializable { } // 标准转换器 - final Converter converter = getConverter(type, isCustomFirst); + final Converter converter = getConverter(type, isCustomFirst); if (null != converter) { - return converter.convert(value, defaultValue); + return converter.convert(type, value, defaultValue); } - Class rowType = (Class) TypeUtil.getClass(type); if (null == rowType) { if (null != defaultValue) { rowType = (Class) defaultValue.getClass(); } else { - // 无法识别的泛型类型,按照Object处理 - return (T) value; + throw new ConvertException("Can not get class from type: {}", type); } } @@ -277,11 +239,11 @@ public class ConverterRegistry implements Serializable { // 尝试转Bean if (BeanUtil.isBean(rowType)) { - return new BeanConverter(type).convert(value, defaultValue); + return (T) BeanConverter.INSTANCE.convert(type, value); } // 无法转换 - throw new ConvertException("Can not Converter from [{}] to [{}]", value.getClass().getName(), type.getTypeName()); + throw new ConvertException("Can not convert from {}: [{}] to [{}]", value.getClass().getName(), value, type.getTypeName()); } /** @@ -337,16 +299,14 @@ public class ConverterRegistry implements Serializable { return null; } - // 集合转换(不可以默认强转) + // 集合转换(含有泛型参数,不可以默认强转) if (Collection.class.isAssignableFrom(rowType)) { - final CollectionConverter collectionConverter = new CollectionConverter(type); - return (T) collectionConverter.convert(value, (Collection) defaultValue); + return (T) CollectionConverter.INSTANCE.convert(type, value, (Collection) defaultValue); } - // Map类型(不可以默认强转) + // Map类型(含有泛型参数,不可以默认强转) if (Map.class.isAssignableFrom(rowType)) { - final MapConverter mapConverter = new MapConverter(type); - return (T) mapConverter.convert(value, (Map) defaultValue); + return (T) MapConverter.INSTANCE.convert(type, value, (Map) defaultValue); } // 默认强转 @@ -354,15 +314,24 @@ public class ConverterRegistry implements Serializable { return (T) value; } + // 原始类型转换 + if(rowType.isPrimitive()){ + return PrimitiveConverter.INSTANCE.convert(type, value, defaultValue); + } + + // 数字类型转换 + if(Number.class.isAssignableFrom(rowType)){ + return NumberConverter.INSTANCE.convert(type, value, defaultValue); + } + // 枚举转换 if (rowType.isEnum()) { - return (T) new EnumConverter(rowType).convert(value, defaultValue); + return EnumConverter.INSTANCE.convert(type, value, defaultValue); } // 数组转换 if (rowType.isArray()) { - final ArrayConverter arrayConverter = new ArrayConverter(rowType); - return (T) arrayConverter.convert(value, defaultValue); + return ArrayConverter.INSTANCE.convert(type, value, defaultValue); } // 表示非需要特殊转换的对象 @@ -374,36 +343,13 @@ public class ConverterRegistry implements Serializable { * * @return 转换器 */ - private ConverterRegistry defaultConverter() { + private ConverterRegistry registerDefault() { defaultConverterMap = new ConcurrentHashMap<>(); - // 原始类型转换器 - defaultConverterMap.put(int.class, new PrimitiveConverter(int.class)); - defaultConverterMap.put(long.class, new PrimitiveConverter(long.class)); - defaultConverterMap.put(byte.class, new PrimitiveConverter(byte.class)); - defaultConverterMap.put(short.class, new PrimitiveConverter(short.class)); - defaultConverterMap.put(float.class, new PrimitiveConverter(float.class)); - defaultConverterMap.put(double.class, new PrimitiveConverter(double.class)); - defaultConverterMap.put(char.class, new PrimitiveConverter(char.class)); - defaultConverterMap.put(boolean.class, new PrimitiveConverter(boolean.class)); - // 包装类转换器 - defaultConverterMap.put(Number.class, new NumberConverter()); - defaultConverterMap.put(Integer.class, new NumberConverter(Integer.class)); - defaultConverterMap.put(AtomicInteger.class, new NumberConverter(AtomicInteger.class));// since 3.0.8 - defaultConverterMap.put(Long.class, new NumberConverter(Long.class)); - defaultConverterMap.put(LongAdder.class, new NumberConverter(LongAdder.class)); - defaultConverterMap.put(AtomicLong.class, new NumberConverter(AtomicLong.class));// since 3.0.8 - defaultConverterMap.put(Byte.class, new NumberConverter(Byte.class)); - defaultConverterMap.put(Short.class, new NumberConverter(Short.class)); - defaultConverterMap.put(Float.class, new NumberConverter(Float.class)); - defaultConverterMap.put(Double.class, new NumberConverter(Double.class)); - defaultConverterMap.put(DoubleAdder.class, new NumberConverter(DoubleAdder.class)); defaultConverterMap.put(Character.class, new CharacterConverter()); defaultConverterMap.put(Boolean.class, new BooleanConverter()); defaultConverterMap.put(AtomicBoolean.class, new AtomicBooleanConverter());// since 3.0.8 - defaultConverterMap.put(BigDecimal.class, new NumberConverter(BigDecimal.class)); - defaultConverterMap.put(BigInteger.class, new NumberConverter(BigInteger.class)); defaultConverterMap.put(CharSequence.class, new StringConverter()); defaultConverterMap.put(String.class, new StringConverter()); @@ -413,27 +359,27 @@ public class ConverterRegistry implements Serializable { // 日期时间 defaultConverterMap.put(Calendar.class, new CalendarConverter()); - defaultConverterMap.put(java.util.Date.class, new DateConverter(java.util.Date.class)); - defaultConverterMap.put(DateTime.class, new DateConverter(DateTime.class)); - defaultConverterMap.put(java.sql.Date.class, new DateConverter(java.sql.Date.class)); - defaultConverterMap.put(java.sql.Time.class, new DateConverter(java.sql.Time.class)); - defaultConverterMap.put(java.sql.Timestamp.class, new DateConverter(java.sql.Timestamp.class)); + defaultConverterMap.put(java.util.Date.class, DateConverter.INSTANCE); + defaultConverterMap.put(DateTime.class, DateConverter.INSTANCE); + defaultConverterMap.put(java.sql.Date.class, DateConverter.INSTANCE); + defaultConverterMap.put(java.sql.Time.class, DateConverter.INSTANCE); + defaultConverterMap.put(java.sql.Timestamp.class, DateConverter.INSTANCE); // 日期时间 JDK8+(since 5.0.0) - defaultConverterMap.put(TemporalAccessor.class, new TemporalAccessorConverter(Instant.class)); - defaultConverterMap.put(Instant.class, new TemporalAccessorConverter(Instant.class)); - defaultConverterMap.put(LocalDateTime.class, new TemporalAccessorConverter(LocalDateTime.class)); - defaultConverterMap.put(LocalDate.class, new TemporalAccessorConverter(LocalDate.class)); - defaultConverterMap.put(LocalTime.class, new TemporalAccessorConverter(LocalTime.class)); - defaultConverterMap.put(ZonedDateTime.class, new TemporalAccessorConverter(ZonedDateTime.class)); - defaultConverterMap.put(OffsetDateTime.class, new TemporalAccessorConverter(OffsetDateTime.class)); - defaultConverterMap.put(OffsetTime.class, new TemporalAccessorConverter(OffsetTime.class)); + defaultConverterMap.put(TemporalAccessor.class, TemporalAccessorConverter.INSTANCE); + defaultConverterMap.put(Instant.class, TemporalAccessorConverter.INSTANCE); + defaultConverterMap.put(LocalDateTime.class, TemporalAccessorConverter.INSTANCE); + defaultConverterMap.put(LocalDate.class, TemporalAccessorConverter.INSTANCE); + defaultConverterMap.put(LocalTime.class, TemporalAccessorConverter.INSTANCE); + defaultConverterMap.put(ZonedDateTime.class, TemporalAccessorConverter.INSTANCE); + defaultConverterMap.put(OffsetDateTime.class, TemporalAccessorConverter.INSTANCE); + defaultConverterMap.put(OffsetTime.class, TemporalAccessorConverter.INSTANCE); defaultConverterMap.put(Period.class, new PeriodConverter()); defaultConverterMap.put(Duration.class, new DurationConverter()); // Reference - defaultConverterMap.put(WeakReference.class, new ReferenceConverter(WeakReference.class));// since 3.0.8 - defaultConverterMap.put(SoftReference.class, new ReferenceConverter(SoftReference.class));// since 3.0.8 + defaultConverterMap.put(WeakReference.class, ReferenceConverter.INSTANCE);// since 3.0.8 + defaultConverterMap.put(SoftReference.class, ReferenceConverter.INSTANCE);// since 3.0.8 defaultConverterMap.put(AtomicReference.class, new AtomicReferenceConverter());// since 3.0.8 //AtomicXXXArray,since 5.4.5 @@ -454,5 +400,21 @@ public class ConverterRegistry implements Serializable { return this; } + + /** + * 使用SPI加载转换器 + */ + private void registerCustomBySpi() { + ServiceLoaderUtil.load(Converter.class).forEach(converter -> { + try { + final Type type = TypeUtil.getTypeArgument(ClassUtil.getClass(converter)); + if (null != type) { + putCustom(type, converter); + } + } catch (final Exception ignore) { + // 忽略注册失败的 + } + }); + } // ----------------------------------------------------------- Private method end } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/NumberWordFormatter.java b/hutool-core/src/main/java/cn/hutool/core/convert/NumberWordFormatter.java index 98a42240c..8021d3eab 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/NumberWordFormatter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/NumberWordFormatter.java @@ -72,7 +72,7 @@ public class NumberWordFormatter { index++; } } - return String.format("%s%s", NumberUtil.decimalFormat("#.##", res), NUMBER_SUFFIX[index]); + return String.format("%s%s", NumberUtil.format("#.##", res), NUMBER_SUFFIX[index]); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/TypeConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/TypeConverter.java deleted file mode 100644 index b72acd7f6..000000000 --- a/hutool-core/src/main/java/cn/hutool/core/convert/TypeConverter.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.hutool.core.convert; - -import java.lang.reflect.Type; - -/** - * 类型转换接口函数,根据给定的值和目标类型,由用户自定义转换规则。 - * - * @author looly - * @since 5.8.0 - */ -@FunctionalInterface -public interface TypeConverter { - - /** - * 转换为指定类型
- * 如果类型无法确定,将读取默认值的类型做为目标类型 - * - * @param targetType 目标Type,非泛型类使用 - * @param value 原始值 - * @return 转换后的值 - * @throws IllegalArgumentException 无法确定目标类型,且默认值为{@code null},无法确定类型 - */ - Object convert(Type targetType, Object value); -} diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/ArrayConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/ArrayConverter.java index f1668c238..739e372e3 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/ArrayConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/ArrayConverter.java @@ -21,14 +21,10 @@ import java.util.List; * * @author Looly */ -public class ArrayConverter extends AbstractConverter { +public class ArrayConverter extends AbstractConverter { private static final long serialVersionUID = 1L; - private final Class targetType; - /** - * 目标元素类型 - */ - private final Class targetComponentType; + public static final ArrayConverter INSTANCE = new ArrayConverter(); /** * 是否忽略元素转换错误 @@ -37,46 +33,32 @@ public class ArrayConverter extends AbstractConverter { /** * 构造 - * - * @param targetType 目标数组类型 */ - public ArrayConverter(final Class targetType) { - this(targetType, false); + public ArrayConverter() { + this(false); } /** * 构造 * - * @param targetType 目标数组类型 * @param ignoreElementError 是否忽略元素转换错误 */ - public ArrayConverter(Class targetType, final boolean ignoreElementError) { - if (null == targetType) { - // 默认Object数组 - targetType = Object[].class; - } - - if (targetType.isArray()) { - this.targetType = targetType; - this.targetComponentType = targetType.getComponentType(); - } else { - //用户传入类为非数组时,按照数组元素类型对待 - this.targetComponentType = targetType; - this.targetType = ArrayUtil.getArrayType(targetType); - } - + public ArrayConverter(final boolean ignoreElementError) { this.ignoreElementError = ignoreElementError; } @Override - protected Object convertInternal(final Object value) { - return value.getClass().isArray() ? convertArrayToArray(value) : convertObjectToArray(value); - } + protected Object convertInternal(Class targetClass, final Object value) { + final Class targetComponentType; + if (targetClass.isArray()) { + targetComponentType = targetClass.getComponentType(); + } else { + //用户传入类为非数组时,按照数组元素类型对待 + targetComponentType = targetClass; + } - @SuppressWarnings({"unchecked", "rawtypes"}) - @Override - public Class getTargetType() { - return this.targetType; + return value.getClass().isArray() ? convertArrayToArray(targetComponentType, value) + : convertObjectToArray(targetComponentType, value); } /** @@ -97,7 +79,7 @@ public class ArrayConverter extends AbstractConverter { * @param array 被转换的数组值 * @return 转换后的数组 */ - private Object convertArrayToArray(final Object array) { + private Object convertArrayToArray(final Class targetComponentType, final Object array) { final Class valueComponentType = ArrayUtil.getComponentType(array); if (valueComponentType == targetComponentType) { @@ -108,7 +90,7 @@ public class ArrayConverter extends AbstractConverter { final Object result = Array.newInstance(targetComponentType, len); for (int i = 0; i < len; i++) { - Array.set(result, i, convertComponentType(Array.get(array, i))); + Array.set(result, i, convertComponentType(targetComponentType, Array.get(array, i))); } return result; } @@ -116,13 +98,14 @@ public class ArrayConverter extends AbstractConverter { /** * 非数组对数组转换 * + * @param targetComponentType 目标单个节点类型 * @param value 被转换值 * @return 转换后的数组 */ - private Object convertObjectToArray(final Object value) { + private Object convertObjectToArray(final Class targetComponentType, final Object value) { if (value instanceof CharSequence) { if (targetComponentType == char.class || targetComponentType == Character.class) { - return convertArrayToArray(value.toString().toCharArray()); + return convertArrayToArray(targetComponentType, value.toString().toCharArray()); } //issue#2365 @@ -137,7 +120,7 @@ public class ArrayConverter extends AbstractConverter { // 单纯字符串情况下按照逗号分隔后劈开 final String[] strings = StrUtil.splitToArray(value.toString(), CharUtil.COMMA); - return convertArrayToArray(strings); + return convertArrayToArray(targetComponentType, strings); } final Object result; @@ -146,7 +129,7 @@ public class ArrayConverter extends AbstractConverter { final List list = (List) value; result = Array.newInstance(targetComponentType, list.size()); for (int i = 0; i < list.size(); i++) { - Array.set(result, i, convertComponentType(list.get(i))); + Array.set(result, i, convertComponentType(targetComponentType, list.get(i))); } } else if (value instanceof Collection) { // 集合转数组 @@ -155,7 +138,7 @@ public class ArrayConverter extends AbstractConverter { int i = 0; for (final Object element : collection) { - Array.set(result, i, convertComponentType(element)); + Array.set(result, i, convertComponentType(targetComponentType, element)); i++; } } else if (value instanceof Iterable) { @@ -163,14 +146,14 @@ public class ArrayConverter extends AbstractConverter { final List list = IterUtil.toList((Iterable) value); result = Array.newInstance(targetComponentType, list.size()); for (int i = 0; i < list.size(); i++) { - Array.set(result, i, convertComponentType(list.get(i))); + Array.set(result, i, convertComponentType(targetComponentType, list.get(i))); } } else if (value instanceof Iterator) { // 可循环对象转数组,可循环对象无法获取长度,因此先转为List后转为数组 final List list = IterUtil.toList((Iterator) value); result = Array.newInstance(targetComponentType, list.size()); for (int i = 0; i < list.size(); i++) { - Array.set(result, i, convertComponentType(list.get(i))); + Array.set(result, i, convertComponentType(targetComponentType, list.get(i))); } }else if (value instanceof Number && byte.class == targetComponentType) { // 用户可能想序列化指定对象 @@ -180,7 +163,7 @@ public class ArrayConverter extends AbstractConverter { result = ObjUtil.serialize(value); } else { // everything else: - result = convertToSingleElementArray(value); + result = convertToSingleElementArray(targetComponentType, value); } return result; @@ -192,9 +175,9 @@ public class ArrayConverter extends AbstractConverter { * @param value 被转换的值 * @return 数组,只包含一个元素 */ - private Object[] convertToSingleElementArray(final Object value) { + private Object[] convertToSingleElementArray(final Class targetComponentType, final Object value) { final Object[] singleElementArray = ArrayUtil.newArray(targetComponentType, 1); - singleElementArray[0] = convertComponentType(value); + singleElementArray[0] = convertComponentType(targetComponentType, value); return singleElementArray; } @@ -205,8 +188,8 @@ public class ArrayConverter extends AbstractConverter { * @return 转换后的值,转换失败若{@link #ignoreElementError}为true,返回null,否则抛出异常 * @since 5.4.3 */ - private Object convertComponentType(final Object value) { - return Convert.convertWithCheck(this.targetComponentType, value, null, this.ignoreElementError); + private Object convertComponentType(final Class targetComponentType, final Object value) { + return Convert.convertWithCheck(targetComponentType, value, null, this.ignoreElementError); } // -------------------------------------------------------------------------------------- Private method end } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/AtomicBooleanConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/AtomicBooleanConverter.java index 643a9179a..6700fe4d4 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/AtomicBooleanConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/AtomicBooleanConverter.java @@ -1,26 +1,25 @@ package cn.hutool.core.convert.impl; -import java.util.concurrent.atomic.AtomicBoolean; - import cn.hutool.core.convert.AbstractConverter; import cn.hutool.core.util.BooleanUtil; +import java.util.concurrent.atomic.AtomicBoolean; + /** * {@link AtomicBoolean}转换器 * * @author Looly * @since 3.0.8 */ -public class AtomicBooleanConverter extends AbstractConverter { +public class AtomicBooleanConverter extends AbstractConverter { private static final long serialVersionUID = 1L; @Override - protected AtomicBoolean convertInternal(final Object value) { + protected AtomicBoolean convertInternal(final Class targetClass, final Object value) { if (value instanceof Boolean) { return new AtomicBoolean((Boolean) value); } final String valueStr = convertToStr(value); return new AtomicBoolean(BooleanUtil.toBoolean(valueStr)); } - } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/AtomicIntegerArrayConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/AtomicIntegerArrayConverter.java index fbc4ac824..545518518 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/AtomicIntegerArrayConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/AtomicIntegerArrayConverter.java @@ -11,11 +11,11 @@ import java.util.concurrent.atomic.AtomicIntegerArray; * @author Looly * @since 5.4.5 */ -public class AtomicIntegerArrayConverter extends AbstractConverter { +public class AtomicIntegerArrayConverter extends AbstractConverter { private static final long serialVersionUID = 1L; @Override - protected AtomicIntegerArray convertInternal(final Object value) { + protected AtomicIntegerArray convertInternal(final Class targetClass, final Object value) { return new AtomicIntegerArray(Convert.convert(int[].class, value)); } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/AtomicLongArrayConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/AtomicLongArrayConverter.java index 2598aecb5..ade67ce44 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/AtomicLongArrayConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/AtomicLongArrayConverter.java @@ -11,11 +11,11 @@ import java.util.concurrent.atomic.AtomicLongArray; * @author Looly * @since 5.4.5 */ -public class AtomicLongArrayConverter extends AbstractConverter { +public class AtomicLongArrayConverter extends AbstractConverter { private static final long serialVersionUID = 1L; @Override - protected AtomicLongArray convertInternal(final Object value) { + protected AtomicLongArray convertInternal(final Class targetClass, final Object value) { return new AtomicLongArray(Convert.convert(long[].class, value)); } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/AtomicReferenceConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/AtomicReferenceConverter.java index bf0a15ae1..ac5d6ade3 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/AtomicReferenceConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/AtomicReferenceConverter.java @@ -1,24 +1,23 @@ package cn.hutool.core.convert.impl; -import java.lang.reflect.Type; -import java.util.concurrent.atomic.AtomicReference; - import cn.hutool.core.convert.AbstractConverter; import cn.hutool.core.convert.ConverterRegistry; import cn.hutool.core.reflect.TypeUtil; +import java.lang.reflect.Type; +import java.util.concurrent.atomic.AtomicReference; + /** * {@link AtomicReference}转换器 * * @author Looly * @since 3.0.8 */ -@SuppressWarnings("rawtypes") -public class AtomicReferenceConverter extends AbstractConverter { +public class AtomicReferenceConverter extends AbstractConverter { private static final long serialVersionUID = 1L; @Override - protected AtomicReference convertInternal(final Object value) { + protected AtomicReference convertInternal(final Class targetClass, final Object value) { //尝试将值转换为Reference泛型的类型 Object targetValue = null; diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/BeanConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/BeanConverter.java index 20f52a605..86bdeacc9 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/BeanConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/BeanConverter.java @@ -4,13 +4,15 @@ import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.copier.BeanCopier; import cn.hutool.core.bean.copier.CopyOptions; import cn.hutool.core.bean.copier.ValueProvider; -import cn.hutool.core.convert.AbstractConverter; import cn.hutool.core.convert.ConvertException; +import cn.hutool.core.convert.Converter; +import cn.hutool.core.lang.Assert; import cn.hutool.core.map.MapProxy; import cn.hutool.core.reflect.ConstructorUtil; import cn.hutool.core.reflect.TypeUtil; import cn.hutool.core.util.ObjUtil; +import java.io.Serializable; import java.lang.reflect.Type; import java.util.Map; @@ -22,70 +24,61 @@ import java.util.Map; * ValueProvider =》 Bean * * - * @param Bean类型 * @author Looly * @since 4.0.2 */ -public class BeanConverter extends AbstractConverter { +public class BeanConverter implements Converter, Serializable { private static final long serialVersionUID = 1L; - private final Type beanType; - private final Class beanClass; + public static BeanConverter INSTANCE = new BeanConverter(); + private final CopyOptions copyOptions; /** - * 构造,默认转换选项,注入失败的字段忽略 - * - * @param beanType 转换成的目标Bean类型 + * 构造 */ - public BeanConverter(final Type beanType) { - this(beanType, CopyOptions.create().setIgnoreError(true)); - } - - /** - * 构造,默认转换选项,注入失败的字段忽略 - * - * @param beanClass 转换成的目标Bean类 - */ - public BeanConverter(final Class beanClass) { - this(beanClass, CopyOptions.create().setIgnoreError(true)); + public BeanConverter() { + this(CopyOptions.of().setIgnoreError(true)); } /** * 构造 * - * @param beanType 转换成的目标Bean类 * @param copyOptions Bean转换选项参数 */ - @SuppressWarnings("unchecked") - public BeanConverter(final Type beanType, final CopyOptions copyOptions) { - this.beanType = beanType; - this.beanClass = (Class) TypeUtil.getClass(beanType); + public BeanConverter(final CopyOptions copyOptions) { this.copyOptions = copyOptions; } @Override - protected T convertInternal(final Object value) { - if(value instanceof Map || + public Object convert(Type targetType, Object value) throws ConvertException { + Assert.notNull(targetType); + if (null == value) { + return null; + } + + Class targetClass = TypeUtil.getClass(targetType); + Assert.notNull(targetClass, "Target type is not a class!"); + + return convertInternal(targetType, targetClass, value); + } + + private Object convertInternal(final Type targetType, final Class targetClass, final Object value) { + if (value instanceof Map || value instanceof ValueProvider || BeanUtil.isBean(value.getClass())) { - if(value instanceof Map && this.beanClass.isInterface()) { + if (value instanceof Map && targetClass.isInterface()) { // 将Map动态代理为Bean - return MapProxy.create((Map)value).toProxyBean(this.beanClass); + return MapProxy.create((Map) value).toProxyBean(targetClass); } //限定被转换对象类型 - return BeanCopier.create(value, ConstructorUtil.newInstanceIfPossible(this.beanClass), this.beanType, this.copyOptions).copy(); - } else if(value instanceof byte[]){ + return BeanCopier.create(value, ConstructorUtil.newInstanceIfPossible(targetClass), targetType, this.copyOptions).copy(); + } else if (value instanceof byte[]) { // 尝试反序列化 - return ObjUtil.deserialize((byte[])value); + return ObjUtil.deserialize((byte[]) value); } throw new ConvertException("Unsupported source type: {}", value.getClass()); } - - @Override - public Class getTargetType() { - return this.beanClass; - } } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/BooleanConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/BooleanConverter.java index 5060d8704..da8c09f73 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/BooleanConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/BooleanConverter.java @@ -16,11 +16,11 @@ import cn.hutool.core.util.BooleanUtil; * * @author Looly */ -public class BooleanConverter extends AbstractConverter { +public class BooleanConverter extends AbstractConverter { private static final long serialVersionUID = 1L; @Override - protected Boolean convertInternal(final Object value) { + protected Boolean convertInternal(final Class targetClass, final Object value) { if (value instanceof Number) { // 0为false,其它数字为true return 0 != ((Number) value).doubleValue(); diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/CalendarConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/CalendarConverter.java index 3e102d70c..18940e088 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/CalendarConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/CalendarConverter.java @@ -1,19 +1,19 @@ package cn.hutool.core.convert.impl; -import java.util.Calendar; -import java.util.Date; - import cn.hutool.core.convert.AbstractConverter; import cn.hutool.core.date.DateUtil; import cn.hutool.core.text.StrUtil; +import java.util.Calendar; +import java.util.Date; + /** * 日期转换器 * * @author Looly * */ -public class CalendarConverter extends AbstractConverter { +public class CalendarConverter extends AbstractConverter { private static final long serialVersionUID = 1L; /** 日期格式化 */ @@ -38,7 +38,7 @@ public class CalendarConverter extends AbstractConverter { } @Override - protected Calendar convertInternal(final Object value) { + protected Calendar convertInternal(final Class targetClass, final Object value) { // Handle Date if (value instanceof Date) { return DateUtil.calendar((Date)value); diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/CastConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/CastConverter.java index 4eca32c69..0a0a2664d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/CastConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/CastConverter.java @@ -10,19 +10,13 @@ import cn.hutool.core.convert.ConvertException; * @param 强制转换到的类型 * @since 4.0.2 */ -public class CastConverter extends AbstractConverter { +public class CastConverter extends AbstractConverter { private static final long serialVersionUID = 1L; - private Class targetType; - @Override - protected T convertInternal(final Object value) { + protected T convertInternal(final Class targetClass, final Object value) { // 由于在AbstractConverter中已经有类型判断并强制转换,因此当在上一步强制转换失败时直接抛出异常 - throw new ConvertException("Can not cast value to [{}]", this.targetType); + throw new ConvertException("Can not cast value to [{}]", targetClass); } - @Override - public Class getTargetType() { - return this.targetType; - } } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/CharacterConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/CharacterConverter.java index 00c64f5c3..ba1dd63fb 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/CharacterConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/CharacterConverter.java @@ -10,11 +10,11 @@ import cn.hutool.core.text.StrUtil; * @author Looly * */ -public class CharacterConverter extends AbstractConverter { +public class CharacterConverter extends AbstractConverter { private static final long serialVersionUID = 1L; @Override - protected Character convertInternal(final Object value) { + protected Character convertInternal(final Class targetClass, final Object value) { if (value instanceof Boolean) { return BooleanUtil.toCharacter((Boolean) value); } else { diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/CharsetConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/CharsetConverter.java index c0cb1943e..448284e98 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/CharsetConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/CharsetConverter.java @@ -1,20 +1,20 @@ package cn.hutool.core.convert.impl; -import java.nio.charset.Charset; - import cn.hutool.core.convert.AbstractConverter; import cn.hutool.core.util.CharsetUtil; +import java.nio.charset.Charset; + /** * 编码对象转换器 * @author Looly * */ -public class CharsetConverter extends AbstractConverter{ +public class CharsetConverter extends AbstractConverter{ private static final long serialVersionUID = 1L; @Override - protected Charset convertInternal(final Object value) { + protected Charset convertInternal(final Class targetClass, final Object value) { return CharsetUtil.charset(convertToStr(value)); } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/ClassConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/ClassConverter.java index 7c6616244..46232f217 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/ClassConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/ClassConverter.java @@ -9,7 +9,7 @@ import cn.hutool.core.classloader.ClassLoaderUtil; * * @author Looly */ -public class ClassConverter extends AbstractConverter> { +public class ClassConverter extends AbstractConverter { private static final long serialVersionUID = 1L; private final boolean isInitialized; @@ -32,7 +32,7 @@ public class ClassConverter extends AbstractConverter> { } @Override - protected Class convertInternal(final Object value) { + protected Class convertInternal(final Class targetClass, final Object value) { return ClassLoaderUtil.loadClass(convertToStr(value), isInitialized); } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/CollectionConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/CollectionConverter.java index cc43b6420..08cf77aef 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/CollectionConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/CollectionConverter.java @@ -2,7 +2,7 @@ package cn.hutool.core.convert.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.convert.Converter; -import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.reflect.TypeReference; import cn.hutool.core.reflect.TypeUtil; import java.lang.reflect.Type; @@ -14,65 +14,29 @@ import java.util.Collection; * @author Looly * @since 3.0.8 */ -public class CollectionConverter implements Converter> { +public class CollectionConverter implements Converter { - /** 集合类型 */ - private final Type collectionType; - /** 集合元素类型 */ - private final Type elementType; - - /** - * 构造,默认集合类型使用{@link Collection} - */ - public CollectionConverter() { - this(Collection.class); - } - - // ---------------------------------------------------------------------------------------------- Constractor start - /** - * 构造 - * - * @param collectionType 集合类型 - */ - public CollectionConverter(final Type collectionType) { - this(collectionType, TypeUtil.getTypeArgument(collectionType)); - } - - /** - * 构造 - * - * @param collectionType 集合类型 - */ - public CollectionConverter(final Class collectionType) { - this(collectionType, TypeUtil.getTypeArgument(collectionType)); - } - - /** - * 构造 - * - * @param collectionType 集合类型 - * @param elementType 集合元素类型 - */ - public CollectionConverter(final Type collectionType, final Type elementType) { - this.collectionType = collectionType; - this.elementType = elementType; - } - // ---------------------------------------------------------------------------------------------- Constractor end + public static CollectionConverter INSTANCE = new CollectionConverter(); @Override - public Collection convert(final Object value, final Collection defaultValue) throws IllegalArgumentException { - final Collection result = convertInternal(value); - return ObjUtil.defaultIfNull(result, defaultValue); + public Collection convert(Type targetType, final Object value) { + if (targetType instanceof TypeReference) { + targetType = ((TypeReference) targetType).getType(); + } + + return convert(targetType, TypeUtil.getTypeArgument(targetType), value); } /** - * 内部转换 + * 转换 * - * @param value 值 + * @param collectionType 集合类型 + * @param elementType 集合中元素类型 + * @param value 被转换的值 * @return 转换后的集合对象 */ - protected Collection convertInternal(final Object value) { - final Collection collection = CollUtil.create(TypeUtil.getClass(this.collectionType)); - return CollUtil.addAll(collection, value, this.elementType); + public Collection convert(final Type collectionType, final Type elementType, final Object value) { + final Collection collection = CollUtil.create(TypeUtil.getClass(collectionType)); + return CollUtil.addAll(collection, value, elementType); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/CurrencyConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/CurrencyConverter.java index 0e4cb7fe4..c1f47e1a2 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/CurrencyConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/CurrencyConverter.java @@ -1,20 +1,20 @@ package cn.hutool.core.convert.impl; -import java.util.Currency; - import cn.hutool.core.convert.AbstractConverter; +import java.util.Currency; + /** * 货币{@link Currency} 转换器 * * @author Looly * @since 3.0.8 */ -public class CurrencyConverter extends AbstractConverter { +public class CurrencyConverter extends AbstractConverter { private static final long serialVersionUID = 1L; @Override - protected Currency convertInternal(final Object value) { + protected Currency convertInternal(Class targetClass, final Object value) { return Currency.getInstance(convertToStr(value)); } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/DateConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/DateConverter.java index 67b568f52..e6ee1a5a7 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/DateConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/DateConverter.java @@ -14,10 +14,11 @@ import java.util.Calendar; * * @author Looly */ -public class DateConverter extends AbstractConverter { +public class DateConverter extends AbstractConverter { private static final long serialVersionUID = 1L; - private final Class targetType; + public static final DateConverter INSTANCE = new DateConverter(); + /** * 日期格式化 */ @@ -25,21 +26,17 @@ public class DateConverter extends AbstractConverter { /** * 构造 - * - * @param targetType 目标类型 */ - public DateConverter(final Class targetType) { - this.targetType = targetType; + public DateConverter() { + this(null); } /** * 构造 * - * @param targetType 目标类型 - * @param format 日期格式 + * @param format 日期格式 */ - public DateConverter(final Class targetType, final String format) { - this.targetType = targetType; + public DateConverter(final String format) { this.format = format; } @@ -62,16 +59,16 @@ public class DateConverter extends AbstractConverter { } @Override - protected java.util.Date convertInternal(final Object value) { + protected java.util.Date convertInternal(Class targetClass, final Object value) { if (value == null || (value instanceof CharSequence && StrUtil.isBlank(value.toString()))) { return null; } if (value instanceof TemporalAccessor) { - return wrap(DateUtil.date((TemporalAccessor) value)); + return wrap(targetClass, DateUtil.date((TemporalAccessor) value)); } else if (value instanceof Calendar) { - return wrap(DateUtil.date((Calendar) value)); + return wrap(targetClass, DateUtil.date((Calendar) value)); } else if (value instanceof Number) { - return wrap(((Number) value).longValue()); + return wrap(targetClass, ((Number) value).longValue()); } else { // 统一按照字符串处理 final String valueStr = convertToStr(value); @@ -79,11 +76,11 @@ public class DateConverter extends AbstractConverter { ? DateUtil.parse(valueStr) // : DateUtil.parse(valueStr, this.format); if (null != dateTime) { - return wrap(dateTime); + return wrap(targetClass, dateTime); } } - throw new ConvertException("Can not convert {}:[{}] to {}", value.getClass().getName(), value, this.targetType.getName()); + throw new ConvertException("Can not convert {}:[{}] to {}", value.getClass().getName(), value, targetClass.getName()); } /** @@ -92,25 +89,25 @@ public class DateConverter extends AbstractConverter { * @param date Date * @return 目标类型对象 */ - private java.util.Date wrap(final DateTime date) { + private java.util.Date wrap(Class targetClass, final DateTime date) { // 返回指定类型 - if (java.util.Date.class == targetType) { + if (java.util.Date.class == targetClass) { return date.toJdkDate(); } - if (DateTime.class == targetType) { + if (DateTime.class == targetClass) { return date; } - if (java.sql.Date.class == targetType) { + if (java.sql.Date.class == targetClass) { return date.toSqlDate(); } - if (java.sql.Time.class == targetType) { + if (java.sql.Time.class == targetClass) { return new java.sql.Time(date.getTime()); } - if (java.sql.Timestamp.class == targetType) { + if (java.sql.Timestamp.class == targetClass) { return date.toTimestamp(); } - throw new UnsupportedOperationException(StrUtil.format("Unsupported target Date type: {}", this.targetType.getName())); + throw new UnsupportedOperationException(StrUtil.format("Unsupported target Date type: {}", targetClass.getName())); } /** @@ -119,30 +116,24 @@ public class DateConverter extends AbstractConverter { * @param mills Date * @return 目标类型对象 */ - private java.util.Date wrap(final long mills) { + private java.util.Date wrap(Class targetClass, final long mills) { // 返回指定类型 - if (java.util.Date.class == targetType) { + if (java.util.Date.class == targetClass) { return new java.util.Date(mills); } - if (DateTime.class == targetType) { + if (DateTime.class == targetClass) { return DateUtil.date(mills); } - if (java.sql.Date.class == targetType) { + if (java.sql.Date.class == targetClass) { return new java.sql.Date(mills); } - if (java.sql.Time.class == targetType) { + if (java.sql.Time.class == targetClass) { return new java.sql.Time(mills); } - if (java.sql.Timestamp.class == targetType) { + if (java.sql.Timestamp.class == targetClass) { return new java.sql.Timestamp(mills); } - throw new UnsupportedOperationException(StrUtil.format("Unsupported target Date type: {}", this.targetType.getName())); - } - - @SuppressWarnings("unchecked") - @Override - public Class getTargetType() { - return (Class) this.targetType; + throw new UnsupportedOperationException(StrUtil.format("Unsupported target Date type: {}", targetClass.getName())); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/DurationConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/DurationConverter.java index f183f613b..5739eb0c1 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/DurationConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/DurationConverter.java @@ -12,11 +12,11 @@ import java.time.temporal.TemporalAmount; * @author Looly * @since 5.0.0 */ -public class DurationConverter extends AbstractConverter { +public class DurationConverter extends AbstractConverter { private static final long serialVersionUID = 1L; @Override - protected Duration convertInternal(final Object value) { + protected Duration convertInternal(final Class targetClass, final Object value) { if(value instanceof TemporalAmount){ return Duration.from((TemporalAmount) value); } else if(value instanceof Long){ diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/EnumConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/EnumConverter.java index 4f0dc4dad..245a35bf3 100755 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/EnumConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/EnumConverter.java @@ -22,40 +22,26 @@ import java.util.stream.Collectors; * @since 4.0.2 */ @SuppressWarnings({"unchecked", "rawtypes"}) -public class EnumConverter extends AbstractConverter { +public class EnumConverter extends AbstractConverter { private static final long serialVersionUID = 1L; + public static final EnumConverter INSTANCE = new EnumConverter(); + private static final WeakConcurrentMap, Map, Method>> VALUE_OF_METHOD_CACHE = new WeakConcurrentMap<>(); - private final Class enumClass; - - /** - * 构造 - * - * @param enumClass 转换成的目标Enum类 - */ - public EnumConverter(final Class enumClass) { - this.enumClass = enumClass; - } - @Override - protected Object convertInternal(final Object value) { - Enum enumValue = tryConvertEnum(value, this.enumClass); + protected Object convertInternal(final Class targetClass, final Object value) { + Enum enumValue = tryConvertEnum(value, targetClass); if (null == enumValue && false == value instanceof String) { // 最后尝试先将value转String,再valueOf转换 - enumValue = Enum.valueOf(this.enumClass, convertToStr(value)); + enumValue = Enum.valueOf((Class) targetClass, convertToStr(value)); } if (null != enumValue) { return enumValue; } - throw new ConvertException("Can not convert {} to {}", value, this.enumClass); - } - - @Override - public Class getTargetType() { - return this.enumClass; + throw new ConvertException("Can not convert {} to {}", value, targetClass); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/LocaleConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/LocaleConverter.java index 65e083d53..70b4279dd 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/LocaleConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/LocaleConverter.java @@ -1,10 +1,10 @@ package cn.hutool.core.convert.impl; -import java.util.Locale; - import cn.hutool.core.convert.AbstractConverter; import cn.hutool.core.text.StrUtil; +import java.util.Locale; + /** * * {@link Locale}对象转换器
@@ -13,11 +13,11 @@ import cn.hutool.core.text.StrUtil; * @author Looly * @since 4.5.2 */ -public class LocaleConverter extends AbstractConverter { +public class LocaleConverter extends AbstractConverter { private static final long serialVersionUID = 1L; @Override - protected Locale convertInternal(final Object value) { + protected Locale convertInternal(final Class targetClass, final Object value) { try { final String str = convertToStr(value); if (StrUtil.isEmpty(str)) { diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/MapConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/MapConverter.java index 342d2bb4b..d7aad7a2f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/MapConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/MapConverter.java @@ -1,12 +1,15 @@ package cn.hutool.core.convert.impl; import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.convert.AbstractConverter; +import cn.hutool.core.convert.ConvertException; import cn.hutool.core.convert.ConverterRegistry; +import cn.hutool.core.convert.Converter; import cn.hutool.core.map.MapUtil; -import cn.hutool.core.text.StrUtil; +import cn.hutool.core.reflect.TypeReference; import cn.hutool.core.reflect.TypeUtil; +import cn.hutool.core.text.StrUtil; +import java.io.Serializable; import java.lang.reflect.Type; import java.util.Map; import java.util.Objects; @@ -17,60 +20,52 @@ import java.util.Objects; * @author Looly * @since 3.0.8 */ -public class MapConverter extends AbstractConverter> { +public class MapConverter implements Converter, Serializable { private static final long serialVersionUID = 1L; - /** Map类型 */ - private final Type mapType; - /** 键类型 */ - private final Type keyType; - /** 值类型 */ - private final Type valueType; - - /** - * 构造,Map的key和value泛型类型自动获取 - * - * @param mapType Map类型 - */ - public MapConverter(final Type mapType) { - this(mapType, TypeUtil.getTypeArgument(mapType, 0), TypeUtil.getTypeArgument(mapType, 1)); - } - - /** - * 构造 - * - * @param mapType Map类型 - * @param keyType 键类型 - * @param valueType 值类型 - */ - public MapConverter(final Type mapType, final Type keyType, final Type valueType) { - this.mapType = mapType; - this.keyType = keyType; - this.valueType = valueType; - } + public static MapConverter INSTANCE = new MapConverter(); @Override - @SuppressWarnings({ "rawtypes", "unchecked" }) - protected Map convertInternal(final Object value) { + public Object convert(Type targetType, Object value) throws ConvertException { + if (targetType instanceof TypeReference) { + targetType = ((TypeReference) targetType).getType(); + } + final Type keyType = TypeUtil.getTypeArgument(targetType, 0); + final Type valueType = TypeUtil.getTypeArgument(targetType, 1); + + return convert(targetType, keyType, valueType, value); + } + + /** + * 转换对象为指定键值类型的指定类型Map + * + * @param targetType 目标的Map类型 + * @param keyType 键类型 + * @param valueType 值类型 + * @param value 被转换的值 + * @return 转换后的Map + */ + @SuppressWarnings("rawtypes") + public Map convert(final Type targetType, final Type keyType, final Type valueType, final Object value) { Map map; if (value instanceof Map) { final Class valueClass = value.getClass(); - if(valueClass.equals(this.mapType)){ + if (valueClass.equals(targetType)) { final Type[] typeArguments = TypeUtil.getTypeArguments(valueClass); if (null != typeArguments // && 2 == typeArguments.length// - && Objects.equals(this.keyType, typeArguments[0]) // - && Objects.equals(this.valueType, typeArguments[1])) { + && Objects.equals(keyType, typeArguments[0]) // + && Objects.equals(valueType, typeArguments[1])) { //对于键值对类型一致的Map对象,不再做转换,直接返回原对象 return (Map) value; } } - map = MapUtil.createMap(TypeUtil.getClass(this.mapType)); - convertMapToMap((Map) value, map); + map = MapUtil.createMap(TypeUtil.getClass(targetType)); + convertMapToMap(keyType, valueType, (Map) value, map); } else if (BeanUtil.isBean(value.getClass())) { map = BeanUtil.beanToMap(value); // 二次转换,转换键值类型 - map = convertInternal(map); + map = convert(targetType, keyType, valueType, map); } else { throw new UnsupportedOperationException(StrUtil.format("Unsupport toMap value type: {}", value.getClass().getName())); } @@ -80,21 +75,16 @@ public class MapConverter extends AbstractConverter> { /** * Map转Map * - * @param srcMap 源Map + * @param srcMap 源Map * @param targetMap 目标Map */ - private void convertMapToMap(final Map srcMap, final Map targetMap) { + @SuppressWarnings({"rawtypes", "unchecked"}) + private void convertMapToMap(Type keyType, Type valueType, final Map srcMap, final Map targetMap) { final ConverterRegistry convert = ConverterRegistry.getInstance(); - srcMap.forEach((key, value)->{ - key = TypeUtil.isUnknown(this.keyType) ? key : convert.convert(this.keyType, key); - value = TypeUtil.isUnknown(this.valueType) ? value : convert.convert(this.valueType, value); + srcMap.forEach((key, value) -> { + key = TypeUtil.isUnknown(keyType) ? key : convert.convert(keyType, key); + value = TypeUtil.isUnknown(valueType) ? value : convert.convert(valueType, value); targetMap.put(key, value); }); } - - @Override - @SuppressWarnings("unchecked") - public Class> getTargetType() { - return (Class>) TypeUtil.getClass(this.mapType); - } } 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 dcefd85e0..1f1db1f61 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 @@ -36,33 +36,15 @@ import java.util.function.Function; * * @author Looly */ -public class NumberConverter extends AbstractConverter { +public class NumberConverter extends AbstractConverter { private static final long serialVersionUID = 1L; - private final Class targetType; + public static final NumberConverter INSTANCE = new NumberConverter(); - public NumberConverter() { - this.targetType = Number.class; - } - - /** - * 构造
- * - * @param clazz 需要转换的数字类型,默认 {@link Number} - */ - public NumberConverter(final Class clazz) { - this.targetType = (null == clazz) ? Number.class : clazz; - } - - @Override @SuppressWarnings("unchecked") - public Class getTargetType() { - return (Class) this.targetType; - } - @Override - protected Number convertInternal(final Object value) { - return convert(value, this.targetType, this::convertToStr); + protected Number convertInternal(final Class targetClass, final Object value) { + return convert(value, (Class) targetClass, this::convertToStr); } @Override diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/OptConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/OptConverter.java index 763bca69c..ff4c31359 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/OptConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/OptConverter.java @@ -10,11 +10,11 @@ import cn.hutool.core.lang.Opt; * @author Looly * @since 5.7.16 */ -public class OptConverter extends AbstractConverter> { +public class OptConverter extends AbstractConverter { private static final long serialVersionUID = 1L; @Override - protected Opt convertInternal(final Object value) { + protected Opt convertInternal(final Class targetClass, final Object value) { return Opt.ofNullable(value); } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/OptionalConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/OptionalConverter.java index 454cdb241..37e22af1c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/OptionalConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/OptionalConverter.java @@ -11,11 +11,11 @@ import java.util.Optional; * @author Looly * @since 5.0.0 */ -public class OptionalConverter extends AbstractConverter> { +public class OptionalConverter extends AbstractConverter { private static final long serialVersionUID = 1L; @Override - protected Optional convertInternal(final Object value) { + protected Optional convertInternal(final Class targetClass, final Object value) { return Optional.ofNullable(value); } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/PathConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/PathConverter.java index 54e685b9c..1d8ed6e0c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/PathConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/PathConverter.java @@ -1,23 +1,23 @@ package cn.hutool.core.convert.impl; +import cn.hutool.core.convert.AbstractConverter; + import java.io.File; import java.net.URI; import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; -import cn.hutool.core.convert.AbstractConverter; - /** * 字符串转换器 * @author Looly * */ -public class PathConverter extends AbstractConverter{ +public class PathConverter extends AbstractConverter{ private static final long serialVersionUID = 1L; @Override - protected Path convertInternal(final Object value) { + protected Path convertInternal(final Class targetClass, final Object value) { try { if(value instanceof URI){ return Paths.get((URI)value); diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/PeriodConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/PeriodConverter.java index c884aee5e..0edd3d1c9 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/PeriodConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/PeriodConverter.java @@ -12,11 +12,11 @@ import java.time.temporal.TemporalAmount; * @author Looly * @since 5.0.0 */ -public class PeriodConverter extends AbstractConverter { +public class PeriodConverter extends AbstractConverter { private static final long serialVersionUID = 1L; @Override - protected Period convertInternal(final Object value) { + protected Period convertInternal(final Class targetClass, final Object value) { if(value instanceof TemporalAmount){ return Period.from((TemporalAmount) value); }else if(value instanceof Integer){ 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 d471682e1..e00aa4fe7 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 @@ -3,8 +3,8 @@ 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.util.ObjUtil; import cn.hutool.core.text.StrUtil; +import cn.hutool.core.util.ObjUtil; import java.util.function.Function; @@ -24,29 +24,22 @@ import java.util.function.Function; * * @author Looly */ -public class PrimitiveConverter extends AbstractConverter { +public class PrimitiveConverter extends AbstractConverter { private static final long serialVersionUID = 1L; - private final Class targetType; + public static final PrimitiveConverter INSTANCE = new PrimitiveConverter(); /** * 构造
* - * @param clazz 需要转换的原始 * @throws IllegalArgumentException 传入的转换类型非原始类型时抛出 */ - public PrimitiveConverter(final Class clazz) { - if (null == clazz) { - throw new NullPointerException("PrimitiveConverter not allow null target type!"); - } else if (false == clazz.isPrimitive()) { - throw new IllegalArgumentException("[" + clazz + "] is not a primitive class!"); - } - this.targetType = clazz; + public PrimitiveConverter() { } @Override - protected Object convertInternal(final Object value) { - return PrimitiveConverter.convert(value, this.targetType, this::convertToStr); + protected Object convertInternal(final Class targetClass, final Object value) { + return PrimitiveConverter.convert(value, targetClass, this::convertToStr); } @Override @@ -54,12 +47,6 @@ public class PrimitiveConverter extends AbstractConverter { return StrUtil.trim(super.convertToStr(value)); } - @Override - @SuppressWarnings("unchecked") - public Class getTargetType() { - return (Class) this.targetType; - } - /** * 将指定值转换为原始类型的值 * @param value 值 diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/ReferenceConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/ReferenceConverter.java index 43f7630c1..8899f5d5e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/ReferenceConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/ReferenceConverter.java @@ -17,26 +17,18 @@ import java.lang.reflect.Type; * @since 3.0.8 */ @SuppressWarnings("rawtypes") -public class ReferenceConverter extends AbstractConverter { +public class ReferenceConverter extends AbstractConverter { private static final long serialVersionUID = 1L; - private final Class targetType; - - /** - * 构造 - * @param targetType {@link Reference}实现类型 - */ - public ReferenceConverter(final Class targetType) { - this.targetType = targetType; - } + public static ReferenceConverter INSTANCE = new ReferenceConverter(); @SuppressWarnings("unchecked") @Override - protected Reference convertInternal(final Object value) { + protected Reference convertInternal(final Class targetClass, final Object value) { //尝试将值转换为Reference泛型的类型 Object targetValue = null; - final Type paramType = TypeUtil.getTypeArgument(targetType); + final Type paramType = TypeUtil.getTypeArgument(targetClass); if(false == TypeUtil.isUnknown(paramType)){ targetValue = ConverterRegistry.getInstance().convert(paramType, value); } @@ -44,13 +36,13 @@ public class ReferenceConverter extends AbstractConverter { targetValue = value; } - if(this.targetType == WeakReference.class){ + if(targetClass == WeakReference.class){ return new WeakReference(targetValue); - }else if(this.targetType == SoftReference.class){ + }else if(targetClass == SoftReference.class){ return new SoftReference(targetValue); } - throw new UnsupportedOperationException(StrUtil.format("Unsupport Reference type: {}", this.targetType.getName())); + throw new UnsupportedOperationException(StrUtil.format("Unsupport Reference type: {}", targetClass.getName())); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/StackTraceElementConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/StackTraceElementConverter.java index 44c99aee2..7c915a6aa 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/StackTraceElementConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/StackTraceElementConverter.java @@ -1,11 +1,11 @@ package cn.hutool.core.convert.impl; -import java.util.Map; - import cn.hutool.core.convert.AbstractConverter; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ObjUtil; +import java.util.Map; + /** * {@link StackTraceElement} 转换器
* 只支持Map方式转换 @@ -13,11 +13,11 @@ import cn.hutool.core.util.ObjUtil; * @author Looly * @since 3.0.8 */ -public class StackTraceElementConverter extends AbstractConverter { +public class StackTraceElementConverter extends AbstractConverter { private static final long serialVersionUID = 1L; @Override - protected StackTraceElement convertInternal(final Object value) { + protected StackTraceElement convertInternal(final Class targetClass, final Object value) { if (value instanceof Map) { final Map map = (Map) value; diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/StringConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/StringConverter.java index c22f78145..90787fa4e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/StringConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/StringConverter.java @@ -19,11 +19,11 @@ import java.util.TimeZone; * * @author Looly */ -public class StringConverter extends AbstractConverter { +public class StringConverter extends AbstractConverter { private static final long serialVersionUID = 1L; @Override - protected String convertInternal(final Object value) { + protected String convertInternal(final Class targetClass, final Object value) { if (value instanceof TimeZone) { return ((TimeZone) value).getID(); } else if (value instanceof org.w3c.dom.Node) { diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/TemporalAccessorConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/TemporalAccessorConverter.java index 131095721..94da2e376 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/TemporalAccessorConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/TemporalAccessorConverter.java @@ -37,10 +37,11 @@ import java.util.Objects; * @author looly * @since 5.0.0 */ -public class TemporalAccessorConverter extends AbstractConverter { +public class TemporalAccessorConverter extends AbstractConverter { private static final long serialVersionUID = 1L; - private final Class targetType; + public static final TemporalAccessorConverter INSTANCE = new TemporalAccessorConverter(); + /** * 日期格式化 */ @@ -48,21 +49,17 @@ public class TemporalAccessorConverter extends AbstractConverter targetType) { - this(targetType, null); + public TemporalAccessorConverter() { + this(null); } /** * 构造 * - * @param targetType 目标类型 * @param format 日期格式 */ - public TemporalAccessorConverter(final Class targetType, final String format) { - this.targetType = targetType; + public TemporalAccessorConverter(final String format) { this.format = format; } @@ -84,26 +81,20 @@ public class TemporalAccessorConverter extends AbstractConverter getTargetType() { - return (Class) this.targetType; - } - - @Override - protected TemporalAccessor convertInternal(final Object value) { + protected TemporalAccessor convertInternal(final Class targetClass, final Object value) { if (value instanceof Long) { - return parseFromLong((Long) value); + return parseFromLong(targetClass, (Long) value); } else if (value instanceof TemporalAccessor) { - return parseFromTemporalAccessor((TemporalAccessor) value); + return parseFromTemporalAccessor(targetClass, (TemporalAccessor) value); } else if (value instanceof Date) { final DateTime dateTime = DateUtil.date((Date) value); - return parseFromInstant(dateTime.toInstant(), dateTime.getZoneId()); + return parseFromInstant(targetClass, dateTime.toInstant(), dateTime.getZoneId()); } else if (value instanceof Calendar) { final Calendar calendar = (Calendar) value; - return parseFromInstant(calendar.toInstant(), calendar.getTimeZone().toZoneId()); + return parseFromInstant(targetClass, calendar.toInstant(), calendar.getTimeZone().toZoneId()); } else { - return parseFromCharSequence(convertToStr(value)); + return parseFromCharSequence(targetClass, convertToStr(value)); } } @@ -113,7 +104,7 @@ public class TemporalAccessorConverter extends AbstractConverter targetClass, final CharSequence value) { if (StrUtil.isBlank(value)) { return null; } @@ -129,17 +120,18 @@ public class TemporalAccessorConverter extends AbstractConverter targetClass, final Long time) { + return parseFromInstant(targetClass, Instant.ofEpochMilli(time), null); } /** @@ -148,16 +140,16 @@ public class TemporalAccessorConverter extends AbstractConverter targetClass, final TemporalAccessor temporalAccessor) { TemporalAccessor result = null; if (temporalAccessor instanceof LocalDateTime) { - result = parseFromLocalDateTime((LocalDateTime) temporalAccessor); + result = parseFromLocalDateTime(targetClass, (LocalDateTime) temporalAccessor); } else if (temporalAccessor instanceof ZonedDateTime) { - result = parseFromZonedDateTime((ZonedDateTime) temporalAccessor); + result = parseFromZonedDateTime(targetClass, (ZonedDateTime) temporalAccessor); } if (null == result) { - result = parseFromInstant(DateUtil.toInstant(temporalAccessor), null); + result = parseFromInstant(targetClass, DateUtil.toInstant(temporalAccessor), null); } return result; @@ -166,26 +158,27 @@ public class TemporalAccessorConverter extends AbstractConverter targetClass, final LocalDateTime localDateTime) { + if (Instant.class.equals(targetClass)) { return DateUtil.toInstant(localDateTime); } - if (LocalDate.class.equals(this.targetType)) { + if (LocalDate.class.equals(targetClass)) { return localDateTime.toLocalDate(); } - if (LocalTime.class.equals(this.targetType)) { + if (LocalTime.class.equals(targetClass)) { return localDateTime.toLocalTime(); } - if (ZonedDateTime.class.equals(this.targetType)) { + if (ZonedDateTime.class.equals(targetClass)) { return localDateTime.atZone(ZoneId.systemDefault()); } - if (OffsetDateTime.class.equals(this.targetType)) { + if (OffsetDateTime.class.equals(targetClass)) { return localDateTime.atZone(ZoneId.systemDefault()).toOffsetDateTime(); } - if (OffsetTime.class.equals(this.targetType)) { + if (OffsetTime.class.equals(targetClass)) { return localDateTime.atZone(ZoneId.systemDefault()).toOffsetDateTime().toOffsetTime(); } @@ -198,23 +191,23 @@ public class TemporalAccessorConverter extends AbstractConverter targetClass, final ZonedDateTime zonedDateTime) { + if (Instant.class.equals(targetClass)) { return DateUtil.toInstant(zonedDateTime); } - if (LocalDateTime.class.equals(this.targetType)) { + if (LocalDateTime.class.equals(targetClass)) { return zonedDateTime.toLocalDateTime(); } - if (LocalDate.class.equals(this.targetType)) { + if (LocalDate.class.equals(targetClass)) { return zonedDateTime.toLocalDate(); } - if (LocalTime.class.equals(this.targetType)) { + if (LocalTime.class.equals(targetClass)) { return zonedDateTime.toLocalTime(); } - if (OffsetDateTime.class.equals(this.targetType)) { + if (OffsetDateTime.class.equals(targetClass)) { return zonedDateTime.toOffsetDateTime(); } - if (OffsetTime.class.equals(this.targetType)) { + if (OffsetTime.class.equals(targetClass)) { return zonedDateTime.toOffsetDateTime().toOffsetTime(); } @@ -228,25 +221,25 @@ public class TemporalAccessorConverter extends AbstractConverter targetClass, final Instant instant, ZoneId zoneId) { + if (Instant.class.equals(targetClass)) { return instant; } zoneId = ObjUtil.defaultIfNull(zoneId, ZoneId::systemDefault); TemporalAccessor result = null; - if (LocalDateTime.class.equals(this.targetType)) { + if (LocalDateTime.class.equals(targetClass)) { result = LocalDateTime.ofInstant(instant, zoneId); - } else if (LocalDate.class.equals(this.targetType)) { + } else if (LocalDate.class.equals(targetClass)) { result = instant.atZone(zoneId).toLocalDate(); - } else if (LocalTime.class.equals(this.targetType)) { + } else if (LocalTime.class.equals(targetClass)) { result = instant.atZone(zoneId).toLocalTime(); - } else if (ZonedDateTime.class.equals(this.targetType)) { + } else if (ZonedDateTime.class.equals(targetClass)) { result = instant.atZone(zoneId); - } else if (OffsetDateTime.class.equals(this.targetType)) { + } else if (OffsetDateTime.class.equals(targetClass)) { result = OffsetDateTime.ofInstant(instant, zoneId); - } else if (OffsetTime.class.equals(this.targetType)) { + } else if (OffsetTime.class.equals(targetClass)) { result = OffsetTime.ofInstant(instant, zoneId); } return result; diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/TimeZoneConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/TimeZoneConverter.java index 3981ac855..9e74fe8c8 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/TimeZoneConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/TimeZoneConverter.java @@ -1,19 +1,19 @@ package cn.hutool.core.convert.impl; -import java.util.TimeZone; - import cn.hutool.core.convert.AbstractConverter; +import java.util.TimeZone; + /** * TimeZone转换器 * @author Looly * */ -public class TimeZoneConverter extends AbstractConverter{ +public class TimeZoneConverter extends AbstractConverter{ private static final long serialVersionUID = 1L; @Override - protected TimeZone convertInternal(final Object value) { + protected TimeZone convertInternal(final Class targetClass, final Object value) { return TimeZone.getTimeZone(convertToStr(value)); } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/URIConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/URIConverter.java index 3f945748b..f6ba1e83c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/URIConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/URIConverter.java @@ -1,21 +1,21 @@ package cn.hutool.core.convert.impl; +import cn.hutool.core.convert.AbstractConverter; + import java.io.File; import java.net.URI; import java.net.URL; -import cn.hutool.core.convert.AbstractConverter; - /** * URI对象转换器 * @author Looly * */ -public class URIConverter extends AbstractConverter{ +public class URIConverter extends AbstractConverter{ private static final long serialVersionUID = 1L; @Override - protected URI convertInternal(final Object value) { + protected URI convertInternal(final Class targetClass, final Object value) { try { if(value instanceof File){ return ((File)value).toURI(); diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/URLConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/URLConverter.java index 03198b545..84eb182c7 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/URLConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/URLConverter.java @@ -1,21 +1,21 @@ package cn.hutool.core.convert.impl; +import cn.hutool.core.convert.AbstractConverter; + import java.io.File; import java.net.URI; import java.net.URL; -import cn.hutool.core.convert.AbstractConverter; - /** * URL对象转换器 * @author Looly * */ -public class URLConverter extends AbstractConverter{ +public class URLConverter extends AbstractConverter{ private static final long serialVersionUID = 1L; @Override - protected URL convertInternal(final Object value) { + protected URL convertInternal(final Class targetClass, final Object value) { try { if(value instanceof File){ return ((File)value).toURI().toURL(); diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/UUIDConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/UUIDConverter.java index ea2236852..9d2ddf566 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/UUIDConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/UUIDConverter.java @@ -1,9 +1,9 @@ package cn.hutool.core.convert.impl; -import java.util.UUID; - import cn.hutool.core.convert.AbstractConverter; +import java.util.UUID; + /** * UUID对象转换器转换器 * @@ -11,11 +11,13 @@ import cn.hutool.core.convert.AbstractConverter; * @since 4.0.10 * */ -public class UUIDConverter extends AbstractConverter { +public class UUIDConverter extends AbstractConverter { private static final long serialVersionUID = 1L; + + @Override - protected UUID convertInternal(final Object value) { + protected UUID convertInternal(final Class targetClass, final Object value) { return UUID.fromString(convertToStr(value)); } diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java index 32eb09d09..485127c96 100755 --- a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java @@ -99,7 +99,8 @@ public class DateUtil extends CalendarUtil { /** * 根据已有{@link Date} 产生新的{@link DateTime}对象,并根据指定时区转换 * - * @param date Date对象 + * @param date Date对象 + * @param timeZone 时区 * @return {@link DateTime}对象 */ public static DateTime date(final Date date, final TimeZone timeZone) { diff --git a/hutool-core/src/main/java/cn/hutool/core/date/LocalDateTimeUtil.java b/hutool-core/src/main/java/cn/hutool/core/date/LocalDateTimeUtil.java index 19273aaed..6816f1adc 100755 --- a/hutool-core/src/main/java/cn/hutool/core/date/LocalDateTimeUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/LocalDateTimeUtil.java @@ -45,6 +45,15 @@ public class LocalDateTimeUtil { return LocalDateTime.now(); } + /** + * 当天时间,默认时区 + * + * @return {@link LocalDateTime} + */ + public static LocalDate today() { + return LocalDate.now(); + } + /** * {@link Instant}转{@link LocalDateTime},使用默认时区 * diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/ansi/AnsiEncoder.java b/hutool-core/src/main/java/cn/hutool/core/lang/ansi/AnsiEncoder.java index deb0b3b8f..e58cbe2fb 100755 --- a/hutool-core/src/main/java/cn/hutool/core/lang/ansi/AnsiEncoder.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/ansi/AnsiEncoder.java @@ -4,7 +4,6 @@ package cn.hutool.core.lang.ansi; * 生成ANSI格式的编码输出 * * @author Phillip Webb - * @since 1.0.0 */ public abstract class AnsiEncoder { diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableByte.java b/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableByte.java index 5cb493511..e0f05026d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableByte.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableByte.java @@ -1,6 +1,6 @@ package cn.hutool.core.lang.mutable; -import cn.hutool.core.math.NumberUtil; +import cn.hutool.core.comparator.CompareUtil; /** * 可变 {@code byte} 类型 @@ -186,7 +186,7 @@ public class MutableByte extends Number implements Comparable, Muta */ @Override public int compareTo(final MutableByte other) { - return NumberUtil.compare(this.value, other.value); + return CompareUtil.compare(this.value, other.value); } // ----------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableDouble.java b/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableDouble.java index f3732a4d1..e068f7212 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableDouble.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableDouble.java @@ -1,6 +1,6 @@ package cn.hutool.core.lang.mutable; -import cn.hutool.core.math.NumberUtil; +import cn.hutool.core.comparator.CompareUtil; /** * 可变 {@code double} 类型 @@ -180,7 +180,7 @@ public class MutableDouble extends Number implements Comparable, */ @Override public int compareTo(final MutableDouble other) { - return NumberUtil.compare(this.value, other.value); + return CompareUtil.compare(this.value, other.value); } // ----------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableFloat.java b/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableFloat.java index 84572f191..345bff4e7 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableFloat.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableFloat.java @@ -1,9 +1,9 @@ package cn.hutool.core.lang.mutable; -import cn.hutool.core.math.NumberUtil; +import cn.hutool.core.comparator.CompareUtil; /** - * 可变 float 类型 + * 可变 {@code float} 类型 * * @see Float * @since 3.0.1 @@ -152,12 +152,12 @@ public class MutableFloat extends Number implements Comparable, Mu * 相等需同时满足如下条件: *
    *
  1. 非空
  2. - *
  3. 类型为 {@link MutableFloat}
  4. + *
  5. 类型为 {@code MutableFloat}
  6. *
  7. 值相等
  8. *
* * @param obj 比对的对象 - * @return 相同返回true,否则 false + * @return 相同返回true,否则 {@code false} */ @Override public boolean equals(final Object obj) { @@ -176,12 +176,12 @@ public class MutableFloat extends Number implements Comparable, Mu /** * 比较 * - * @param other 其它 {@link MutableFloat} 对象 + * @param other 其它 {@code MutableFloat} 对象 * @return x==y返回0,x<y返回-1,x>y返回1 */ @Override public int compareTo(final MutableFloat other) { - return NumberUtil.compare(this.value, other.value); + return CompareUtil.compare(this.value, other.value); } // ----------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableInt.java b/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableInt.java index 1b2c64611..912a67afc 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableInt.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableInt.java @@ -1,6 +1,6 @@ package cn.hutool.core.lang.mutable; -import cn.hutool.core.math.NumberUtil; +import cn.hutool.core.comparator.CompareUtil; /** * 可变 int 类型 @@ -181,7 +181,7 @@ public class MutableInt extends Number implements Comparable, Mutabl */ @Override public int compareTo(final MutableInt other) { - return NumberUtil.compare(this.value, other.value); + return CompareUtil.compare(this.value, other.value); } // ----------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableLong.java b/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableLong.java index cafdca29f..4f1d08ac1 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableLong.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableLong.java @@ -1,6 +1,6 @@ package cn.hutool.core.lang.mutable; -import cn.hutool.core.math.NumberUtil; +import cn.hutool.core.comparator.CompareUtil; /** * 可变 {@code long} 类型 @@ -193,7 +193,7 @@ public class MutableLong extends Number implements Comparable, Muta */ @Override public int compareTo(final MutableLong other) { - return NumberUtil.compare(this.value, other.value); + return CompareUtil.compare(this.value, other.value); } // ----------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableShort.java b/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableShort.java index 654d6d214..0e53d907e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableShort.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableShort.java @@ -1,9 +1,9 @@ package cn.hutool.core.lang.mutable; -import cn.hutool.core.math.NumberUtil; +import cn.hutool.core.comparator.CompareUtil; /** - * 可变 short 类型 + * 可变 {@code short} 类型 * * @see Short * @since 3.0.1 @@ -157,12 +157,12 @@ public class MutableShort extends Number implements Comparable, Mu * 相等需同时满足如下条件: *
    *
  1. 非空
  2. - *
  3. 类型为 {@link MutableShort}
  4. + *
  5. 类型为 {@code MutableShort}
  6. *
  7. 值相等
  8. *
* * @param obj 比对的对象 - * @return 相同返回true,否则 false + * @return 相同返回true,否则 {@code false} */ @Override public boolean equals(final Object obj) { @@ -181,12 +181,12 @@ public class MutableShort extends Number implements Comparable, Mu /** * 比较 * - * @param other 其它 {@link MutableShort} 对象 + * @param other 其它 {@code MutableShort} 对象 * @return x==y返回0,x<y返回-1,x>y返回1 */ @Override public int compareTo(final MutableShort other) { - return NumberUtil.compare(this.value, other.value); + return CompareUtil.compare(this.value, other.value); } // ----------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/map/Dict.java b/hutool-core/src/main/java/cn/hutool/core/map/Dict.java index 89eb4f05e..ff8b563fd 100755 --- a/hutool-core/src/main/java/cn/hutool/core/map/Dict.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/Dict.java @@ -247,7 +247,7 @@ public class Dict extends LinkedHashMap implements BasicTypeGett * @return vo */ public T toBeanIgnoreCase(final Class clazz) { - return BeanUtil.toBean(this, clazz, CopyOptions.create().setIgnoreCase(true)); + return BeanUtil.toBean(this, clazz, CopyOptions.of().setIgnoreCase(true)); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/math/Arrangement.java b/hutool-core/src/main/java/cn/hutool/core/math/Arrangement.java index ab9bbfc79..1a51c8634 100644 --- a/hutool-core/src/main/java/cn/hutool/core/math/Arrangement.java +++ b/hutool-core/src/main/java/cn/hutool/core/math/Arrangement.java @@ -9,7 +9,7 @@ import java.util.List; /** * 排列A(n, m)
- * 排列组合相关类 参考:http://cgs1999.iteye.com/blog/2327664 + * 排列组合相关类 参考:http://cgs1999.iteye.com/blog/2327664 * * @author looly * @since 4.0.7 @@ -47,9 +47,9 @@ public class Arrangement implements Serializable { */ public static long count(final int n, final int m) { if (n == m) { - return NumberUtil.factorial(n); + return MathUtil.factorial(n); } - return (n > m) ? NumberUtil.factorial(n, n - m) : 0; + return (n > m) ? MathUtil.factorial(n, n - m) : 0; } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/math/Combination.java b/hutool-core/src/main/java/cn/hutool/core/math/Combination.java index 7fd55f5a8..821522a3f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/math/Combination.java +++ b/hutool-core/src/main/java/cn/hutool/core/math/Combination.java @@ -1,15 +1,15 @@ package cn.hutool.core.math; +import cn.hutool.core.text.StrUtil; + import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import cn.hutool.core.text.StrUtil; - /** * 组合,即C(n, m)
- * 排列组合相关类 参考:http://cgs1999.iteye.com/blog/2327664 + * 排列组合相关类 参考:http://cgs1999.iteye.com/blog/2327664 * * @author looly * @since 4.0.6 @@ -21,7 +21,7 @@ public class Combination implements Serializable { /** * 组合,即C(n, m)
- * 排列组合相关类 参考:http://cgs1999.iteye.com/blog/2327664 + * 排列组合相关类 参考:http://cgs1999.iteye.com/blog/2327664 * * @param datas 用于组合的数据 */ @@ -40,7 +40,7 @@ public class Combination implements Serializable { if (0 == m || n == m) { return 1; } - return (n > m) ? NumberUtil.factorial(n, n - m) / NumberUtil.factorial(m) : 0; + return (n > m) ? MathUtil.factorial(n, n - m) / MathUtil.factorial(m) : 0; } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/math/MathUtil.java b/hutool-core/src/main/java/cn/hutool/core/math/MathUtil.java index 41a4665c3..0a2bffbb8 100644 --- a/hutool-core/src/main/java/cn/hutool/core/math/MathUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/math/MathUtil.java @@ -1,5 +1,9 @@ package cn.hutool.core.math; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.text.StrUtil; + +import java.math.BigInteger; import java.util.List; /** @@ -11,6 +15,14 @@ import java.util.List; */ public class MathUtil { + /** + * 0-20对应的阶乘,超过20的阶乘会超过Long.MAX_VALUE + */ + private static final long[] FACTORIALS = new long[]{ + 1L, 1L, 2L, 6L, 24L, 120L, 720L, 5040L, 40320L, 362880L, 3628800L, 39916800L, 479001600L, 6227020800L, + 87178291200L, 1307674368000L, 20922789888000L, 355687428096000L, 6402373705728000L, 121645100408832000L, + 2432902008176640000L}; + //--------------------------------------------------------------------------------------------- Arrangement /** * 计算排列数,即A(n, m) = n!/(n-m)! @@ -100,4 +112,191 @@ public class MathUtil { final int centPart = (int) (cent % 100); return new Money(yuan, centPart).getAmount().doubleValue(); } + + /** + * 计算阶乘 + *

+ * n! = n * (n-1) * ... * 2 * 1 + *

+ * + * @param n 阶乘起始 + * @return 结果 + * @since 5.6.0 + */ + public static BigInteger factorial(final BigInteger n) { + if (n.equals(BigInteger.ZERO)) { + return BigInteger.ONE; + } + return factorial(n, BigInteger.ZERO); + } + + /** + * 计算范围阶乘 + *

+ * factorial(start, end) = start * (start - 1) * ... * (end + 1) + *

+ * + * @param start 阶乘起始(包含) + * @param end 阶乘结束,必须小于起始(不包括) + * @return 结果 + * @since 5.6.0 + */ + public static BigInteger factorial(BigInteger start, BigInteger end) { + Assert.notNull(start, "Factorial start must be not null!"); + Assert.notNull(end, "Factorial end must be not null!"); + if (start.compareTo(BigInteger.ZERO) < 0 || end.compareTo(BigInteger.ZERO) < 0) { + throw new IllegalArgumentException(StrUtil.format("Factorial start and end both must be > 0, but got start={}, end={}", start, end)); + } + + if (start.equals(BigInteger.ZERO)) { + start = BigInteger.ONE; + } + + if (end.compareTo(BigInteger.ONE) < 0) { + end = BigInteger.ONE; + } + + BigInteger result = start; + end = end.add(BigInteger.ONE); + while (start.compareTo(end) > 0) { + start = start.subtract(BigInteger.ONE); + result = result.multiply(start); + } + return result; + } + + /** + * 计算范围阶乘 + *

+ * factorial(start, end) = start * (start - 1) * ... * (end + 1) + *

+ * + * @param start 阶乘起始(包含) + * @param end 阶乘结束,必须小于起始(不包括) + * @return 结果 + * @since 4.1.0 + */ + public static long factorial(final long start, final long end) { + // 负数没有阶乘 + if (start < 0 || end < 0) { + throw new IllegalArgumentException(StrUtil.format("Factorial start and end both must be >= 0, but got start={}, end={}", start, end)); + } + if (0L == start || start == end) { + return 1L; + } + if (start < end) { + return 0L; + } + return factorialMultiplyAndCheck(start, factorial(start - 1, end)); + } + + /** + * 计算范围阶乘中校验中间的计算是否存在溢出,factorial提前做了负数和0的校验,因此这里没有校验数字的正负 + * + * @param a 乘数 + * @param b 被乘数 + * @return 如果 a * b的结果没有溢出直接返回,否则抛出异常 + */ + private static long factorialMultiplyAndCheck(final long a, final long b) { + if (a <= Long.MAX_VALUE / b) { + return a * b; + } + throw new IllegalArgumentException(StrUtil.format("Overflow in multiplication: {} * {}", a, b)); + } + + /** + * 计算阶乘 + *

+ * n! = n * (n-1) * ... * 2 * 1 + *

+ * + * @param n 阶乘起始 + * @return 结果 + */ + public static long factorial(final long n) { + if (n < 0 || n > 20) { + throw new IllegalArgumentException(StrUtil.format("Factorial must have n >= 0 and n <= 20 for n!, but got n = {}", n)); + } + return FACTORIALS[(int) n]; + } + + /** + * 平方根算法
+ * 推荐使用 {@link Math#sqrt(double)} + * + * @param x 值 + * @return 平方根 + */ + public static long sqrt(long x) { + long y = 0; + long b = (~Long.MAX_VALUE) >>> 1; + while (b > 0) { + if (x >= y + b) { + x -= y + b; + y >>= 1; + y += b; + } else { + y >>= 1; + } + b >>= 2; + } + return y; + } + + /** + * 可以用于计算双色球、大乐透注数的方法
+ * 比如大乐透35选5可以这样调用processMultiple(7,5); 就是数学中的:C75=7*6/2*1 + * + * @param selectNum 选中小球个数 + * @param minNum 最少要选中多少个小球 + * @return 注数 + */ + public static int processMultiple(final int selectNum, final int minNum) { + final int result; + result = mathSubNode(selectNum, minNum) / mathNode(selectNum - minNum); + return result; + } + + /** + * 最大公约数 + * + * @param m 第一个值 + * @param n 第二个值 + * @return 最大公约数 + */ + public static int divisor(int m, int n) { + while (m % n != 0) { + final int temp = m % n; + m = n; + n = temp; + } + return n; + } + + /** + * 最小公倍数 + * + * @param m 第一个值 + * @param n 第二个值 + * @return 最小公倍数 + */ + public static int multiple(final int m, final int n) { + return m * n / divisor(m, n); + } + + private static int mathSubNode(final int selectNum, final int minNum) { + if (selectNum == minNum) { + return 1; + } else { + return selectNum * mathSubNode(selectNum - 1, minNum); + } + } + + private static int mathNode(final int selectNum) { + if (selectNum == 0) { + return 1; + } else { + return selectNum * mathNode(selectNum - 1); + } + } } diff --git a/hutool-core/src/main/java/cn/hutool/core/math/NumberUtil.java b/hutool-core/src/main/java/cn/hutool/core/math/NumberUtil.java index 575f8a9e0..6d40e14f4 100644 --- a/hutool-core/src/main/java/cn/hutool/core/math/NumberUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/math/NumberUtil.java @@ -1,11 +1,9 @@ package cn.hutool.core.math; -import cn.hutool.core.exceptions.UtilException; import cn.hutool.core.lang.Assert; import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.CharUtil; -import cn.hutool.core.util.RandomUtil; import java.math.BigDecimal; import java.math.BigInteger; @@ -14,8 +12,6 @@ import java.text.DecimalFormat; import java.text.NumberFormat; import java.text.ParseException; import java.util.Collection; -import java.util.HashSet; -import java.util.Set; /** * 数字工具类
@@ -36,7 +32,6 @@ import java.util.Set; *
  • one-jdk7-bug-thinking
  • * *

    - * TODO 需整理精简方法,去掉无用的重载方法。 * * @author Looly */ @@ -47,83 +42,6 @@ public class NumberUtil { */ private static final int DEFAULT_DIV_SCALE = 10; - /** - * 0-20对应的阶乘,超过20的阶乘会超过Long.MAX_VALUE - */ - private static final long[] FACTORIALS = new long[]{ - 1L, 1L, 2L, 6L, 24L, 120L, 720L, 5040L, 40320L, 362880L, 3628800L, 39916800L, 479001600L, 6227020800L, - 87178291200L, 1307674368000L, 20922789888000L, 355687428096000L, 6402373705728000L, 121645100408832000L, - 2432902008176640000L}; - - /** - * 提供精确的加法运算 - * - * @param v1 被加数 - * @param v2 加数 - * @return 和 - */ - public static double add(final float v1, final float v2) { - return add(Float.toString(v1), Float.toString(v2)).doubleValue(); - } - - /** - * 提供精确的加法运算 - * - * @param v1 被加数 - * @param v2 加数 - * @return 和 - */ - public static double add(final float v1, final double v2) { - return add(Float.toString(v1), Double.toString(v2)).doubleValue(); - } - - /** - * 提供精确的加法运算 - * - * @param v1 被加数 - * @param v2 加数 - * @return 和 - */ - public static double add(final double v1, final float v2) { - return add(Double.toString(v1), Float.toString(v2)).doubleValue(); - } - - /** - * 提供精确的加法运算 - * - * @param v1 被加数 - * @param v2 加数 - * @return 和 - */ - public static double add(final double v1, final double v2) { - return add(Double.toString(v1), Double.toString(v2)).doubleValue(); - } - - /** - * 提供精确的加法运算 - * - * @param v1 被加数 - * @param v2 加数 - * @return 和 - * @since 3.1.1 - */ - public static double add(final Double v1, final Double v2) { - //noinspection RedundantCast - return add((Number) v1, (Number) v2).doubleValue(); - } - - /** - * 提供精确的加法运算
    - * 如果传入多个值为null或者空,则返回0 - * - * @param v1 被加数 - * @param v2 加数 - * @return 和 - */ - public static BigDecimal add(final Number v1, final Number v2) { - return add(new Number[]{v1, v2}); - } - /** * 提供精确的加法运算
    * 如果传入多个值为null或者空,则返回0 @@ -172,98 +90,6 @@ public class NumberUtil { return result; } - /** - * 提供精确的加法运算
    - * 如果传入多个值为null或者空,则返回0 - * - * @param values 多个被加值 - * @return 和 - * @since 4.0.0 - */ - public static BigDecimal add(final BigDecimal... values) { - if (ArrayUtil.isEmpty(values)) { - return BigDecimal.ZERO; - } - - BigDecimal value = values[0]; - BigDecimal result = toBigDecimal(value); - for (int i = 1; i < values.length; i++) { - value = values[i]; - if (null != value) { - result = result.add(value); - } - } - return result; - } - - /** - * 提供精确的减法运算 - * - * @param v1 被减数 - * @param v2 减数 - * @return 差 - */ - public static double sub(final float v1, final float v2) { - return sub(Float.toString(v1), Float.toString(v2)).doubleValue(); - } - - /** - * 提供精确的减法运算 - * - * @param v1 被减数 - * @param v2 减数 - * @return 差 - */ - public static double sub(final float v1, final double v2) { - return sub(Float.toString(v1), Double.toString(v2)).doubleValue(); - } - - /** - * 提供精确的减法运算 - * - * @param v1 被减数 - * @param v2 减数 - * @return 差 - */ - public static double sub(final double v1, final float v2) { - return sub(Double.toString(v1), Float.toString(v2)).doubleValue(); - } - - /** - * 提供精确的减法运算 - * - * @param v1 被减数 - * @param v2 减数 - * @return 差 - */ - public static double sub(final double v1, final double v2) { - return sub(Double.toString(v1), Double.toString(v2)).doubleValue(); - } - - /** - * 提供精确的减法运算 - * - * @param v1 被减数 - * @param v2 减数 - * @return 差 - */ - public static double sub(final Double v1, final Double v2) { - //noinspection RedundantCast - return sub((Number) v1, (Number) v2).doubleValue(); - } - - /** - * 提供精确的减法运算
    - * 如果传入多个值为null或者空,则返回0 - * - * @param v1 被减数 - * @param v2 减数 - * @return 差 - */ - public static BigDecimal sub(final Number v1, final Number v2) { - return sub(new Number[]{v1, v2}); - } - /** * 提供精确的减法运算
    * 如果传入多个值为null或者空,则返回0 @@ -312,99 +138,6 @@ public class NumberUtil { return result; } - /** - * 提供精确的减法运算
    - * 如果传入多个值为null或者空,则返回0 - * - * @param values 多个被减值 - * @return 差 - * @since 4.0.0 - */ - public static BigDecimal sub(final BigDecimal... values) { - if (ArrayUtil.isEmpty(values)) { - return BigDecimal.ZERO; - } - - BigDecimal value = values[0]; - BigDecimal result = toBigDecimal(value); - for (int i = 1; i < values.length; i++) { - value = values[i]; - if (null != value) { - result = result.subtract(value); - } - } - return result; - } - - /** - * 提供精确的乘法运算 - * - * @param v1 被乘数 - * @param v2 乘数 - * @return 积 - */ - public static double mul(final float v1, final float v2) { - return mul(Float.toString(v1), Float.toString(v2)).doubleValue(); - } - - /** - * 提供精确的乘法运算 - * - * @param v1 被乘数 - * @param v2 乘数 - * @return 积 - */ - public static double mul(final float v1, final double v2) { - return mul(Float.toString(v1), Double.toString(v2)).doubleValue(); - } - - /** - * 提供精确的乘法运算 - * - * @param v1 被乘数 - * @param v2 乘数 - * @return 积 - */ - public static double mul(final double v1, final float v2) { - return mul(Double.toString(v1), Float.toString(v2)).doubleValue(); - } - - /** - * 提供精确的乘法运算 - * - * @param v1 被乘数 - * @param v2 乘数 - * @return 积 - */ - public static double mul(final double v1, final double v2) { - return mul(Double.toString(v1), Double.toString(v2)).doubleValue(); - } - - /** - * 提供精确的乘法运算
    - * 如果传入多个值为null或者空,则返回0 - * - * @param v1 被乘数 - * @param v2 乘数 - * @return 积 - */ - public static double mul(final Double v1, final Double v2) { - //noinspection RedundantCast - return mul((Number) v1, (Number) v2).doubleValue(); - } - - /** - * 提供精确的乘法运算
    - * 如果传入多个值为null或者空,则返回0 - * - * @param v1 被乘数 - * @param v2 乘数 - * @return 积 - */ - public static BigDecimal mul(final Number v1, final Number v2) { - return mul(new Number[]{v1, v2}); - } - /** * 提供精确的乘法运算
    * 如果传入多个值为null或者空,则返回0 @@ -427,18 +160,6 @@ public class NumberUtil { return result; } - /** - * 提供精确的乘法运算 - * - * @param v1 被乘数 - * @param v2 乘数 - * @return 积 - * @since 3.0.8 - */ - public static BigDecimal mul(final String v1, final String v2) { - return mul(new BigDecimal(v1), new BigDecimal(v2)); - } - /** * 提供精确的乘法运算
    * 如果传入多个值为null或者空,则返回0 @@ -460,81 +181,6 @@ public class NumberUtil { return result; } - /** - * 提供精确的乘法运算
    - * 如果传入多个值为null或者空,则返回0 - * - * @param values 多个被乘值 - * @return 积 - * @since 4.0.0 - */ - public static BigDecimal mul(final BigDecimal... values) { - if (ArrayUtil.isEmpty(values) || ArrayUtil.hasNull(values)) { - return BigDecimal.ZERO; - } - - BigDecimal result = values[0]; - for (int i = 1; i < values.length; i++) { - result = result.multiply(values[i]); - } - return result; - } - - /** - * 提供(相对)精确的除法运算,当发生除不尽的情况的时候,精确到小数点后10位,后面的四舍五入 - * - * @param v1 被除数 - * @param v2 除数 - * @return 两个参数的商 - */ - public static double div(final float v1, final float v2) { - return div(v1, v2, DEFAULT_DIV_SCALE); - } - - /** - * 提供(相对)精确的除法运算,当发生除不尽的情况的时候,精确到小数点后10位,后面的四舍五入 - * - * @param v1 被除数 - * @param v2 除数 - * @return 两个参数的商 - */ - public static double div(final float v1, final double v2) { - return div(v1, v2, DEFAULT_DIV_SCALE); - } - - /** - * 提供(相对)精确的除法运算,当发生除不尽的情况的时候,精确到小数点后10位,后面的四舍五入 - * - * @param v1 被除数 - * @param v2 除数 - * @return 两个参数的商 - */ - public static double div(final double v1, final float v2) { - return div(v1, v2, DEFAULT_DIV_SCALE); - } - - /** - * 提供(相对)精确的除法运算,当发生除不尽的情况的时候,精确到小数点后10位,后面的四舍五入 - * - * @param v1 被除数 - * @param v2 除数 - * @return 两个参数的商 - */ - public static double div(final double v1, final double v2) { - return div(v1, v2, DEFAULT_DIV_SCALE); - } - - /** - * 提供(相对)精确的除法运算,当发生除不尽的情况的时候,精确到小数点后10位,后面的四舍五入 - * - * @param v1 被除数 - * @param v2 除数 - * @return 两个参数的商 - */ - public static double div(final Double v1, final Double v2) { - return div(v1, v2, DEFAULT_DIV_SCALE); - } - /** * 提供(相对)精确的除法运算,当发生除不尽的情况的时候,精确到小数点后10位,后面的四舍五入 * @@ -558,66 +204,6 @@ public class NumberUtil { return div(v1, v2, DEFAULT_DIV_SCALE); } - /** - * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度,后面的四舍五入 - * - * @param v1 被除数 - * @param v2 除数 - * @param scale 精确度,如果为负值,取绝对值 - * @return 两个参数的商 - */ - public static double div(final float v1, final float v2, final int scale) { - return div(v1, v2, scale, RoundingMode.HALF_UP); - } - - /** - * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度,后面的四舍五入 - * - * @param v1 被除数 - * @param v2 除数 - * @param scale 精确度,如果为负值,取绝对值 - * @return 两个参数的商 - */ - public static double div(final float v1, final double v2, final int scale) { - return div(v1, v2, scale, RoundingMode.HALF_UP); - } - - /** - * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度,后面的四舍五入 - * - * @param v1 被除数 - * @param v2 除数 - * @param scale 精确度,如果为负值,取绝对值 - * @return 两个参数的商 - */ - public static double div(final double v1, final float v2, final int scale) { - return div(v1, v2, scale, RoundingMode.HALF_UP); - } - - /** - * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度,后面的四舍五入 - * - * @param v1 被除数 - * @param v2 除数 - * @param scale 精确度,如果为负值,取绝对值 - * @return 两个参数的商 - */ - public static double div(final double v1, final double v2, final int scale) { - return div(v1, v2, scale, RoundingMode.HALF_UP); - } - - /** - * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度,后面的四舍五入 - * - * @param v1 被除数 - * @param v2 除数 - * @param scale 精确度,如果为负值,取绝对值 - * @return 两个参数的商 - */ - public static double div(final Double v1, final Double v2, final int scale) { - return div(v1, v2, scale, RoundingMode.HALF_UP); - } - /** * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度,后面的四舍五入 * @@ -643,89 +229,6 @@ public class NumberUtil { return div(v1, v2, scale, RoundingMode.HALF_UP); } - /** - * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度 - * - * @param v1 被除数 - * @param v2 除数 - * @param scale 精确度,如果为负值,取绝对值 - * @param roundingMode 保留小数的模式 {@link RoundingMode} - * @return 两个参数的商 - */ - public static double div(final float v1, final float v2, final int scale, final RoundingMode roundingMode) { - return div(Float.toString(v1), Float.toString(v2), scale, roundingMode).doubleValue(); - } - - /** - * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度 - * - * @param v1 被除数 - * @param v2 除数 - * @param scale 精确度,如果为负值,取绝对值 - * @param roundingMode 保留小数的模式 {@link RoundingMode} - * @return 两个参数的商 - */ - public static double div(final float v1, final double v2, final int scale, final RoundingMode roundingMode) { - return div(Float.toString(v1), Double.toString(v2), scale, roundingMode).doubleValue(); - } - - /** - * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度 - * - * @param v1 被除数 - * @param v2 除数 - * @param scale 精确度,如果为负值,取绝对值 - * @param roundingMode 保留小数的模式 {@link RoundingMode} - * @return 两个参数的商 - */ - public static double div(final double v1, final float v2, final int scale, final RoundingMode roundingMode) { - return div(Double.toString(v1), Float.toString(v2), scale, roundingMode).doubleValue(); - } - - /** - * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度 - * - * @param v1 被除数 - * @param v2 除数 - * @param scale 精确度,如果为负值,取绝对值 - * @param roundingMode 保留小数的模式 {@link RoundingMode} - * @return 两个参数的商 - */ - public static double div(final double v1, final double v2, final int scale, final RoundingMode roundingMode) { - return div(Double.toString(v1), Double.toString(v2), scale, roundingMode).doubleValue(); - } - - /** - * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度 - * - * @param v1 被除数 - * @param v2 除数 - * @param scale 精确度,如果为负值,取绝对值 - * @param roundingMode 保留小数的模式 {@link RoundingMode} - * @return 两个参数的商 - */ - public static double div(final Double v1, final Double v2, final int scale, final RoundingMode roundingMode) { - //noinspection RedundantCast - return div((Number) v1, (Number) v2, scale, roundingMode).doubleValue(); - } - - /** - * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度 - * - * @param v1 被除数 - * @param v2 除数 - * @param scale 精确度,如果为负值,取绝对值 - * @param roundingMode 保留小数的模式 {@link RoundingMode} - * @return 两个参数的商 - * @since 3.1.0 - */ - public static BigDecimal div(final Number v1, final Number v2, final int scale, final RoundingMode roundingMode) { - if (v1 instanceof BigDecimal && v2 instanceof BigDecimal) { - return div((BigDecimal) v1, (BigDecimal) v2, scale, roundingMode); - } - return div(StrUtil.toStringOrNull(v1), StrUtil.toStringOrNull(v2), scale, roundingMode); - } - /** * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度 * @@ -747,17 +250,20 @@ public class NumberUtil { * @param scale 精确度,如果为负值,取绝对值 * @param roundingMode 保留小数的模式 {@link RoundingMode} * @return 两个参数的商 - * @since 3.0.9 + * @since 3.1.0 */ - public static BigDecimal div(final BigDecimal v1, final BigDecimal v2, int scale, final RoundingMode roundingMode) { + public static BigDecimal div(Number v1, final Number v2, int scale, final RoundingMode roundingMode) { Assert.notNull(v2, "Divisor must be not null !"); if (null == v1) { - return BigDecimal.ZERO; + v1 = BigDecimal.ZERO; } - if (scale < 0) { - scale = -scale; + if (v1 instanceof BigDecimal && v2 instanceof BigDecimal) { + if (scale < 0) { + scale = -scale; + } + return ((BigDecimal) v1).divide((BigDecimal) v2, scale, roundingMode); } - return v1.divide(v2, scale, roundingMode); + return div(StrUtil.toStringOrNull(v1), StrUtil.toStringOrNull(v2), scale, roundingMode); } /** @@ -1014,7 +520,7 @@ public class NumberUtil { * @param value 值 * @return 格式化后的值 */ - public static String decimalFormat(final String pattern, final double value) { + public static String format(final String pattern, final double value) { Assert.isTrue(isValid(value), "value is NaN or Infinite!"); return new DecimalFormat(pattern).format(value); } @@ -1038,7 +544,7 @@ public class NumberUtil { * @return 格式化后的值 * @since 3.0.5 */ - public static String decimalFormat(final String pattern, final long value) { + public static String format(final String pattern, final long value) { return new DecimalFormat(pattern).format(value); } @@ -1061,8 +567,8 @@ public class NumberUtil { * @return 格式化后的值 * @since 5.1.6 */ - public static String decimalFormat(final String pattern, final Object value) { - return decimalFormat(pattern, value, null); + public static String format(final String pattern, final Object value) { + return format(pattern, value, null); } /** @@ -1085,7 +591,7 @@ public class NumberUtil { * @return 格式化后的值 * @since 5.6.5 */ - public static String decimalFormat(final String pattern, final Object value, final RoundingMode roundingMode) { + public static String format(final String pattern, final Object value, final RoundingMode roundingMode) { if (value instanceof Number) { Assert.isTrue(isValidNumber((Number) value), "value is NaN or Infinite!"); } @@ -1103,8 +609,8 @@ public class NumberUtil { * @return 格式化后的值 * @since 3.0.9 */ - public static String decimalFormatMoney(final double value) { - return decimalFormat(",##0.00", value); + public static String formatMoney(final double value) { + return format(",##0.00", value); } /** @@ -1242,7 +748,7 @@ public class NumberUtil { * @return 是否为整数 */ public static boolean isInteger(final String s) { - if(StrUtil.isBlank(s)) { + if (StrUtil.isBlank(s)) { return false; } try { @@ -1262,7 +768,7 @@ public class NumberUtil { * @since 4.0.0 */ public static boolean isLong(final String s) { - if(StrUtil.isBlank(s)) { + if (StrUtil.isBlank(s)) { return false; } try { @@ -1280,7 +786,7 @@ public class NumberUtil { * @return 是否为{@link Double}类型 */ public static boolean isDouble(final String s) { - if(StrUtil.isBlank(s)) { + if (StrUtil.isBlank(s)) { return false; } try { @@ -1309,131 +815,61 @@ public class NumberUtil { return true; } - // ------------------------------------------------------------------------------------------- generateXXX - - /** - * 生成不重复随机数 根据给定的最小数字和最大数字,以及随机数的个数,产生指定的不重复的数组 - * - * @param begin 最小数字(包含该数) - * @param end 最大数字(不包含该数) - * @param size 指定产生随机数的个数 - * @return 随机int数组 - */ - public static int[] generateRandomNumber(final int begin, final int end, final int size) { - // 种子你可以随意生成,但不能重复 - final int[] seed = ArrayUtil.range(begin, end); - return generateRandomNumber(begin, end, size, seed); - } - - /** - * 生成不重复随机数 根据给定的最小数字和最大数字,以及随机数的个数,产生指定的不重复的数组 - * - * @param begin 最小数字(包含该数) - * @param end 最大数字(不包含该数) - * @param size 指定产生随机数的个数 - * @param seed 种子,用于取随机数的int池 - * @return 随机int数组 - * @since 5.4.5 - */ - public static int[] generateRandomNumber(int begin, int end, final int size, final int[] seed) { - if (begin > end) { - final int temp = begin; - begin = end; - end = temp; - } - // 加入逻辑判断,确保begin= size, "Size is larger than range between begin and end!"); - Assert.isTrue(seed.length >= size, "Size is larger than seed size!"); - - final int[] ranArr = new int[size]; - // 数量你可以自己定义。 - for (int i = 0; i < size; i++) { - // 得到一个位置 - final int j = RandomUtil.randomInt(seed.length - i); - // 得到那个位置的数值 - ranArr[i] = seed[j]; - // 将最后一个未用的数字放到这里 - seed[j] = seed[seed.length - 1 - i]; - } - return ranArr; - } - - /** - * 生成不重复随机数 根据给定的最小数字和最大数字,以及随机数的个数,产生指定的不重复的数组 - * - * @param begin 最小数字(包含该数) - * @param end 最大数字(不包含该数) - * @param size 指定产生随机数的个数 - * @return 随机int数组 - */ - public static Integer[] generateBySet(int begin, int end, final int size) { - if (begin > end) { - final int temp = begin; - begin = end; - end = temp; - } - // 加入逻辑判断,确保begin set = new HashSet<>(size, 1); - while (set.size() < size) { - set.add(begin + RandomUtil.randomInt(end - begin)); - } - - return set.toArray(new Integer[0]); - } - // ------------------------------------------------------------------------------------------- range /** - * 从0开始给定范围内的整数列表,步进为1 + * 生成一个从0开始的数字列表
    * - * @param stop 结束(包含) - * @return 整数列表 - * @since 3.3.1 + * @param stopIncluded 结束的数字(不包含) + * @return 数字列表 */ - public static int[] range(final int stop) { - return range(0, stop); + public static int[] range(final int stopIncluded) { + return range(0, stopIncluded, 1); } /** - * 给定范围内的整数列表,步进为1 + * 生成一个数字列表
    + * 自动判定正序反序 * - * @param start 开始(包含) - * @param stop 结束(包含) - * @return 整数列表 + * @param startInclude 开始的数字(包含) + * @param stopIncluded 结束的数字(包含) + * @return 数字列表 */ - public static int[] range(final int start, final int stop) { - return range(start, stop, 1); + public static int[] range(final int startInclude, final int stopIncluded) { + return range(startInclude, stopIncluded, 1); } /** - * 给定范围内的整数列表 + * 生成一个数字列表
    + * 自动判定正序反序 * - * @param start 开始(包含) - * @param stop 结束(包含) - * @param step 步进 - * @return 整数列表 + * @param startInclude 开始的数字(包含) + * @param stopIncluded 结束的数字(不包含) + * @param step 步进 + * @return 数字列表 */ - public static int[] range(final int start, final int stop, int step) { - if (start < stop) { - step = Math.abs(step); - } else if (start > stop) { - step = -Math.abs(step); - } else {// start == end - return new int[]{start}; + public static int[] range(int startInclude, int stopIncluded, int step) { + if (startInclude > stopIncluded) { + final int tmp = startInclude; + startInclude = stopIncluded; + stopIncluded = tmp; } - final int size = Math.abs((stop - start) / step) + 1; - final int[] values = new int[size]; - int index = 0; - for (int i = start; (step > 0) ? i <= stop : i >= stop; i += step) { - values[index] = i; - index++; + if (step <= 0) { + step = 1; } - return values; + + final int deviation = stopIncluded + 1 - startInclude; + int length = deviation / step; + if (deviation % step != 0) { + length += 1; + } + final int[] range = new int[length]; + for (int i = 0; i < length; i++) { + range[i] = startInclude; + startInclude += step; + } + return range; } /** @@ -1451,23 +887,23 @@ public class NumberUtil { /** * 将给定范围内的整数添加到已有集合中 * - * @param start 开始(包含) - * @param stop 结束(包含) - * @param step 步进 - * @param values 集合 + * @param startInclude 开始(包含) + * @param stopInclude 结束(包含) + * @param step 步进 + * @param values 集合 * @return 集合 */ - public static Collection appendRange(final int start, final int stop, int step, final Collection values) { - if (start < stop) { + public static Collection appendRange(final int startInclude, final int stopInclude, int step, final Collection values) { + if (startInclude < stopInclude) { step = Math.abs(step); - } else if (start > stop) { + } else if (startInclude > stopInclude) { step = -Math.abs(step); } else {// start == end - values.add(start); + values.add(startInclude); return values; } - for (int i = start; (step > 0) ? i <= stop : i >= stop; i += step) { + for (int i = startInclude; (step > 0) ? i <= stopInclude : i >= stopInclude; i += step) { values.add(i); } return values; @@ -1475,177 +911,6 @@ public class NumberUtil { // ------------------------------------------------------------------------------------------- others - /** - * 计算阶乘 - *

    - * n! = n * (n-1) * ... * 2 * 1 - *

    - * - * @param n 阶乘起始 - * @return 结果 - * @since 5.6.0 - */ - public static BigInteger factorial(final BigInteger n) { - if (n.equals(BigInteger.ZERO)) { - return BigInteger.ONE; - } - return factorial(n, BigInteger.ZERO); - } - - /** - * 计算范围阶乘 - *

    - * factorial(start, end) = start * (start - 1) * ... * (end + 1) - *

    - * - * @param start 阶乘起始(包含) - * @param end 阶乘结束,必须小于起始(不包括) - * @return 结果 - * @since 5.6.0 - */ - public static BigInteger factorial(BigInteger start, BigInteger end) { - Assert.notNull(start, "Factorial start must be not null!"); - Assert.notNull(end, "Factorial end must be not null!"); - if (start.compareTo(BigInteger.ZERO) < 0 || end.compareTo(BigInteger.ZERO) < 0) { - throw new IllegalArgumentException(StrUtil.format("Factorial start and end both must be > 0, but got start={}, end={}", start, end)); - } - - if (start.equals(BigInteger.ZERO)) { - start = BigInteger.ONE; - } - - if (end.compareTo(BigInteger.ONE) < 0) { - end = BigInteger.ONE; - } - - BigInteger result = start; - end = end.add(BigInteger.ONE); - while (start.compareTo(end) > 0) { - start = start.subtract(BigInteger.ONE); - result = result.multiply(start); - } - return result; - } - - /** - * 计算范围阶乘 - *

    - * factorial(start, end) = start * (start - 1) * ... * (end + 1) - *

    - * - * @param start 阶乘起始(包含) - * @param end 阶乘结束,必须小于起始(不包括) - * @return 结果 - * @since 4.1.0 - */ - public static long factorial(final long start, final long end) { - // 负数没有阶乘 - if (start < 0 || end < 0) { - throw new IllegalArgumentException(StrUtil.format("Factorial start and end both must be >= 0, but got start={}, end={}", start, end)); - } - if (0L == start || start == end) { - return 1L; - } - if (start < end) { - return 0L; - } - return factorialMultiplyAndCheck(start, factorial(start - 1, end)); - } - - /** - * 计算范围阶乘中校验中间的计算是否存在溢出,factorial提前做了负数和0的校验,因此这里没有校验数字的正负 - * - * @param a 乘数 - * @param b 被乘数 - * @return 如果 a * b的结果没有溢出直接返回,否则抛出异常 - */ - private static long factorialMultiplyAndCheck(final long a, final long b) { - if (a <= Long.MAX_VALUE / b) { - return a * b; - } - throw new IllegalArgumentException(StrUtil.format("Overflow in multiplication: {} * {}", a, b)); - } - - /** - * 计算阶乘 - *

    - * n! = n * (n-1) * ... * 2 * 1 - *

    - * - * @param n 阶乘起始 - * @return 结果 - */ - public static long factorial(final long n) { - if (n < 0 || n > 20) { - throw new IllegalArgumentException(StrUtil.format("Factorial must have n >= 0 and n <= 20 for n!, but got n = {}", n)); - } - return FACTORIALS[(int) n]; - } - - /** - * 平方根算法
    - * 推荐使用 {@link Math#sqrt(double)} - * - * @param x 值 - * @return 平方根 - */ - public static long sqrt(long x) { - long y = 0; - long b = (~Long.MAX_VALUE) >>> 1; - while (b > 0) { - if (x >= y + b) { - x -= y + b; - y >>= 1; - y += b; - } else { - y >>= 1; - } - b >>= 2; - } - return y; - } - - /** - * 可以用于计算双色球、大乐透注数的方法
    - * 比如大乐透35选5可以这样调用processMultiple(7,5); 就是数学中的:C75=7*6/2*1 - * - * @param selectNum 选中小球个数 - * @param minNum 最少要选中多少个小球 - * @return 注数 - */ - public static int processMultiple(final int selectNum, final int minNum) { - final int result; - result = mathSubNode(selectNum, minNum) / mathNode(selectNum - minNum); - return result; - } - - /** - * 最大公约数 - * - * @param m 第一个值 - * @param n 第二个值 - * @return 最大公约数 - */ - public static int divisor(int m, int n) { - while (m % n != 0) { - final int temp = m % n; - m = n; - n = temp; - } - return n; - } - - /** - * 最小公倍数 - * - * @param m 第一个值 - * @param n 第二个值 - * @return 最小公倍数 - */ - public static int multiple(final int m, final int n) { - return m * n / divisor(m, n); - } - /** * 获得数字对应的二进制字符串 * @@ -1682,86 +947,6 @@ public class NumberUtil { return Long.parseLong(binaryStr, 2); } - // ------------------------------------------------------------------------------------------- compare - - /** - * 比较两个值的大小 - * - * @param x 第一个值 - * @param y 第二个值 - * @return x==y返回0,x<y返回小于0的数,x>y返回大于0的数 - * @see Character#compare(char, char) - * @since 3.0.1 - */ - public static int compare(final char x, final char y) { - return Character.compare(x, y); - } - - /** - * 比较两个值的大小 - * - * @param x 第一个值 - * @param y 第二个值 - * @return x==y返回0,x<y返回小于0的数,x>y返回大于0的数 - * @see Double#compare(double, double) - * @since 3.0.1 - */ - public static int compare(final double x, final double y) { - return Double.compare(x, y); - } - - /** - * 比较两个值的大小 - * - * @param x 第一个值 - * @param y 第二个值 - * @return x==y返回0,x<y返回小于0的数,x>y返回大于0的数 - * @see Integer#compare(int, int) - * @since 3.0.1 - */ - public static int compare(final int x, final int y) { - return Integer.compare(x, y); - } - - /** - * 比较两个值的大小 - * - * @param x 第一个值 - * @param y 第二个值 - * @return x==y返回0,x<y返回小于0的数,x>y返回大于0的数 - * @see Long#compare(long, long) - * @since 3.0.1 - */ - public static int compare(final long x, final long y) { - return Long.compare(x, y); - } - - /** - * 比较两个值的大小 - * - * @param x 第一个值 - * @param y 第二个值 - * @return x==y返回0,x<y返回小于0的数,x>y返回大于0的数 - * @see Short#compare(short, short) - * @since 3.0.1 - */ - public static int compare(final short x, final short y) { - return Short.compare(x, y); - } - - /** - * 比较两个值的大小 - * - * @param x 第一个值 - * @param y 第二个值 - * @return x==y返回0,x<y返回-1,x>y返回1 - * @see Byte#compare(byte, byte) - * @since 3.0.1 - */ - public static int compare(final byte x, final byte y) { - return Byte.compare(x, y); - } - /** * 比较大小,参数1 > 参数2 返回true * @@ -1894,176 +1079,6 @@ public class NumberUtil { return CharUtil.equals(c1, c2, ignoreCase); } - /** - * 取最小值 - * - * @param 元素类型 - * @param numberArray 数字数组 - * @return 最小值 - * @see ArrayUtil#min(Comparable[]) - * @since 4.0.7 - */ - public static > T min(final T[] numberArray) { - return ArrayUtil.min(numberArray); - } - - /** - * 取最小值 - * - * @param numberArray 数字数组 - * @return 最小值 - * @see ArrayUtil#min(long...) - * @since 4.0.7 - */ - public static long min(final long... numberArray) { - return ArrayUtil.min(numberArray); - } - - /** - * 取最小值 - * - * @param numberArray 数字数组 - * @return 最小值 - * @see ArrayUtil#min(int...) - * @since 4.0.7 - */ - public static int min(final int... numberArray) { - return ArrayUtil.min(numberArray); - } - - /** - * 取最小值 - * - * @param numberArray 数字数组 - * @return 最小值 - * @see ArrayUtil#min(short...) - * @since 4.0.7 - */ - public static short min(final short... numberArray) { - return ArrayUtil.min(numberArray); - } - - /** - * 取最小值 - * - * @param numberArray 数字数组 - * @return 最小值 - * @see ArrayUtil#min(double...) - * @since 4.0.7 - */ - public static double min(final double... numberArray) { - return ArrayUtil.min(numberArray); - } - - /** - * 取最小值 - * - * @param numberArray 数字数组 - * @return 最小值 - * @see ArrayUtil#min(float...) - * @since 4.0.7 - */ - public static float min(final float... numberArray) { - return ArrayUtil.min(numberArray); - } - - /** - * 取最小值 - * - * @param numberArray 数字数组 - * @return 最小值 - * @see ArrayUtil#min(Comparable[]) - * @since 5.0.8 - */ - public static BigDecimal min(final BigDecimal... numberArray) { - return ArrayUtil.min(numberArray); - } - - /** - * 取最大值 - * - * @param 元素类型 - * @param numberArray 数字数组 - * @return 最大值 - * @see ArrayUtil#max(Comparable[]) - * @since 4.0.7 - */ - public static > T max(final T[] numberArray) { - return ArrayUtil.max(numberArray); - } - - /** - * 取最大值 - * - * @param numberArray 数字数组 - * @return 最大值 - * @see ArrayUtil#max(long...) - * @since 4.0.7 - */ - public static long max(final long... numberArray) { - return ArrayUtil.max(numberArray); - } - - /** - * 取最大值 - * - * @param numberArray 数字数组 - * @return 最大值 - * @see ArrayUtil#max(int...) - * @since 4.0.7 - */ - public static int max(final int... numberArray) { - return ArrayUtil.max(numberArray); - } - - /** - * 取最大值 - * - * @param numberArray 数字数组 - * @return 最大值 - * @see ArrayUtil#max(short...) - * @since 4.0.7 - */ - public static short max(final short... numberArray) { - return ArrayUtil.max(numberArray); - } - - /** - * 取最大值 - * - * @param numberArray 数字数组 - * @return 最大值 - * @see ArrayUtil#max(double...) - * @since 4.0.7 - */ - public static double max(final double... numberArray) { - return ArrayUtil.max(numberArray); - } - - /** - * 取最大值 - * - * @param numberArray 数字数组 - * @return 最大值 - * @see ArrayUtil#max(float...) - * @since 4.0.7 - */ - public static float max(final float... numberArray) { - return ArrayUtil.max(numberArray); - } - - /** - * 取最大值 - * - * @param numberArray 数字数组 - * @return 最大值 - * @see ArrayUtil#max(Comparable[]) - * @since 5.0.8 - */ - public static BigDecimal max(final BigDecimal... numberArray) { - return ArrayUtil.max(numberArray); - } - /** * 数字转字符串
    * 调用{@link Number#toString()},并去除尾小数点儿后多余的0 @@ -2762,21 +1777,4 @@ public class NumberUtil { return false == isOdd(num); } - // ------------------------------------------------------------------------------------------- Private method start - private static int mathSubNode(final int selectNum, final int minNum) { - if (selectNum == minNum) { - return 1; - } else { - return selectNum * mathSubNode(selectNum - 1, minNum); - } - } - - private static int mathNode(final int selectNum) { - if (selectNum == 0) { - return 1; - } else { - return selectNum * mathNode(selectNum - 1); - } - } - // ------------------------------------------------------------------------------------------- Private method end } diff --git a/hutool-core/src/main/java/cn/hutool/core/reflect/MethodUtil.java b/hutool-core/src/main/java/cn/hutool/core/reflect/MethodUtil.java index 0eaf74075..c00ca0102 100644 --- a/hutool-core/src/main/java/cn/hutool/core/reflect/MethodUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/reflect/MethodUtil.java @@ -565,7 +565,7 @@ public class MethodUtil { * @param method 方法(对象方法或static方法都可) * @param args 参数对象 * @return 结果 - * @throws InvocationTargetRuntimeException 目标方法执行异常 + * @throws InvocationTargetException 目标方法执行异常 * @throws IllegalAccessException 访问权限异常 */ @SuppressWarnings("unchecked") diff --git a/hutool-core/src/main/java/cn/hutool/core/text/TextSimilarity.java b/hutool-core/src/main/java/cn/hutool/core/text/TextSimilarity.java index 994ff2f1d..a86d0160d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/text/TextSimilarity.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/TextSimilarity.java @@ -42,7 +42,7 @@ public class TextSimilarity { } final int commonLength = longestCommonSubstringLength(newStrA, newStrB); - return NumberUtil.div(commonLength, temp); + return NumberUtil.div(commonLength, temp).doubleValue(); } /** @@ -59,7 +59,7 @@ public class TextSimilarity { /** * 最长公共子串,采用动态规划算法。 其不要求所求得的字符在所给的字符串中是连续的。
    - * 算法解析见:https://leetcode-cn.com/problems/longest-common-subsequence/solution/zui-chang-gong-gong-zi-xu-lie-by-leetcod-y7u0/ + * 算法解析见:zui-chang-gong-gong-zi-xu-lie-by-leetcod-y7u0 * * @param strA 字符串1 * @param strB 字符串2 diff --git a/hutool-core/src/main/java/cn/hutool/core/text/bloom/FuncFilter.java b/hutool-core/src/main/java/cn/hutool/core/text/bloom/FuncFilter.java index 99f3ed96a..b28456519 100644 --- a/hutool-core/src/main/java/cn/hutool/core/text/bloom/FuncFilter.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/bloom/FuncFilter.java @@ -16,7 +16,7 @@ public class FuncFilter extends AbstractFilter { * * @param size 最大值 * @param hashFunc Hash函数 - * @return + * @return FuncFilter */ public static FuncFilter of(final int size, final Function hashFunc) { return new FuncFilter(size, hashFunc); diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java index 83060fb9d..ed613a297 100755 --- a/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java @@ -348,7 +348,7 @@ public class ArrayUtil extends PrimitiveArrayUtil { Array.set(buffer, index, value); return buffer; } else { - if(ArrayUtil.isEmpty(buffer)){ + if (ArrayUtil.isEmpty(buffer)) { final T[] values = newArray(value.getClass(), 1); values[0] = value; return append(buffer, values); @@ -1644,10 +1644,11 @@ public class ArrayUtil extends PrimitiveArrayUtil { * 去重数组中的元素,去重后生成新的数组,原数组不变
    * 此方法通过{@link LinkedHashSet} 去重 * - * @param 数组元素类型 - * @param 唯一键类型 - * @param array 数组 - * @param override 是否覆盖模式,如果为{@code true},加入的新值会覆盖相同key的旧值,否则会忽略新加值 + * @param 数组元素类型 + * @param 唯一键类型 + * @param array 数组 + * @param uniqueGenerator 唯一键生成器 + * @param override 是否覆盖模式,如果为{@code true},加入的新值会覆盖相同key的旧值,否则会忽略新加值 * @return 去重后的数组 * @since 5.8.0 */ @@ -1658,9 +1659,9 @@ public class ArrayUtil extends PrimitiveArrayUtil { } final UniqueKeySet set = new UniqueKeySet<>(true, uniqueGenerator); - if(override){ + if (override) { Collections.addAll(set, array); - } else{ + } else { for (final T t : array) { set.addIfAbsent(t); } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/IdcardUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/IdcardUtil.java index 3bf357b46..b09afc98a 100755 --- a/hutool-core/src/main/java/cn/hutool/core/util/IdcardUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/IdcardUtil.java @@ -638,6 +638,9 @@ public class IdcardUtil { * 参考文档《港澳居民来往内地通行证号码规则》: * https://www.hmo.gov.cn/fwga_new/wldjnd/201711/t20171120_1333.html *

    + * + * @param idCard 身份证号码 + * @return 是否有效 */ public static boolean isValidHkMoHomeReturn(final String idCard) { if (StrUtil.isEmpty(idCard)) { diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ObjUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ObjUtil.java index 10eee71d1..79e359785 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/ObjUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ObjUtil.java @@ -186,15 +186,13 @@ public class ObjUtil { * *
     	 * 1. == null
    -	 * 2. equals(null)
     	 * 
    * * @param obj 对象 * @return 是否为null */ public static boolean isNull(final Object obj) { - //noinspection ConstantConditions - return null == obj || obj.equals(null); + return null == obj; } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/util/PrimitiveArrayUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/PrimitiveArrayUtil.java index f6b54825b..9c7e4e8c7 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/PrimitiveArrayUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/PrimitiveArrayUtil.java @@ -462,63 +462,6 @@ public class PrimitiveArrayUtil { return result; } - // ---------------------------------------------------------------------- range - - /** - * 生成一个从0开始的数字列表
    - * - * @param excludedEnd 结束的数字(不包含) - * @return 数字列表 - */ - public static int[] range(final int excludedEnd) { - return range(0, excludedEnd, 1); - } - - /** - * 生成一个数字列表
    - * 自动判定正序反序 - * - * @param includedStart 开始的数字(包含) - * @param excludedEnd 结束的数字(不包含) - * @return 数字列表 - */ - public static int[] range(final int includedStart, final int excludedEnd) { - return range(includedStart, excludedEnd, 1); - } - - /** - * 生成一个数字列表
    - * 自动判定正序反序 - * - * @param includedStart 开始的数字(包含) - * @param excludedEnd 结束的数字(不包含) - * @param step 步进 - * @return 数字列表 - */ - public static int[] range(int includedStart, int excludedEnd, int step) { - if (includedStart > excludedEnd) { - final int tmp = includedStart; - includedStart = excludedEnd; - excludedEnd = tmp; - } - - if (step <= 0) { - step = 1; - } - - final int deviation = excludedEnd - includedStart; - int length = deviation / step; - if (deviation % step != 0) { - length += 1; - } - final int[] range = new int[length]; - for (int i = 0; i < length; i++) { - range[i] = includedStart; - includedStart += step; - } - return range; - } - // ---------------------------------------------------------------------- split /** diff --git a/hutool-core/src/main/java/cn/hutool/core/util/RandomUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/RandomUtil.java index 77453b431..c376f2b60 100755 --- a/hutool-core/src/main/java/cn/hutool/core/util/RandomUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/RandomUtil.java @@ -6,6 +6,7 @@ import cn.hutool.core.date.DateField; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import cn.hutool.core.exceptions.UtilException; +import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.WeightRandom; import cn.hutool.core.lang.WeightRandom.WeightObj; import cn.hutool.core.math.NumberUtil; @@ -50,7 +51,7 @@ public class RandomUtil { * *

    * 注意:此方法返回的{@link ThreadLocalRandom}不可以在多线程环境下共享对象,否则有重复随机数问题。 - * 见:https://www.jianshu.com/p/89dfe990295c + * 见:https://www.jianshu.com/p/89dfe990295c *

    * * @return {@link ThreadLocalRandom} @@ -76,7 +77,7 @@ public class RandomUtil { * 注意:此方法获取的是伪随机序列发生器PRNG(pseudo-random number generator) * *

    - * 相关说明见:https://stackoverflow.com/questions/137212/how-to-solve-slow-java-securerandom + * 相关说明见:how-to-solve-slow-java-securerandom * * @return {@link SecureRandom} * @since 3.1.2 @@ -90,7 +91,7 @@ public class RandomUtil { * 注意:此方法获取的是伪随机序列发生器PRNG(pseudo-random number generator) * *

    - * 相关说明见:https://stackoverflow.com/questions/137212/how-to-solve-slow-java-securerandom + * 相关说明见:how-to-solve-slow-java-securerandom * * @param seed 随机数种子 * @return {@link SecureRandom} @@ -104,10 +105,10 @@ public class RandomUtil { /** * 获取SHA1PRNG的{@link SecureRandom},类提供加密的强随机数生成器 (RNG)
    * 注意:此方法获取的是伪随机序列发生器PRNG(pseudo-random number generator),在Linux下噪声生成时可能造成较长时间停顿。
    - * see: http://ifeve.com/jvm-random-and-entropy-source/ + * see: http://ifeve.com/jvm-random-and-entropy-source/ * *

    - * 相关说明见:https://stackoverflow.com/questions/137212/how-to-solve-slow-java-securerandom + * 相关说明见:how-to-solve-slow-java-securerandom * * @param seed 随机数种子 * @return {@link SecureRandom} @@ -443,7 +444,7 @@ public class RandomUtil { * @return 随机列表 * @since 5.2.1 */ - public static List randomEleList(final List source, final int count) { + public static List randomPick(final List source, final int count) { if (count >= source.size()) { return ListUtil.of(source); } @@ -455,6 +456,30 @@ public class RandomUtil { return result; } + /** + * 生成从种子中获取随机数字 + * + * @param size 指定产生随机数的个数 + * @param seed 种子,用于取随机数的int池 + * @return 随机int数组 + * @since 5.4.5 + */ + public static int[] randomPickInts(final int size, final int[] seed) { + Assert.isTrue(seed.length >= size, "Size is larger than seed size!"); + + final int[] ranArr = new int[size]; + // 数量你可以自己定义。 + for (int i = 0; i < size; i++) { + // 得到一个位置 + final int j = RandomUtil.randomInt(seed.length - i); + // 得到那个位置的数值 + ranArr[i] = seed[j]; + // 将最后一个未用的数字放到这里 + seed[j] = seed[seed.length - 1 - i]; + } + return ranArr; + } + /** * 随机获得列表中的一定量的不重复元素,返回Set * @@ -487,7 +512,7 @@ public class RandomUtil { * @since 5.2.1 */ public static int[] randomInts(final int length) { - final int[] range = ArrayUtil.range(length); + final int[] range = NumberUtil.range(length); for (int i = 0; i < length; i++) { final int random = randomInt(i, length); ArrayUtil.swap(range, i, random); diff --git a/hutool-core/src/test/java/cn/hutool/core/bean/BeanCopyMappingTest.java b/hutool-core/src/test/java/cn/hutool/core/bean/BeanCopyMappingTest.java index 702ba07f4..151419e48 100644 --- a/hutool-core/src/test/java/cn/hutool/core/bean/BeanCopyMappingTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/bean/BeanCopyMappingTest.java @@ -15,15 +15,17 @@ public class BeanCopyMappingTest { */ @Test public void copyPropertiesTest() { - final CopyOptions copyOptions = CopyOptions.create() + final CopyOptions copyOptions = CopyOptions.of() .setFieldMapping(MapUtil.of("car", "carNo")); + final B b = B.builder().car("12312312").build(); final A a = A.builder().build(); final C c = C.builder().build(); BeanUtil.copyProperties(b, a, copyOptions); BeanUtil.copyProperties(a, c); + Assert.assertEquals("12312312", a.getCarNo()); Assert.assertEquals("12312312", c.getCarNo()); } 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 77bfcc86d..8061d81ec 100755 --- a/hutool-core/src/test/java/cn/hutool/core/bean/BeanUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/bean/BeanUtilTest.java @@ -71,7 +71,7 @@ public class BeanUtilTest { return true; } - }, CopyOptions.create()); + }, CopyOptions.of()); Assert.assertEquals("张三", person.getName()); Assert.assertEquals(18, person.getAge()); @@ -116,7 +116,7 @@ public class BeanUtilTest { // 错误的类型,此处忽略 map.put("age", "aaaaaa"); - final Person person = BeanUtil.toBean(map, Person.class, CopyOptions.create().setIgnoreError(true)); + final Person person = BeanUtil.toBean(map, Person.class, CopyOptions.of().setIgnoreError(true)); Assert.assertEquals("Joe", person.getName()); // 错误的类型,不copy这个字段,使用对象创建的默认值 Assert.assertEquals(0, person.getAge()); @@ -128,7 +128,7 @@ public class BeanUtilTest { map.put("Name", "Joe"); map.put("aGe", 12); - final Person person = BeanUtil.toBean(map, Person.class, CopyOptions.create().setIgnoreCase(true)); + final Person person = BeanUtil.toBean(map, Person.class, CopyOptions.of().setIgnoreCase(true)); Assert.assertEquals("Joe", person.getName()); Assert.assertEquals(12, person.getAge()); } @@ -144,7 +144,7 @@ public class BeanUtilTest { mapping.put("a_name", "name"); mapping.put("b_age", "age"); - final Person person = BeanUtil.toBean(map, Person.class, CopyOptions.create().setFieldMapping(mapping)); + final Person person = BeanUtil.toBean(map, Person.class, CopyOptions.of().setFieldMapping(mapping)); Assert.assertEquals("Joe", person.getName()); Assert.assertEquals(12, person.getAge()); } @@ -159,7 +159,7 @@ public class BeanUtilTest { map.put("age", 12); // 非空构造也可以实例化成功 - final Person2 person = BeanUtil.toBean(map, Person2.class, CopyOptions.create()); + final Person2 person = BeanUtil.toBean(map, Person2.class, CopyOptions.of()); Assert.assertEquals("Joe", person.name); Assert.assertEquals(12, person.age); } @@ -229,7 +229,10 @@ public class BeanUtilTest { person.setSubName("sub名字"); final Map map = BeanUtil.beanToMap(person, new LinkedHashMap<>(), - CopyOptions.create().setFieldValueEditor((key, value) -> key + "_" + value)); + CopyOptions.of().setFieldEditor((entry) -> { + entry.setValue(entry.getKey() + "_" + entry.getValue()); + return entry; + })); Assert.assertEquals("subName_sub名字", map.get("subName")); } @@ -387,7 +390,7 @@ public class BeanUtilTest { p2.setName("oldName"); // null值不覆盖目标属性 - BeanUtil.copyProperties(p1, p2, CopyOptions.create().ignoreNullValue()); + BeanUtil.copyProperties(p1, p2, CopyOptions.of().ignoreNullValue()); Assert.assertEquals("oldName", p2.getName()); // null覆盖目标属性 @@ -578,7 +581,7 @@ public class BeanUtilTest { info.setBookID("0"); info.setCode(""); final Food newFood = new Food(); - final CopyOptions copyOptions = CopyOptions.create().setPropertiesFilter((f, v) -> !(v instanceof CharSequence) || StrUtil.isNotBlank(v.toString())); + final CopyOptions copyOptions = CopyOptions.of().setPropertiesFilter((f, v) -> !(v instanceof CharSequence) || StrUtil.isNotBlank(v.toString())); BeanUtil.copyProperties(info, newFood, copyOptions); Assert.assertEquals(info.getBookID(), newFood.getBookID()); Assert.assertNull(newFood.getCode()); @@ -592,7 +595,7 @@ public class BeanUtilTest { o.setAge(123); o.setOpenid("asd"); - @SuppressWarnings("unchecked") final CopyOptions copyOptions = CopyOptions.create().setIgnoreProperties(Person::getAge,Person::getOpenid); + @SuppressWarnings("unchecked") final CopyOptions copyOptions = CopyOptions.of().setIgnoreProperties(Person::getAge,Person::getOpenid); final Person n = new Person(); BeanUtil.copyProperties(o, n, copyOptions); @@ -680,7 +683,12 @@ public class BeanUtilTest { a, new LinkedHashMap<>(), false, - key -> Arrays.asList("id", "name", "code", "sortOrder").contains(key) ? key : null); + entry -> { + if(false == Arrays.asList("id", "name", "code", "sortOrder").contains(entry.getKey())){ + entry.setKey(null); + } + return entry; + }); Assert.assertFalse(f.containsKey(null)); } @@ -749,10 +757,13 @@ public class BeanUtilTest { childVo1.setChild_father_name("张无忌"); childVo1.setChild_mother_name("赵敏敏"); - final CopyOptions copyOptions = CopyOptions.create(). + final CopyOptions copyOptions = CopyOptions.of(). //setIgnoreNullValue(true). //setIgnoreCase(false). - setFieldNameEditor(StrUtil::toCamelCase); + setFieldEditor(entry->{ + entry.setKey(StrUtil.toCamelCase(entry.getKey())); + return entry; + }); final ChildVo2 childVo2 = new ChildVo2(); BeanUtil.copyProperties(childVo1, childVo2, copyOptions); @@ -783,7 +794,7 @@ public class BeanUtilTest { public void issueI41WKPTest(){ final Test1 t1 = new Test1().setStrList(ListUtil.of("list")); final Test2 t2_hu = new Test2(); - BeanUtil.copyProperties(t1, t2_hu, CopyOptions.create().setIgnoreError(true)); + BeanUtil.copyProperties(t1, t2_hu, CopyOptions.of().setIgnoreError(true)); Assert.assertNull(t2_hu.getStrList()); } diff --git a/hutool-core/src/test/java/cn/hutool/core/bean/Issue1687Test.java b/hutool-core/src/test/java/cn/hutool/core/bean/Issue1687Test.java index 488405fc0..cfbddac83 100755 --- a/hutool-core/src/test/java/cn/hutool/core/bean/Issue1687Test.java +++ b/hutool-core/src/test/java/cn/hutool/core/bean/Issue1687Test.java @@ -33,7 +33,7 @@ public class Issue1687Test { sysUserFb.setCustomerId("456"); // 补救别名错位 - final CopyOptions copyOptions = CopyOptions.create().setFieldMapping( + final CopyOptions copyOptions = CopyOptions.of().setFieldMapping( MapUtil.builder("depart", "depId").build() ); final SysUser sysUser = BeanUtil.toBean(sysUserFb, SysUser.class, copyOptions); diff --git a/hutool-core/src/test/java/cn/hutool/core/bean/Issue2202Test.java b/hutool-core/src/test/java/cn/hutool/core/bean/Issue2202Test.java index fb1433d1b..6ffd5f6e1 100755 --- a/hutool-core/src/test/java/cn/hutool/core/bean/Issue2202Test.java +++ b/hutool-core/src/test/java/cn/hutool/core/bean/Issue2202Test.java @@ -22,7 +22,10 @@ public class Issue2202Test { headerMap.put("wechatpay-timestamp", "timestamp"); headerMap.put("wechatpay-signature", "signature"); final ResponseSignVerifyParams case1 = BeanUtil.toBean(headerMap, ResponseSignVerifyParams.class, - CopyOptions.create().setFieldNameEditor(field -> NamingCase.toCamelCase(field, '-'))); + CopyOptions.of().setFieldEditor(entry -> { + entry.setKey(NamingCase.toCamelCase(entry.getKey(), '-')); + return entry; + })); Assert.assertEquals("serial", case1.getWechatpaySerial()); Assert.assertEquals("nonce", case1.getWechatpayNonce()); diff --git a/hutool-core/src/test/java/cn/hutool/core/bean/copier/BeanCopierTest.java b/hutool-core/src/test/java/cn/hutool/core/bean/copier/BeanCopierTest.java index 369631104..54a113c32 100644 --- a/hutool-core/src/test/java/cn/hutool/core/bean/copier/BeanCopierTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/bean/copier/BeanCopierTest.java @@ -12,13 +12,13 @@ public class BeanCopierTest { public void beanToMapIgnoreNullTest() { final A a = new A(); - HashMap map = BeanCopier.create(a, new HashMap<>(), CopyOptions.create()).copy(); + HashMap map = BeanCopier.create(a, new HashMap<>(), CopyOptions.of()).copy(); Assert.assertEquals(1, map.size()); Assert.assertTrue(map.containsKey("value")); Assert.assertNull(map.get("value")); // 忽略null的情况下,空字段不写入map - map = BeanCopier.create(a, new HashMap<>(), CopyOptions.create().ignoreNullValue()).copy(); + map = BeanCopier.create(a, new HashMap<>(), CopyOptions.of().ignoreNullValue()).copy(); Assert.assertFalse(map.containsKey("value")); Assert.assertEquals(0, map.size()); } @@ -33,7 +33,7 @@ public class BeanCopierTest { final B b = new B(); b.setValue("abc"); - final BeanCopier copier = BeanCopier.create(a, b, CopyOptions.create().setOverride(false)); + final BeanCopier copier = BeanCopier.create(a, b, CopyOptions.of().setOverride(false)); copier.copy(); Assert.assertEquals("abc", b.getValue()); @@ -49,7 +49,7 @@ public class BeanCopierTest { final B b = new B(); b.setValue("abc"); - final BeanCopier copier = BeanCopier.create(a, b, CopyOptions.create()); + final BeanCopier copier = BeanCopier.create(a, b, CopyOptions.of()); copier.copy(); Assert.assertEquals("123", b.getValue()); diff --git a/hutool-core/src/test/java/cn/hutool/core/collection/PartitionIterTest.java b/hutool-core/src/test/java/cn/hutool/core/collection/PartitionIterTest.java index e4c02049c..4d11d678f 100644 --- a/hutool-core/src/test/java/cn/hutool/core/collection/PartitionIterTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/collection/PartitionIterTest.java @@ -3,7 +3,7 @@ package cn.hutool.core.collection; import cn.hutool.core.collection.iter.LineIter; import cn.hutool.core.collection.iter.PartitionIter; import cn.hutool.core.io.resource.ResourceUtil; -import cn.hutool.core.math.NumberUtil; +import cn.hutool.core.util.ArrayUtil; import org.junit.Assert; import org.junit.Test; @@ -26,7 +26,7 @@ public class PartitionIterTest { final PartitionIter iter = new PartitionIter<>(list.iterator(), 3); int max = 0; for (final List lines : iter) { - max = NumberUtil.max(max, NumberUtil.max(lines.toArray(new Integer[0]))); + max = ArrayUtil.max(max, ArrayUtil.max(lines.toArray(new Integer[0]))); } Assert.assertEquals(45, max); } diff --git a/hutool-core/src/test/java/cn/hutool/core/convert/ConvertToArrayTest.java b/hutool-core/src/test/java/cn/hutool/core/convert/ConvertToArrayTest.java index 0e96c964d..44fa3b833 100644 --- a/hutool-core/src/test/java/cn/hutool/core/convert/ConvertToArrayTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/convert/ConvertToArrayTest.java @@ -39,8 +39,8 @@ public class ConvertToArrayTest { public void toIntArrayTestIgnoreComponentErrorTest() { final String[] b = { "a", "1" }; - final ArrayConverter arrayConverter = new ArrayConverter(Integer[].class, true); - final Integer[] integerArray = (Integer[]) arrayConverter.convert(b, null); + final ArrayConverter arrayConverter = new ArrayConverter(true); + final Integer[] integerArray = arrayConverter.convert(Integer[].class, b, null); Assert.assertArrayEquals(integerArray, new Integer[]{null, 1}); } @@ -89,8 +89,8 @@ public class ConvertToArrayTest { //字符串转数组 final String arrayStr = "1,2,3,4,5"; //获取Converter类的方法2,自己实例化相应Converter对象 - final ArrayConverter c3 = new ArrayConverter(int[].class); - final int[] result3 = (int[]) c3.convert(arrayStr, null); + final ArrayConverter c3 = new ArrayConverter(); + final int[] result3 = c3.convert(int[].class, arrayStr, null); Assert.assertArrayEquals(new int[]{1,2,3,4,5}, result3); } diff --git a/hutool-core/src/test/java/cn/hutool/core/convert/ConvertToNumberTest.java b/hutool-core/src/test/java/cn/hutool/core/convert/ConvertToNumberTest.java index feeab7e80..931f661fb 100644 --- a/hutool-core/src/test/java/cn/hutool/core/convert/ConvertToNumberTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/convert/ConvertToNumberTest.java @@ -41,4 +41,11 @@ public class ConvertToNumberTest { bigDecimal = Convert.toBigDecimal("1L"); Assert.assertEquals(1L, bigDecimal.longValue()); } + + @Test + public void toNumberTest(){ + // 直接转换为抽象Number,默认使用BigDecimal实现 + final Number number = Convert.toNumber("1"); + Assert.assertEquals(BigDecimal.class, number.getClass()); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/convert/ConverterRegistryTest.java b/hutool-core/src/test/java/cn/hutool/core/convert/ConverterRegistryTest.java index 7fe2c7af3..4e96e9570 100644 --- a/hutool-core/src/test/java/cn/hutool/core/convert/ConverterRegistryTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/convert/ConverterRegistryTest.java @@ -3,6 +3,8 @@ package cn.hutool.core.convert; import org.junit.Assert; import org.junit.Test; +import java.lang.reflect.Type; + /** * ConverterRegistry 单元测试 * @author Looly @@ -12,7 +14,7 @@ public class ConverterRegistryTest { @Test public void getConverterTest() { - final Converter converter = ConverterRegistry.getInstance().getConverter(CharSequence.class, false); + final Converter converter = ConverterRegistry.getInstance().getConverter(CharSequence.class, false); Assert.assertNotNull(converter); } @@ -26,14 +28,14 @@ public class ConverterRegistryTest { //此处做为示例自定义CharSequence转换,因为Hutool中已经提供CharSequence转换,请尽量不要替换 //替换可能引发关联转换异常(例如覆盖CharSequence转换会影响全局) - converterRegistry.putCustom(CharSequence.class, CustomConverter.class); + converterRegistry.putCustom(CharSequence.class, new CustomConverter()); result = converterRegistry.convert(CharSequence.class, a); Assert.assertEquals("Custom: 454553", result); } - public static class CustomConverter implements Converter{ + public static class CustomConverter implements Converter{ @Override - public CharSequence convert(final Object value, final CharSequence defaultValue) throws IllegalArgumentException { + public Object convert(Type targetType, Object value) throws ConvertException { return "Custom: " + value.toString(); } } diff --git a/hutool-core/src/test/java/cn/hutool/core/convert/NumberConverterTest.java b/hutool-core/src/test/java/cn/hutool/core/convert/NumberConverterTest.java index 795d79fa1..3ed82e6a9 100644 --- a/hutool-core/src/test/java/cn/hutool/core/convert/NumberConverterTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/convert/NumberConverterTest.java @@ -8,15 +8,15 @@ public class NumberConverterTest { @Test public void toDoubleTest(){ - final NumberConverter numberConverter = new NumberConverter(Double.class); - final Number convert = numberConverter.convert("1,234.55", null); + final NumberConverter numberConverter = new NumberConverter(); + final Number convert = numberConverter.convert(Double.class, "1,234.55", null); Assert.assertEquals(1234.55D, convert); } @Test public void toIntegerTest(){ - final NumberConverter numberConverter = new NumberConverter(Integer.class); - final Number convert = numberConverter.convert("1,234.55", null); + final NumberConverter numberConverter = new NumberConverter(); + final Number convert = numberConverter.convert(Integer.class, "1,234.55", null); Assert.assertEquals(1234, convert); } } diff --git a/hutool-core/src/test/java/cn/hutool/core/math/MathUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/math/MathUtilTest.java new file mode 100644 index 000000000..b196b3dbf --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/math/MathUtilTest.java @@ -0,0 +1,44 @@ +package cn.hutool.core.math; + +import org.junit.Assert; +import org.junit.Test; + +import java.math.BigInteger; + +public class MathUtilTest { + @Test + public void factorialTest(){ + long factorial = MathUtil.factorial(0); + Assert.assertEquals(1, factorial); + + Assert.assertEquals(1L, MathUtil.factorial(1)); + Assert.assertEquals(1307674368000L, MathUtil.factorial(15)); + Assert.assertEquals(2432902008176640000L, MathUtil.factorial(20)); + + factorial = MathUtil.factorial(5, 0); + Assert.assertEquals(120, factorial); + factorial = MathUtil.factorial(5, 1); + Assert.assertEquals(120, factorial); + + Assert.assertEquals(5, MathUtil.factorial(5, 4)); + Assert.assertEquals(2432902008176640000L, MathUtil.factorial(20, 0)); + } + + @Test + public void factorialTest2(){ + long factorial = MathUtil.factorial(new BigInteger("0")).longValue(); + Assert.assertEquals(1, factorial); + + Assert.assertEquals(1L, MathUtil.factorial(new BigInteger("1")).longValue()); + Assert.assertEquals(1307674368000L, MathUtil.factorial(new BigInteger("15")).longValue()); + Assert.assertEquals(2432902008176640000L, MathUtil.factorial(20)); + + factorial = MathUtil.factorial(new BigInteger("5"), new BigInteger("0")).longValue(); + Assert.assertEquals(120, factorial); + factorial = MathUtil.factorial(new BigInteger("5"), BigInteger.ONE).longValue(); + Assert.assertEquals(120, factorial); + + Assert.assertEquals(5, MathUtil.factorial(new BigInteger("5"), new BigInteger("4")).longValue()); + Assert.assertEquals(2432902008176640000L, MathUtil.factorial(new BigInteger("20"), BigInteger.ZERO).longValue()); + } +} diff --git a/hutool-core/src/test/java/cn/hutool/core/util/ArrayUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/ArrayUtilTest.java index 5656f92df..5d9d2a798 100755 --- a/hutool-core/src/test/java/cn/hutool/core/util/ArrayUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/ArrayUtilTest.java @@ -167,27 +167,6 @@ public class ArrayUtilTest { Assert.assertEquals(values[2], cast[2]); } - @Test - public void rangeTest() { - final int[] range = ArrayUtil.range(0, 10); - Assert.assertEquals(0, range[0]); - Assert.assertEquals(1, range[1]); - Assert.assertEquals(2, range[2]); - Assert.assertEquals(3, range[3]); - Assert.assertEquals(4, range[4]); - Assert.assertEquals(5, range[5]); - Assert.assertEquals(6, range[6]); - Assert.assertEquals(7, range[7]); - Assert.assertEquals(8, range[8]); - Assert.assertEquals(9, range[9]); - } - - @Test(expected = NegativeArraySizeException.class) - public void rangeMinTest() { - //noinspection ResultOfMethodCallIgnored - ArrayUtil.range(0, Integer.MIN_VALUE); - } - @Test public void maxTest() { final int max = ArrayUtil.max(1, 2, 13, 4, 5); diff --git a/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java index d3607ce39..c89dc1f1e 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java @@ -1,15 +1,12 @@ package cn.hutool.core.util; -import cn.hutool.core.convert.Convert; import cn.hutool.core.lang.Console; import cn.hutool.core.math.NumberUtil; import org.junit.Assert; import org.junit.Test; import java.math.BigDecimal; -import java.math.BigInteger; import java.math.RoundingMode; -import java.util.Set; /** * {@link NumberUtil} 单元测试类 @@ -31,7 +28,7 @@ public class NumberUtilTest { public void addTest2() { final double a = 3.15f; final double b = 4.22; - final double result = NumberUtil.add(a, b); + final double result = NumberUtil.add(a, b).doubleValue(); Assert.assertEquals(7.37, result, 2); } @@ -45,7 +42,10 @@ public class NumberUtilTest { @Test public void addTest4() { - final BigDecimal result = NumberUtil.add(new BigDecimal("133"), new BigDecimal("331")); + BigDecimal result = NumberUtil.add(new BigDecimal("133"), new BigDecimal("331")); + Assert.assertEquals(new BigDecimal("464"), result); + + result = NumberUtil.add(new BigDecimal[]{new BigDecimal("133"), new BigDecimal("331")}); Assert.assertEquals(new BigDecimal("464"), result); } @@ -55,6 +55,30 @@ public class NumberUtilTest { Assert.assertEquals(new BigDecimal("123"), result); } + @Test + public void subTest() { + BigDecimal result = NumberUtil.sub(new BigDecimal("133"), new BigDecimal("331")); + Assert.assertEquals(new BigDecimal("-198"), result); + + result = NumberUtil.sub(new BigDecimal[]{new BigDecimal("133"), new BigDecimal("331")}); + Assert.assertEquals(new BigDecimal("-198"), result); + } + + @Test + public void mulTest() { + BigDecimal result = NumberUtil.mul(new BigDecimal("133"), new BigDecimal("331")); + Assert.assertEquals(new BigDecimal("44023"), result); + + result = NumberUtil.mul(new BigDecimal[]{new BigDecimal("133"), new BigDecimal("331")}); + Assert.assertEquals(new BigDecimal("44023"), result); + } + + @Test + public void mulNullTest(){ + final BigDecimal mul = NumberUtil.mul(new BigDecimal("10"), null); + Assert.assertEquals(BigDecimal.ZERO, mul); + } + @Test public void isIntegerTest() { Assert.assertTrue(NumberUtil.isInteger("-12")); @@ -90,7 +114,7 @@ public class NumberUtilTest { @Test public void divTest() { - final double result = NumberUtil.div(0, 1); + final double result = NumberUtil.div(0, 1).doubleValue(); Assert.assertEquals(0.0, result, 0); } @@ -177,7 +201,7 @@ public class NumberUtilTest { public void decimalFormatTest() { final long c = 299792458;// 光速 - final String format = NumberUtil.decimalFormat(",###", c); + final String format = NumberUtil.format(",###", c); Assert.assertEquals("299,792,458", format); } @@ -187,7 +211,7 @@ public class NumberUtilTest { final Double b = 0D; final Double c = a / b; - Console.log(NumberUtil.decimalFormat("#%", c)); + Console.log(NumberUtil.format("#%", c)); } @Test(expected = IllegalArgumentException.class) @@ -195,14 +219,14 @@ public class NumberUtilTest { final Double a = 0D; final Double b = 0D; - Console.log(NumberUtil.decimalFormat("#%", a / b)); + Console.log(NumberUtil.format("#%", a / b)); } @Test public void decimalFormatDoubleTest() { final Double c = 467.8101; - final String format = NumberUtil.decimalFormat("0.00", c); + final String format = NumberUtil.format("0.00", c); Assert.assertEquals("467.81", format); } @@ -210,11 +234,11 @@ public class NumberUtilTest { public void decimalFormatMoneyTest() { final double c = 299792400.543534534; - final String format = NumberUtil.decimalFormatMoney(c); + final String format = NumberUtil.formatMoney(c); Assert.assertEquals("299,792,400.54", format); final double value = 0.5; - final String money = NumberUtil.decimalFormatMoney(value); + final String money = NumberUtil.formatMoney(value); Assert.assertEquals("0.50", money); } @@ -237,18 +261,6 @@ public class NumberUtilTest { Assert.assertEquals("1234.56", bigDecimal.toString()); } - @Test - public void maxTest() { - final int max = NumberUtil.max(5,4,3,6,1); - Assert.assertEquals(6, max); - } - - @Test - public void minTest() { - final int min = NumberUtil.min(5,4,3,6,1); - Assert.assertEquals(1, min); - } - @Test public void parseIntTest() { int number = NumberUtil.parseInt("0xFF"); @@ -337,49 +349,6 @@ public class NumberUtilTest { Assert.assertEquals(0, number); } - @Test - public void factorialTest(){ - long factorial = NumberUtil.factorial(0); - Assert.assertEquals(1, factorial); - - Assert.assertEquals(1L, NumberUtil.factorial(1)); - Assert.assertEquals(1307674368000L, NumberUtil.factorial(15)); - Assert.assertEquals(2432902008176640000L, NumberUtil.factorial(20)); - - factorial = NumberUtil.factorial(5, 0); - Assert.assertEquals(120, factorial); - factorial = NumberUtil.factorial(5, 1); - Assert.assertEquals(120, factorial); - - Assert.assertEquals(5, NumberUtil.factorial(5, 4)); - Assert.assertEquals(2432902008176640000L, NumberUtil.factorial(20, 0)); - } - - @Test - public void factorialTest2(){ - long factorial = NumberUtil.factorial(new BigInteger("0")).longValue(); - Assert.assertEquals(1, factorial); - - Assert.assertEquals(1L, NumberUtil.factorial(new BigInteger("1")).longValue()); - Assert.assertEquals(1307674368000L, NumberUtil.factorial(new BigInteger("15")).longValue()); - Assert.assertEquals(2432902008176640000L, NumberUtil.factorial(20)); - - factorial = NumberUtil.factorial(new BigInteger("5"), new BigInteger("0")).longValue(); - Assert.assertEquals(120, factorial); - factorial = NumberUtil.factorial(new BigInteger("5"), BigInteger.ONE).longValue(); - Assert.assertEquals(120, factorial); - - Assert.assertEquals(5, NumberUtil.factorial(new BigInteger("5"), new BigInteger("4")).longValue()); - Assert.assertEquals(2432902008176640000L, NumberUtil.factorial(new BigInteger("20"), BigInteger.ZERO).longValue()); - } - - @Test - public void mulTest(){ - final BigDecimal mul = NumberUtil.mul(new BigDecimal("10"), null); - Assert.assertEquals(BigDecimal.ZERO, mul); - } - - @Test public void isPowerOfTwoTest() { Assert.assertFalse(NumberUtil.isPowerOfTwo(-1)); @@ -389,14 +358,6 @@ public class NumberUtilTest { Assert.assertFalse(NumberUtil.isPowerOfTwo(17)); } - @Test - public void generateRandomNumberTest(){ - final int[] ints = NumberUtil.generateRandomNumber(10, 20, 5); - Assert.assertEquals(5, ints.length); - final Set set = Convert.convert(Set.class, ints); - Assert.assertEquals(5, set.size()); - } - @Test public void toStrTest(){ Assert.assertEquals("1", NumberUtil.toStr(new BigDecimal("1.0000000000"))); @@ -405,15 +366,6 @@ public class NumberUtilTest { Assert.assertEquals("0", NumberUtil.toStr(new BigDecimal("9600.00000").subtract(new BigDecimal("9600.000000000")))); } - @Test - public void generateRandomNumberTest2(){ - // 检查边界 - final int[] ints = NumberUtil.generateRandomNumber(1, 8, 7); - Assert.assertEquals(7, ints.length); - final Set set = Convert.convert(Set.class, ints); - Assert.assertEquals(7, set.size()); - } - @Test public void toPlainNumberTest(){ final String num = "5344.34234e3"; @@ -421,12 +373,6 @@ public class NumberUtilTest { Assert.assertEquals("5344342.34", s); } - @Test - public void generateBySetTest(){ - final Integer[] integers = NumberUtil.generateBySet(10, 100, 5); - Assert.assertEquals(5, integers.length); - } - @Test public void isOddOrEvenTest(){ final int[] a = { 0, 32, -32, 123, -123 }; @@ -456,7 +402,7 @@ public class NumberUtilTest { @Test public void divIntegerTest(){ - final BigDecimal div = NumberUtil.div(100101300, (Number) 100); + final BigDecimal div = NumberUtil.div(100101300, 100); Assert.assertEquals(1001013, div.intValue()); } @@ -467,4 +413,25 @@ public class NumberUtilTest { Assert.assertFalse(NumberUtil.isDouble(" ")); } + @Test + public void rangeTest() { + final int[] range = NumberUtil.range(0, 10); + Assert.assertEquals(0, range[0]); + Assert.assertEquals(1, range[1]); + Assert.assertEquals(2, range[2]); + Assert.assertEquals(3, range[3]); + Assert.assertEquals(4, range[4]); + Assert.assertEquals(5, range[5]); + Assert.assertEquals(6, range[6]); + Assert.assertEquals(7, range[7]); + Assert.assertEquals(8, range[8]); + Assert.assertEquals(9, range[9]); + Assert.assertEquals(10, range[10]); + } + + @Test(expected = NegativeArraySizeException.class) + public void rangeMinTest() { + //noinspection ResultOfMethodCallIgnored + NumberUtil.range(0, Integer.MIN_VALUE); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/util/RandomUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/RandomUtilTest.java index 336d7b896..25c4c67a0 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/RandomUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/RandomUtilTest.java @@ -1,7 +1,9 @@ package cn.hutool.core.util; import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.convert.Convert; import cn.hutool.core.lang.Console; +import cn.hutool.core.math.NumberUtil; import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; @@ -72,4 +74,12 @@ public class RandomUtilTest { } } } + + @Test + public void generateRandomNumberTest(){ + final int[] ints = RandomUtil.randomPickInts(5, NumberUtil.range(5, 20)); + Assert.assertEquals(5, ints.length); + final Set set = Convert.convert(Set.class, ints); + Assert.assertEquals(5, set.size()); + } } diff --git a/hutool-extra/src/main/java/cn/hutool/extra/management/oshi/CpuInfo.java b/hutool-extra/src/main/java/cn/hutool/extra/management/oshi/CpuInfo.java index 946d6babf..5657868e0 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/management/oshi/CpuInfo.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/management/oshi/CpuInfo.java @@ -161,7 +161,7 @@ public class CpuInfo { * @return 总CPU使用率 */ public double getUsed() { - return NumberUtil.sub(100, this.free); + return NumberUtil.sub(100, this.free).doubleValue(); } @Override diff --git a/hutool-extra/src/main/java/cn/hutool/extra/servlet/JakartaServletUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/servlet/JakartaServletUtil.java index 8a4347fc7..737cf7ca9 100755 --- a/hutool-extra/src/main/java/cn/hutool/extra/servlet/JakartaServletUtil.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/servlet/JakartaServletUtil.java @@ -169,7 +169,7 @@ public class JakartaServletUtil { * @return Bean */ public static T fillBean(final ServletRequest request, final T bean, final boolean isIgnoreError) { - return fillBean(request, bean, CopyOptions.create().setIgnoreError(isIgnoreError)); + return fillBean(request, bean, CopyOptions.of().setIgnoreError(isIgnoreError)); } /** diff --git a/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java index 312fb379b..2b3f6eed8 100755 --- a/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java @@ -169,7 +169,7 @@ public class ServletUtil { * @return Bean */ public static T fillBean(final ServletRequest request, final T bean, final boolean isIgnoreError) { - return fillBean(request, bean, CopyOptions.create().setIgnoreError(isIgnoreError)); + return fillBean(request, bean, CopyOptions.of().setIgnoreError(isIgnoreError)); } /** diff --git a/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java b/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java index 9978ac9fd..869118446 100755 --- a/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java +++ b/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java @@ -59,8 +59,8 @@ public final class InternalJSONUtil { * @throws JSONException If the value is or contains an invalid number. */ static String valueToString(final Object value) throws JSONException { - if (value == null || value instanceof JSONNull) { - return JSONNull.NULL.toString(); + if (value == null) { + return StrUtil.NULL; } if (value instanceof JSONString) { try { @@ -94,7 +94,7 @@ public final class InternalJSONUtil { public static Object stringToValue(final String string) { // null处理 if (StrUtil.isEmpty(string) || StrUtil.NULL.equalsIgnoreCase(string)) { - return JSONNull.NULL; + return null; } // boolean处理 @@ -184,7 +184,7 @@ public final class InternalJSONUtil { * @since 5.8.0 */ static CopyOptions toCopyOptions(final JSONConfig config) { - return CopyOptions.create() + return CopyOptions.of() .setIgnoreCase(config.isIgnoreCase()) .setIgnoreError(config.isIgnoreError()) .setIgnoreNullValue(config.isIgnoreNullValue()) @@ -201,7 +201,7 @@ public final class InternalJSONUtil { static Map createRawMap(final int capacity, JSONConfig config) { final Map rawHashMap; if (null == config) { - config = JSONConfig.create(); + config = JSONConfig.of(); } final Comparator keyComparator = config.getKeyComparator(); if (config.isIgnoreCase()) { diff --git a/hutool-json/src/main/java/cn/hutool/json/JSON.java b/hutool-json/src/main/java/cn/hutool/json/JSON.java index 4d0cf063e..e06aaa72c 100755 --- a/hutool-json/src/main/java/cn/hutool/json/JSON.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSON.java @@ -36,7 +36,9 @@ public interface JSON extends Cloneable, Serializable { * @see BeanPath#get(Object) * @since 4.0.6 */ - Object getByPath(String expression); + default Object getByPath(String expression){ + return BeanPath.of(expression).get(this); + } /** * 设置表达式指定位置(或filed对应)的值
    @@ -59,7 +61,9 @@ public interface JSON extends Cloneable, Serializable { * @param expression 表达式 * @param value 值 */ - void putByPath(String expression, Object value); + default void putByPath(String expression, Object value){ + BeanPath.of(expression).set(this, value); + } /** * 通过表达式获取JSON中嵌套的对象
    diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONArray.java b/hutool-json/src/main/java/cn/hutool/json/JSONArray.java index 8f19bf523..5a04ac89e 100755 --- a/hutool-json/src/main/java/cn/hutool/json/JSONArray.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONArray.java @@ -1,11 +1,12 @@ package cn.hutool.json; -import cn.hutool.core.bean.BeanPath; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.convert.impl.ArrayConverter; import cn.hutool.core.lang.func.Filter; import cn.hutool.core.lang.mutable.Mutable; -import cn.hutool.core.lang.mutable.MutableObj; import cn.hutool.core.lang.mutable.MutableEntry; +import cn.hutool.core.lang.mutable.MutableObj; import cn.hutool.core.text.StrJoiner; import cn.hutool.core.util.ObjUtil; import cn.hutool.json.serialize.JSONWriter; @@ -66,7 +67,7 @@ public class JSONArray implements JSON, JSONGetter, List, Rando * @since 3.2.2 */ public JSONArray(final int initialCapacity) { - this(initialCapacity, JSONConfig.create()); + this(initialCapacity, JSONConfig.of()); } /** @@ -90,7 +91,7 @@ public class JSONArray implements JSON, JSONGetter, List, Rando */ public JSONArray(final int initialCapacity, final JSONConfig config) { this.rawList = new ArrayList<>(initialCapacity); - this.config = ObjUtil.defaultIfNull(config, JSONConfig::create); + this.config = ObjUtil.defaultIfNull(config, JSONConfig::of); } /** @@ -107,7 +108,7 @@ public class JSONArray implements JSON, JSONGetter, List, Rando * @throws JSONException 非数组或集合 */ public JSONArray(final Object object) throws JSONException { - this(object, JSONConfig.create()); + this(object, JSONConfig.of()); } /** @@ -190,19 +191,9 @@ public class JSONArray implements JSON, JSONGetter, List, Rando return (index < 0 || index >= this.size()) ? defaultValue : this.rawList.get(index); } - @Override - public Object getByPath(final String expression) { - return BeanPath.of(expression).get(this); - } - @Override public T getByPath(final String expression, final Class resultType) { - return JSONConverter.jsonConvert(resultType, getByPath(expression), true); - } - - @Override - public void putByPath(final String expression, final Object value) { - BeanPath.of(expression).set(this, value); + return JSONConverter.jsonConvert(resultType, getByPath(expression), this.config.isIgnoreError()); } /** @@ -332,7 +323,7 @@ public class JSONArray implements JSON, JSONGetter, List, Rando @Override @SuppressWarnings({"unchecked"}) public T[] toArray(final T[] a) { - return (T[]) JSONConverter.toArray(this, a.getClass().getComponentType()); + return (T[]) ArrayConverter.INSTANCE.convert(a.getClass().getComponentType(), this); } @Override @@ -374,6 +365,10 @@ public class JSONArray implements JSON, JSONGetter, List, Rando } final ArrayList list = new ArrayList<>(c.size()); for (final Object object : c) { + if(null == object && config.isIgnoreNullValue()){ + continue; + } + this.add(index); list.add(JSONUtil.wrap(object, this.config)); } return rawList.addAll(index, list); @@ -426,25 +421,36 @@ public class JSONArray implements JSON, JSONGetter, List, Rando } } + // 越界则追加到指定位置 if (index >= size()) { add(index, element); + return null; + } + if(null == element && config.isIgnoreNullValue()){ + return null; } return this.rawList.set(index, JSONUtil.wrap(element, this.config)); } @Override - public void add(final int index, final Object element) { - if (index < 0) { - throw new JSONException("JSONArray[{}] not found.", index); + public void add(int index, final Object element) { + if(null == element && config.isIgnoreNullValue()){ + return; } if (index < this.size()) { + if (index < 0) { + index = 0; + } InternalJSONUtil.testValidity(element); this.rawList.add(index, JSONUtil.wrap(element, this.config)); } else { - while (index != this.size()) { - this.add(JSONNull.NULL); + if(false == config.isIgnoreNullValue()){ + while (index != this.size()) { + // 非末尾,则填充null + this.add(null); + } } - this.set(element); + this.add(element); } } @@ -481,7 +487,7 @@ public class JSONArray implements JSON, JSONGetter, List, Rando * @return 实体类对象 */ public Object toArray(final Class arrayClass) { - return JSONConverter.toArray(this, arrayClass); + return ArrayConverter.INSTANCE.convert(arrayClass, this); } /** @@ -493,7 +499,7 @@ public class JSONArray implements JSON, JSONGetter, List, Rando * @since 3.0.8 */ public List toList(final Class elementType) { - return JSONConverter.toList(this, elementType); + return Convert.toList(elementType, this); } /** @@ -581,6 +587,10 @@ public class JSONArray implements JSON, JSONGetter, List, Rando return false; } } + if(null == obj && config.isIgnoreNullValue()){ + // 忽略空则不添加 + return false; + } return this.rawList.add(obj); } } diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONConfig.java b/hutool-json/src/main/java/cn/hutool/json/JSONConfig.java index dfc7d826d..811b63347 100755 --- a/hutool-json/src/main/java/cn/hutool/json/JSONConfig.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONConfig.java @@ -49,7 +49,7 @@ public class JSONConfig implements Serializable { * * @return JSONConfig */ - public static JSONConfig create() { + public static JSONConfig of() { return new JSONConfig(); } diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONConverter.java b/hutool-json/src/main/java/cn/hutool/json/JSONConverter.java index 126df29f3..990d902bb 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONConverter.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONConverter.java @@ -6,7 +6,6 @@ import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.ConvertException; import cn.hutool.core.convert.Converter; import cn.hutool.core.convert.ConverterRegistry; -import cn.hutool.core.convert.impl.ArrayConverter; import cn.hutool.core.convert.impl.BeanConverter; import cn.hutool.core.reflect.ConstructorUtil; import cn.hutool.core.reflect.TypeUtil; @@ -16,7 +15,6 @@ import cn.hutool.json.serialize.GlobalSerializeMapping; import cn.hutool.json.serialize.JSONDeserializer; import java.lang.reflect.Type; -import java.util.List; /** * JSON转换器 @@ -24,37 +22,21 @@ import java.util.List; * @author looly * @since 4.2.2 */ -public class JSONConverter implements Converter { +public class JSONConverter implements Converter { + + public static JSONConverter INSTANCE = new JSONConverter(); static { // 注册到转换中心 final ConverterRegistry registry = ConverterRegistry.getInstance(); - registry.putCustom(JSON.class, JSONConverter.class); - registry.putCustom(JSONObject.class, JSONConverter.class); - registry.putCustom(JSONArray.class, JSONConverter.class); + registry.putCustom(JSON.class, INSTANCE); + registry.putCustom(JSONObject.class, INSTANCE); + registry.putCustom(JSONArray.class, INSTANCE); } - /** - * JSONArray转数组 - * - * @param jsonArray JSONArray - * @param arrayClass 数组元素类型 - * @return 数组对象 - */ - protected static Object toArray(final JSONArray jsonArray, final Class arrayClass) { - return new ArrayConverter(arrayClass).convert(jsonArray, null); - } - - /** - * 将JSONArray转换为指定类型的对量列表 - * - * @param 元素类型 - * @param jsonArray JSONArray - * @param elementType 对象元素类型 - * @return 对象列表 - */ - protected static List toList(final JSONArray jsonArray, final Class elementType) { - return Convert.toList(elementType, jsonArray); + @Override + public Object convert(Type targetType, Object value) throws ConvertException { + return JSONUtil.parse(value); } /** @@ -71,7 +53,7 @@ public class JSONConverter implements Converter { */ @SuppressWarnings("unchecked") protected static T jsonConvert(final Type targetType, final Object value, final boolean ignoreError) throws ConvertException { - if (JSONUtil.isNull(value)) { + if (null == value) { return null; } @@ -109,7 +91,7 @@ public class JSONConverter implements Converter { */ @SuppressWarnings("unchecked") protected static T jsonToBean(final Type targetType, final Object value, final boolean ignoreError) throws ConvertException { - if (JSONUtil.isNull(value)) { + if (null == value) { return null; } @@ -124,9 +106,9 @@ public class JSONConverter implements Converter { if(value instanceof JSONGetter && targetType instanceof Class && BeanUtil.hasSetter((Class) targetType)){ final JSONConfig config = ((JSONGetter) value).getConfig(); - final Converter converter = new BeanConverter<>(targetType, - InternalJSONUtil.toCopyOptions(config).setIgnoreError(ignoreError)); - return converter.convertWithCheck(value, null, ignoreError); + final Converter converter = new BeanConverter(InternalJSONUtil.toCopyOptions(config).setIgnoreError(ignoreError)); + return ignoreError ? converter.convert(targetType, value, null) + : (T) converter.convert(targetType, value); } } @@ -144,9 +126,4 @@ public class JSONConverter implements Converter { return targetValue; } - - @Override - public JSON convert(final Object value, final JSON defaultValue) throws IllegalArgumentException { - return JSONUtil.parse(value); - } } diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONGetter.java b/hutool-json/src/main/java/cn/hutool/json/JSONGetter.java index 981e2e6fc..5efbdf656 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONGetter.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONGetter.java @@ -6,6 +6,7 @@ import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.lang.getter.OptNullBasicTypeFromObjectGetter; import cn.hutool.core.text.StrUtil; +import cn.hutool.core.util.ObjUtil; import java.time.LocalDateTime; import java.util.Date; @@ -32,10 +33,10 @@ public interface JSONGetter extends OptNullBasicTypeFromObjectGetter { * key对应值是否为{@code null}或无此key * * @param key 键 - * @return true 无此key或值为{@code null}或{@link JSONNull#NULL}返回{@code false},其它返回{@code true} + * @return true 无此key或值为{@code null}返回{@code false},其它返回{@code true} */ default boolean isNull(final K key) { - return JSONUtil.isNull(this.getObj(key)); + return ObjUtil.isNull(this.getObj(key)); } /** @@ -70,7 +71,7 @@ public interface JSONGetter extends OptNullBasicTypeFromObjectGetter { */ default JSONArray getJSONArray(final K key) { final Object object = this.getObj(key); - if (JSONUtil.isNull(object)) { + if (ObjUtil.isNull(object)) { return null; } @@ -89,7 +90,7 @@ public interface JSONGetter extends OptNullBasicTypeFromObjectGetter { */ default JSONObject getJSONObject(final K key) { final Object object = this.getObj(key); - if (JSONUtil.isNull(object)) { + if (ObjUtil.isNull(object)) { return null; } @@ -133,7 +134,7 @@ public interface JSONGetter extends OptNullBasicTypeFromObjectGetter { default Date getDate(final K key, final Date defaultValue) { // 默认转换 final Object obj = getObj(key); - if (JSONUtil.isNull(obj)) { + if (ObjUtil.isNull(obj)) { return defaultValue; } if (obj instanceof Date) { @@ -167,7 +168,7 @@ public interface JSONGetter extends OptNullBasicTypeFromObjectGetter { default LocalDateTime getLocalDateTime(final K key, final LocalDateTime defaultValue) { // 默认转换 final Object obj = getObj(key); - if (JSONUtil.isNull(obj)) { + if (ObjUtil.isNull(obj)) { return defaultValue; } if (obj instanceof LocalDateTime) { @@ -228,7 +229,7 @@ public interface JSONGetter extends OptNullBasicTypeFromObjectGetter { */ default T get(final K key, final Class type, final boolean ignoreError) throws ConvertException { final Object value = this.getObj(key); - if (JSONUtil.isNull(value)) { + if (ObjUtil.isNull(value)) { return null; } return JSONConverter.jsonConvert(type, value, ignoreError); diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONNull.java b/hutool-json/src/main/java/cn/hutool/json/JSONNull.java deleted file mode 100644 index 27a4442fa..000000000 --- a/hutool-json/src/main/java/cn/hutool/json/JSONNull.java +++ /dev/null @@ -1,46 +0,0 @@ -package cn.hutool.json; - -import cn.hutool.core.text.StrUtil; - -import java.io.Serializable; - -/** - * 用于定义{@code null},与Javascript中null相对应
    - * Java中的{@code null}值在js中表示为undefined。 - * - * @author Looly - */ -public class JSONNull implements Serializable { - private static final long serialVersionUID = 2633815155870764938L; - - /** - * {@code NULL} 对象用于减少歧义来表示Java 中的{@code null}
    - * {@code NULL.equals(null)} 返回 {@code true}.
    - * {@code NULL.toString()} 返回 {@code "null"}. - */ - public static final JSONNull NULL = new JSONNull(); - - /** - * A Null object is equal to the null value and to itself. - * 对象与其本身和{@code null}值相等 - * - * @param object An object to test for nullness. - * @return true if the object parameter is the JSONObject.NULL object or null. - */ - @SuppressWarnings("EqualsWhichDoesntCheckParameterClass") - @Override - public boolean equals(final Object object) { - return object == null || (object == this); - } - - /** - * Get the "null" string value. - * 获得“null”字符串 - * - * @return The string "null". - */ - @Override - public String toString() { - return StrUtil.NULL; - } -} diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONObject.java b/hutool-json/src/main/java/cn/hutool/json/JSONObject.java index c4521d0c7..99be5b560 100755 --- a/hutool-json/src/main/java/cn/hutool/json/JSONObject.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONObject.java @@ -1,6 +1,5 @@ package cn.hutool.json; -import cn.hutool.core.bean.BeanPath; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.func.Filter; import cn.hutool.core.lang.mutable.MutableEntry; @@ -46,7 +45,7 @@ public class JSONObject extends MapWrapper implements JSON, JSON * 构造,初始容量为 {@link #DEFAULT_CAPACITY},KEY有序 */ public JSONObject() { - this(JSONConfig.create()); + this(JSONConfig.of()); } /** @@ -67,8 +66,8 @@ public class JSONObject extends MapWrapper implements JSON, JSON * @since 4.1.19 */ public JSONObject(final int capacity, final JSONConfig config) { - super(InternalJSONUtil.createRawMap(capacity, ObjUtil.defaultIfNull(config, JSONConfig.create()))); - this.config = ObjUtil.defaultIfNull(config, JSONConfig.create()); + super(InternalJSONUtil.createRawMap(capacity, ObjUtil.defaultIfNull(config, JSONConfig.of()))); + this.config = ObjUtil.defaultIfNull(config, JSONConfig.of()); } /** @@ -84,7 +83,7 @@ public class JSONObject extends MapWrapper implements JSON, JSON * @param source JavaBean或者Map对象或者String */ public JSONObject(final Object source) { - this(source, JSONConfig.create().setIgnoreNullValue(InternalJSONUtil.defaultIgnoreNullValue(source))); + this(source, JSONConfig.of().setIgnoreNullValue(InternalJSONUtil.defaultIgnoreNullValue(source))); } /** @@ -182,19 +181,9 @@ public class JSONObject extends MapWrapper implements JSON, JSON return this.getOrDefault(key, defaultValue); } - @Override - public Object getByPath(final String expression) { - return BeanPath.of(expression).get(this); - } - @Override public T getByPath(final String expression, final Class resultType) { - return JSONConverter.jsonConvert(resultType, getByPath(expression), true); - } - - @Override - public void putByPath(final String expression, final Object value) { - BeanPath.of(expression).set(this, value); + return JSONConverter.jsonConvert(resultType, getByPath(expression), this.config.isIgnoreError()); } /** @@ -219,7 +208,23 @@ public class JSONObject extends MapWrapper implements JSON, JSON * @throws JSONException 值是无穷数字抛出此异常 */ public JSONObject set(final String key, final Object value) throws JSONException { - return set(key, value, null, false); + put(key, value, null, false); + return this; + } + + /** + * 一次性Put 键值对,如果key已经存在抛出异常,如果键值中有null值,忽略 + * + * @param key 键 + * @param value 值对象,可以是以下类型: Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL. + * @param filter 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@code null}表示不过滤 + * @return this + * @throws JSONException 值是无穷数字、键重复抛出异常 + * @since 5.8.0 + */ + public JSONObject setOnce(final String key, final Object value, final Filter> filter) throws JSONException { + put(key, value, filter, true); + return this; } /** @@ -238,32 +243,6 @@ public class JSONObject extends MapWrapper implements JSON, JSON return this; } - /** - * 一次性Put 键值对,如果key已经存在抛出异常,如果键值中有null值,忽略 - * - * @param key 键 - * @param value 值对象,可以是以下类型: Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL. - * @return this. - * @throws JSONException 值是无穷数字、键重复抛出异常 - */ - public JSONObject putOnce(final String key, final Object value) throws JSONException { - return setOnce(key, value, null); - } - - /** - * 一次性Put 键值对,如果key已经存在抛出异常,如果键值中有null值,忽略 - * - * @param key 键 - * @param value 值对象,可以是以下类型: Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL. - * @param filter 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@code null}表示不过滤 - * @return this - * @throws JSONException 值是无穷数字、键重复抛出异常 - * @since 5.8.0 - */ - public JSONObject setOnce(final String key, final Object value, final Filter> filter) throws JSONException { - return set(key, value, filter, true); - } - /** * 在键和值都为非空的情况下put到JSONObject中 * @@ -272,7 +251,7 @@ public class JSONObject extends MapWrapper implements JSON, JSON * @return this. * @throws JSONException 值是无穷数字 */ - public JSONObject putOpt(final String key, final Object value) throws JSONException { + public JSONObject setOpt(final String key, final Object value) throws JSONException { if (key != null && value != null) { this.set(key, value); } @@ -287,29 +266,12 @@ public class JSONObject extends MapWrapper implements JSON, JSON } /** - * 积累值。类似于set,当key对应value已经存在时,与value组成新的JSONArray.
    - * 如果只有一个值,此值就是value,如果多个值,则是添加到新的JSONArray中 - * - * @param key 键 - * @param value 被积累的值 - * @return this. - * @throws JSONException 如果给定键为{@code null}或者键对应的值存在且为非JSONArray - */ - public JSONObject accumulate(final String key, final Object value) throws JSONException { - InternalJSONUtil.testValidity(value); - final Object object = this.getObj(key); - if (object == null) { - this.set(key, value); - } else if (object instanceof JSONArray) { - ((JSONArray) object).set(value); - } else { - this.set(key, JSONUtil.createArray(this.config).set(object).set(value)); - } - return this; - } - - /** - * 追加值,如果key无对应值,就添加一个JSONArray,其元素只有value,如果值已经是一个JSONArray,则添加到值JSONArray中。 + * 追加值. + *
      + *
    • 如果键值对不存在或对应值为{@code null},则value为单独值
    • + *
    • 如果值是一个{@link JSONArray},追加之
    • + *
    • 如果值是一个其他值,则和旧值共同组合为一个{@link JSONArray}
    • + *
    * * @param key 键 * @param value 值 @@ -320,11 +282,11 @@ public class JSONObject extends MapWrapper implements JSON, JSON InternalJSONUtil.testValidity(value); final Object object = this.getObj(key); if (object == null) { - this.set(key, new JSONArray(this.config).set(value)); + this.set(key, value); } else if (object instanceof JSONArray) { - this.set(key, ((JSONArray) object).set(value)); + ((JSONArray) object).set(value); } else { - throw new JSONException("JSONObject [" + key + "] is not a JSONArray."); + this.set(key, JSONUtil.createArray(this.config).set(object).set(value)); } return this; } @@ -435,13 +397,13 @@ public class JSONObject extends MapWrapper implements JSON, JSON * @param value 值对象. 可以是以下类型: Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL. * @param filter 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@code null}表示不过滤 * @param checkDuplicate 是否检查重复键,如果为{@code true},则出现重复键时抛出{@link JSONException}异常 - * @return this. + * @return 旧值 * @throws JSONException 值是无穷数字抛出此异常 * @since 5.8.0 */ private Object put(String key, Object value, final Filter> filter, final boolean checkDuplicate) throws JSONException { if (null == key) { - return this; + return null; } // 添加前置过滤,通过MutablePair实现过滤、修改键值对等 @@ -453,12 +415,12 @@ public class JSONObject extends MapWrapper implements JSON, JSON value = pair.getValue(); } else { // 键值对被过滤 - return this; + return null; } } final boolean ignoreNullValue = this.config.isIgnoreNullValue(); - if (ObjUtil.isNull(value) && ignoreNullValue) { + if (null == value && ignoreNullValue) { // 忽略值模式下如果值为空清除key return this.remove(key); } else if (checkDuplicate && containsKey(key)) { diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONParser.java b/hutool-json/src/main/java/cn/hutool/json/JSONParser.java index f79c90c5e..15c766b06 100755 --- a/hutool-json/src/main/java/cn/hutool/json/JSONParser.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONParser.java @@ -106,7 +106,7 @@ public class JSONParser { for (; ; ) { if (x.nextClean() == ',') { x.back(); - jsonArray.addRaw(JSONNull.NULL, filter); + jsonArray.addRaw(null, filter); } else { x.back(); jsonArray.addRaw(x.nextValue(), filter); diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java b/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java index e86c0c30f..22bd82894 100755 --- a/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java @@ -411,7 +411,7 @@ public class JSONTokener { while (true) { if (this.nextClean() == ',') { this.back(); - jsonArray.add(JSONNull.NULL); + jsonArray.add(null); } else { this.back(); jsonArray.add(this.nextValue()); diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONUtil.java b/hutool-json/src/main/java/cn/hutool/json/JSONUtil.java index de0289c43..bfbb221d0 100755 --- a/hutool-json/src/main/java/cn/hutool/json/JSONUtil.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONUtil.java @@ -113,7 +113,7 @@ public class JSONUtil { * @since 3.0.9 */ public static JSONObject parseObj(final Object obj, final boolean ignoreNullValue) { - return new JSONObject(obj, JSONConfig.create().setIgnoreNullValue(ignoreNullValue)); + return new JSONObject(obj, JSONConfig.of().setIgnoreNullValue(ignoreNullValue)); } /** @@ -148,7 +148,7 @@ public class JSONUtil { * @since 3.2.3 */ public static JSONArray parseArray(final Object arrayOrCollection, final boolean ignoreNullValue) { - return new JSONArray(arrayOrCollection, JSONConfig.create().setIgnoreNullValue(ignoreNullValue)); + return new JSONArray(arrayOrCollection, JSONConfig.of().setIgnoreNullValue(ignoreNullValue)); } /** @@ -286,7 +286,7 @@ public class JSONUtil { /** * 转为JSON字符串,并写出到write * - * @param json JSON + * @param json JSON * @param writer Writer * @since 5.3.3 */ @@ -322,7 +322,7 @@ public class JSONUtil { /** * 转换为JSON字符串 * - * @param obj 被转为JSON的对象 + * @param obj 被转为JSON的对象 * @param jsonConfig JSON配置 * @return JSON字符串 * @since 5.7.12 @@ -340,7 +340,7 @@ public class JSONUtil { /** * 转换为JSON字符串并写出到writer * - * @param obj 被转为JSON的对象 + * @param obj 被转为JSON的对象 * @param writer Writer * @since 5.3.3 */ @@ -438,7 +438,7 @@ public class JSONUtil { * @since 4.3.2 */ public static T toBean(final String jsonString, final Type beanType, final boolean ignoreError) { - return parse(jsonString, JSONConfig.create().setIgnoreError(ignoreError)).toBean(beanType); + return parse(jsonString, JSONConfig.of().setIgnoreError(ignoreError)).toBean(beanType); } /** @@ -540,9 +540,9 @@ public class JSONUtil { * person.friends[5].name * * - * @param 值类型 - * @param json {@link JSON} - * @param expression 表达式 + * @param 值类型 + * @param json {@link JSON} + * @param expression 表达式 * @param defaultValue 默认值 * @return 对象 * @see JSON#getByPath(String) @@ -550,11 +550,11 @@ public class JSONUtil { */ @SuppressWarnings("unchecked") public static T getByPath(final JSON json, final String expression, final T defaultValue) { - if((null == json || StrUtil.isBlank(expression))){ + if ((null == json || StrUtil.isBlank(expression))) { return defaultValue; } - if(null != defaultValue){ + if (null != defaultValue) { final Class type = (Class) defaultValue.getClass(); return ObjUtil.defaultIfNull(json.getByPath(expression, type), defaultValue); } @@ -701,7 +701,6 @@ public class JSONUtil { * 在需要的时候包装对象
    * 包装包括: *
      - *
    • {@code null} =》 {@code JSONNull.NULL}
    • *
    • array or collection =》 JSONArray
    • *
    • map =》 JSONObject
    • *
    • standard property (Double, String, et al) =》 原对象
    • @@ -716,10 +715,9 @@ public class JSONUtil { @SuppressWarnings({"rawtypes", "unchecked"}) public static Object wrap(final Object object, final JSONConfig jsonConfig) { if (object == null) { - return jsonConfig.isIgnoreNullValue() ? null : JSONNull.NULL; + return null; } if (object instanceof JSON // - || ObjUtil.isNull(object) // || object instanceof JSONString // || object instanceof CharSequence // || object instanceof Number // @@ -743,13 +741,13 @@ public class JSONUtil { try { // fix issue#1399@Github - if(object instanceof SQLException){ + if (object instanceof SQLException) { return object.toString(); } // JSONArray if (object instanceof Iterable || ArrayUtil.isArray(object)) { - if(object instanceof byte[]){ + if (object instanceof byte[]) { // issue#I59LW4 // json内容中的bytes默认转为Base64 return Base64.encode((byte[]) object); @@ -836,22 +834,6 @@ public class JSONUtil { return StrUtil.isWrap(StrUtil.trim(str), '[', ']'); } - /** - * 是否为null对象,null的情况包括: - * - *
      -	 * 1. {@code null}
      -	 * 2. {@link JSONNull}
      -	 * 
      - * - * @param obj 对象 - * @return 是否为null - * @since 4.5.7 - */ - public static boolean isNull(final Object obj) { - return null == obj || obj instanceof JSONNull; - } - /** * XML转JSONObject
      * 转换过程中一些信息可能会丢失,JSON中无法区分节点和属性,相同的节点将被处理为JSONArray。 diff --git a/hutool-json/src/main/java/cn/hutool/json/ObjectMapper.java b/hutool-json/src/main/java/cn/hutool/json/ObjectMapper.java index f012609fa..cc8592c2e 100755 --- a/hutool-json/src/main/java/cn/hutool/json/ObjectMapper.java +++ b/hutool-json/src/main/java/cn/hutool/json/ObjectMapper.java @@ -1,6 +1,7 @@ package cn.hutool.json; import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.bean.copier.CopyOptions; import cn.hutool.core.collection.iter.ArrayIter; import cn.hutool.core.convert.Convert; import cn.hutool.core.io.IoUtil; @@ -110,8 +111,7 @@ public class ObjectMapper { mapFromResourceBundle((ResourceBundle) source, jsonObject, filter); } else if (BeanUtil.isReadableBean(source.getClass())) { // 普通Bean - // TODO 过滤器对Bean无效,需补充。 - mapFromBean(source, jsonObject); + mapFromBean(source, jsonObject, filter); } else { // 不支持对象类型转换为JSONObject throw new JSONException("Unsupported type [{}] to JSONObject!", source.getClass()); @@ -119,7 +119,7 @@ public class ObjectMapper { } /** - * 初始化 + * 将给定对象转换为{@link JSONArray} * * @param jsonArray 目标{@link JSONArray} * @param filter 键值对过滤编辑器,可以通过实现此接口,完成解析前对值的过滤和修改操作,{@code null}表示不过滤 @@ -139,7 +139,7 @@ public class ObjectMapper { } else if (source instanceof CharSequence) { // JSON字符串 mapFromStr((CharSequence) source, jsonArray, filter); - }else if (source instanceof Reader) { + } else if (source instanceof Reader) { mapFromTokener(new JSONTokener((Reader) source, jsonArray.getConfig()), jsonArray, filter); } else if (source instanceof InputStream) { mapFromTokener(new JSONTokener((InputStream) source, jsonArray.getConfig()), jsonArray, filter); @@ -248,7 +248,11 @@ public class ObjectMapper { * @param bean Bean对象 * @param jsonObject {@link JSONObject} */ - private static void mapFromBean(final Object bean, final JSONObject jsonObject) { - BeanUtil.beanToMap(bean, jsonObject, InternalJSONUtil.toCopyOptions(jsonObject.getConfig())); + private static void mapFromBean(final Object bean, final JSONObject jsonObject, final Filter> filter) { + final CopyOptions copyOptions = InternalJSONUtil.toCopyOptions(jsonObject.getConfig()); + if(null != filter){ + copyOptions.setFieldEditor((entry -> filter.accept(entry) ? entry : null)); + } + BeanUtil.beanToMap(bean, jsonObject, copyOptions); } } diff --git a/hutool-json/src/main/java/cn/hutool/json/jwt/Claims.java b/hutool-json/src/main/java/cn/hutool/json/jwt/Claims.java index 0da7e9348..aade47c62 100755 --- a/hutool-json/src/main/java/cn/hutool/json/jwt/Claims.java +++ b/hutool-json/src/main/java/cn/hutool/json/jwt/Claims.java @@ -21,7 +21,7 @@ public class Claims implements Serializable { private static final long serialVersionUID = 1L; // 时间使用秒级时间戳表示 - private final JSONConfig CONFIG = JSONConfig.create().setDateFormat("#sss"); + private final JSONConfig CONFIG = JSONConfig.of().setDateFormat("#sss"); private JSONObject claimJSON; diff --git a/hutool-json/src/main/java/cn/hutool/json/serialize/JSONWriter.java b/hutool-json/src/main/java/cn/hutool/json/serialize/JSONWriter.java index 9fde0e255..8ddb3876c 100755 --- a/hutool-json/src/main/java/cn/hutool/json/serialize/JSONWriter.java +++ b/hutool-json/src/main/java/cn/hutool/json/serialize/JSONWriter.java @@ -14,7 +14,6 @@ import cn.hutool.json.JSON; import cn.hutool.json.JSONArray; import cn.hutool.json.JSONConfig; import cn.hutool.json.JSONException; -import cn.hutool.json.JSONNull; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONString; import cn.hutool.json.JSONUtil; @@ -96,6 +95,7 @@ public class JSONWriter extends Writer { * @return this */ public JSONWriter beginObj() { + //noinspection resource writeRaw(CharUtil.DELIM_START); return this; } @@ -106,6 +106,7 @@ public class JSONWriter extends Writer { * @return this */ public JSONWriter beginArray() { + //noinspection resource writeRaw(CharUtil.BRACKET_START); arrayMode = true; return this; @@ -118,7 +119,9 @@ public class JSONWriter extends Writer { */ public JSONWriter end() { // 换行缩进 + //noinspection resource writeLF().writeSpace(indent); + //noinspection resource writeRaw(arrayMode ? CharUtil.BRACKET_END : CharUtil.DELIM_END); flush(); arrayMode = false; @@ -135,22 +138,24 @@ public class JSONWriter extends Writer { */ public JSONWriter writeKey(final String key) { if (needSeparator) { + //noinspection resource writeRaw(CharUtil.COMMA); } // 换行缩进 + //noinspection resource writeLF().writeSpace(indentFactor + indent); return writeRaw(JSONUtil.quote(key)); } /** * 写出值,自动处理分隔符和缩进,自动判断类型,并根据不同类型写出特定格式的值
      - * 如果写出的值为{@code null}或者{@link JSONNull},且配置忽略null,则跳过。 + * 如果写出的值为{@code null},且配置忽略null,则跳过。 * * @param value 值 * @return this */ public JSONWriter writeValue(final Object value) { - if(JSONUtil.isNull(value) && config.isIgnoreNullValue()){ + if (null == value && config.isIgnoreNullValue()) { return this; } return writeValueDirect(value); @@ -159,16 +164,17 @@ public class JSONWriter extends Writer { /** * 写出字段名及字段值,如果字段值是{@code null}且忽略null值,则不写出任何内容 * - * @param key 字段名 + * @param key 字段名 * @param value 字段值 * @return this * @since 5.7.6 */ - public JSONWriter writeField(final String key, final Object value){ - if(JSONUtil.isNull(value) && config.isIgnoreNullValue()){ + public JSONWriter writeField(final String key, final Object value) { + if (null == value && config.isIgnoreNullValue()) { return this; } + //noinspection resource return writeKey(key).writeValueDirect(value); } @@ -192,6 +198,7 @@ public class JSONWriter extends Writer { } // ------------------------------------------------------------------------------ Private methods + /** * 写出值,自动处理分隔符和缩进,自动判断类型,并根据不同类型写出特定格式的值 * @@ -201,11 +208,14 @@ public class JSONWriter extends Writer { private JSONWriter writeValueDirect(final Object value) { if (arrayMode) { if (needSeparator) { + //noinspection resource writeRaw(CharUtil.COMMA); } // 换行缩进 + //noinspection resource writeLF().writeSpace(indentFactor + indent); } else { + //noinspection resource writeRaw(CharUtil.COLON).writeSpace(1); } needSeparator = true; @@ -220,24 +230,26 @@ public class JSONWriter extends Writer { */ private JSONWriter writeObjValue(final Object value) { final int indent = indentFactor + this.indent; - if (value == null || value instanceof JSONNull) { - writeRaw(JSONNull.NULL.toString()); + if (value == null) { + //noinspection resource + writeRaw(StrUtil.NULL); } else if (value instanceof JSON) { ((JSON) value).write(writer, indentFactor, indent); } else if (value instanceof Map || value instanceof Map.Entry) { new JSONObject(value).write(writer, indentFactor, indent); } else if (value instanceof Iterable || value instanceof Iterator || ArrayUtil.isArray(value)) { - if(value instanceof byte[]){ + if (value instanceof byte[]) { // issue#I59LW4 // json内容中的bytes默认转为Base64 writeStrValue(Base64.encode((byte[]) value)); - }else{ + } else { new JSONArray(value).write(writer, indentFactor, indent); } } else if (value instanceof Number) { writeNumberValue((Number) value); } else if (value instanceof Date || value instanceof Calendar || value instanceof TemporalAccessor) { final String format = (null == config) ? null : config.getDateFormat(); + //noinspection resource writeRaw(formatDate(value, format)); } else if (value instanceof Boolean) { writeBooleanValue((Boolean) value); @@ -260,6 +272,7 @@ public class JSONWriter extends Writer { private void writeNumberValue(final Number number) { // since 5.6.2可配置是否去除末尾多余0,例如如果为true,5.0返回5 final boolean isStripTrailingZeros = null == config || config.isStripTrailingZeros(); + //noinspection resource writeRaw(NumberUtil.toStr(number, isStripTrailingZeros)); } @@ -269,6 +282,7 @@ public class JSONWriter extends Writer { * @param value Boolean值 */ private void writeBooleanValue(final Boolean value) { + //noinspection resource writeRaw(value.toString()); } @@ -287,6 +301,7 @@ public class JSONWriter extends Writer { throw new JSONException(e); } if (null != valueStr) { + //noinspection resource writeRaw(valueStr); } else { writeStrValue(jsonString.toString()); @@ -317,6 +332,7 @@ public class JSONWriter extends Writer { private void writeSpace(final int count) { if (indentFactor > 0) { for (int i = 0; i < count; i++) { + //noinspection resource writeRaw(CharUtil.SPACE); } } @@ -329,6 +345,7 @@ public class JSONWriter extends Writer { */ private JSONWriter writeLF() { if (indentFactor > 0) { + //noinspection resource writeRaw(CharUtil.LF); } return this; diff --git a/hutool-json/src/main/java/cn/hutool/json/xml/JSONXMLParser.java b/hutool-json/src/main/java/cn/hutool/json/xml/JSONXMLParser.java index 28f2ab225..d50a4bef7 100644 --- a/hutool-json/src/main/java/cn/hutool/json/xml/JSONXMLParser.java +++ b/hutool-json/src/main/java/cn/hutool/json/xml/JSONXMLParser.java @@ -1,5 +1,6 @@ package cn.hutool.json.xml; +import cn.hutool.core.text.StrUtil; import cn.hutool.json.InternalJSONUtil; import cn.hutool.json.JSONException; import cn.hutool.json.JSONObject; @@ -63,7 +64,7 @@ public class JSONXMLParser { if (x.next() == '[') { string = x.nextCDATA(); if (string.length() > 0) { - context.accumulate("content", string); + context.append("content", string); } return false; } @@ -126,10 +127,10 @@ public class JSONXMLParser { if (!(token instanceof String)) { throw x.syntaxError("Missing value"); } - jsonobject.accumulate(string, keepStrings ? token : InternalJSONUtil.stringToValue((String) token)); + jsonobject.append(string, keepStrings ? token : InternalJSONUtil.stringToValue((String) token)); token = null; } else { - jsonobject.accumulate(string, ""); + jsonobject.append(string, ""); } } else if (token == XML.SLASH) { @@ -138,9 +139,9 @@ public class JSONXMLParser { throw x.syntaxError("Misshaped tag"); } if (jsonobject.size() > 0) { - context.accumulate(tagName, jsonobject); + context.append(tagName, jsonobject); } else { - context.accumulate(tagName, ""); + context.append(tagName, StrUtil.EMPTY); } return false; @@ -156,18 +157,18 @@ public class JSONXMLParser { } else if (token instanceof String) { string = (String) token; if (string.length() > 0) { - jsonobject.accumulate("content", keepStrings ? token : InternalJSONUtil.stringToValue(string)); + jsonobject.append("content", keepStrings ? token : InternalJSONUtil.stringToValue(string)); } } else if (token == XML.LT) { // Nested element if (parse(x, jsonobject, tagName, keepStrings)) { if (jsonobject.size() == 0) { - context.accumulate(tagName, ""); + context.append(tagName, ""); } else if (jsonobject.size() == 1 && jsonobject.get("content") != null) { - context.accumulate(tagName, jsonobject.get("content")); + context.append(tagName, jsonobject.get("content")); } else { - context.accumulate(tagName, jsonobject); + context.append(tagName, jsonobject); } return false; } diff --git a/hutool-json/src/test/java/cn/hutool/json/Issue1075Test.java b/hutool-json/src/test/java/cn/hutool/json/Issue1075Test.java index 96f0c685d..bfd4edd05 100644 --- a/hutool-json/src/test/java/cn/hutool/json/Issue1075Test.java +++ b/hutool-json/src/test/java/cn/hutool/json/Issue1075Test.java @@ -19,7 +19,7 @@ public class Issue1075Test { @Test public void testToBeanIgnoreCase() { // 在忽略大小写的情况下,f2、fac都匹配 - final ObjA o2 = JSONUtil.parseObj(jsonStr, JSONConfig.create().setIgnoreCase(true)).toBean(ObjA.class); + final ObjA o2 = JSONUtil.parseObj(jsonStr, JSONConfig.of().setIgnoreCase(true)).toBean(ObjA.class); Assert.assertEquals("fac", o2.getFAC()); Assert.assertEquals("f2", o2.getF2()); diff --git a/hutool-json/src/test/java/cn/hutool/json/Issue2223Test.java b/hutool-json/src/test/java/cn/hutool/json/Issue2223Test.java index ee8126021..327c81015 100755 --- a/hutool-json/src/test/java/cn/hutool/json/Issue2223Test.java +++ b/hutool-json/src/test/java/cn/hutool/json/Issue2223Test.java @@ -23,12 +23,12 @@ public class Issue2223Test { map1.put("m1", m1); Assert.assertEquals("{\"m1\":{\"2022/0\":0,\"2022/1\":1,\"2022/2\":2,\"2022/3\":3,\"2022/4\":4}}", - JSONUtil.toJsonStr(map1, JSONConfig.create())); + JSONUtil.toJsonStr(map1, JSONConfig.of())); final BeanDemo beanDemo = new BeanDemo(); beanDemo.setMap1(map1); Assert.assertEquals("{\"map1\":{\"m1\":{\"2022/0\":0,\"2022/1\":1,\"2022/2\":2,\"2022/3\":3,\"2022/4\":4}}}", - JSONUtil.toJsonStr(beanDemo, JSONConfig.create())); + JSONUtil.toJsonStr(beanDemo, JSONConfig.of())); } @Data diff --git a/hutool-json/src/test/java/Issue2365Test.java b/hutool-json/src/test/java/cn/hutool/json/Issue2365Test.java similarity index 95% rename from hutool-json/src/test/java/Issue2365Test.java rename to hutool-json/src/test/java/cn/hutool/json/Issue2365Test.java index 2b16fea50..c5785d7c5 100644 --- a/hutool-json/src/test/java/Issue2365Test.java +++ b/hutool-json/src/test/java/cn/hutool/json/Issue2365Test.java @@ -1,3 +1,5 @@ +package cn.hutool.json; + import cn.hutool.json.JSONUtil; import lombok.Data; import org.junit.Assert; diff --git a/hutool-json/src/test/java/cn/hutool/json/IssueI4RBZ4Test.java b/hutool-json/src/test/java/cn/hutool/json/IssueI4RBZ4Test.java index 6ef5586fc..7fa39184a 100755 --- a/hutool-json/src/test/java/cn/hutool/json/IssueI4RBZ4Test.java +++ b/hutool-json/src/test/java/cn/hutool/json/IssueI4RBZ4Test.java @@ -12,7 +12,7 @@ public class IssueI4RBZ4Test { public void sortTest(){ final String jsonStr = "{\"id\":\"123\",\"array\":[1,2,3],\"outNum\":356,\"body\":{\"ava1\":\"20220108\",\"use\":1,\"ava2\":\"20230108\"},\"name\":\"John\"}"; - final JSONObject jsonObject = JSONUtil.parseObj(jsonStr, JSONConfig.create().setNatureKeyComparator()); + final JSONObject jsonObject = JSONUtil.parseObj(jsonStr, JSONConfig.of().setNatureKeyComparator()); Assert.assertEquals("{\"array\":[1,2,3],\"body\":{\"ava1\":\"20220108\",\"ava2\":\"20230108\",\"use\":1},\"id\":\"123\",\"name\":\"John\",\"outNum\":356}", jsonObject.toString()); } } diff --git a/hutool-json/src/test/java/cn/hutool/json/IssueI50EGGTest.java b/hutool-json/src/test/java/cn/hutool/json/IssueI50EGGTest.java index 348b5b7c0..699f48383 100755 --- a/hutool-json/src/test/java/cn/hutool/json/IssueI50EGGTest.java +++ b/hutool-json/src/test/java/cn/hutool/json/IssueI50EGGTest.java @@ -10,7 +10,7 @@ public class IssueI50EGGTest { @Test public void toBeanTest(){ final String data = "{\"return_code\": 1, \"return_msg\": \"成功\", \"return_data\" : null}"; - final ApiResult apiResult = JSONUtil.toBean(data, JSONConfig.create().setIgnoreCase(true), ApiResult.class); + final ApiResult apiResult = JSONUtil.toBean(data, JSONConfig.of().setIgnoreCase(true), ApiResult.class); Assert.assertEquals(1, apiResult.getReturn_code()); } diff --git a/hutool-json/src/test/java/cn/hutool/json/JSONArrayTest.java b/hutool-json/src/test/java/cn/hutool/json/JSONArrayTest.java index e56fe9517..a88bfb8e2 100755 --- a/hutool-json/src/test/java/cn/hutool/json/JSONArrayTest.java +++ b/hutool-json/src/test/java/cn/hutool/json/JSONArrayTest.java @@ -31,11 +31,11 @@ public class JSONArrayTest { // JSONObject实现了Iterable接口,可以转换为JSONArray final JSONObject jsonObject = new JSONObject(); - JSONArray jsonArray = new JSONArray(jsonObject, JSONConfig.create()); + JSONArray jsonArray = new JSONArray(jsonObject, JSONConfig.of()); Assert.assertEquals(new JSONArray(), jsonArray); jsonObject.set("key1", "value1"); - jsonArray = new JSONArray(jsonObject, JSONConfig.create()); + jsonArray = new JSONArray(jsonObject, JSONConfig.of()); Assert.assertEquals(1, jsonArray.size()); Assert.assertEquals("[{\"key1\":\"value1\"}]", jsonArray.toString()); } @@ -44,7 +44,7 @@ public class JSONArrayTest { public void addNullTest(){ final List aaa = ListUtil.view("aaa", null); final String jsonStr = JSONUtil.toJsonStr(JSONUtil.parse(aaa, - JSONConfig.create().setIgnoreNullValue(false))); + JSONConfig.of().setIgnoreNullValue(false))); Assert.assertEquals("[\"aaa\",null]", jsonStr); } @@ -135,7 +135,7 @@ public class JSONArrayTest { public void toDictListTest() { final String jsonArr = "[{\"id\":111,\"name\":\"test1\"},{\"id\":112,\"name\":\"test2\"}]"; - final JSONArray array = JSONUtil.parseArray(jsonArr, JSONConfig.create().setIgnoreError(false)); + final JSONArray array = JSONUtil.parseArray(jsonArr, JSONConfig.of().setIgnoreError(false)); final List list = JSONUtil.toList(array, Dict.class); @@ -166,7 +166,7 @@ public class JSONArrayTest { @Test public void toListWithNullTest() { final String json = "[null,{'akey':'avalue','bkey':'bvalue'}]"; - final JSONArray ja = JSONUtil.parseArray(json); + final JSONArray ja = JSONUtil.parseArray(json, JSONConfig.of().setIgnoreNullValue(false)); final List list = ja.toList(KeyBean.class); Assert.assertNull(list.get(0)); @@ -218,8 +218,13 @@ public class JSONArrayTest { @Test public void putToIndexTest(){ - final JSONArray jsonArray = new JSONArray(); - jsonArray.put(3, "test"); + JSONArray jsonArray = new JSONArray(); + jsonArray.set(3, "test"); + // 默认忽略null值,因此空位无值,只有一个值 + Assert.assertEquals(1, jsonArray.size()); + + jsonArray = new JSONArray(JSONConfig.of().setIgnoreNullValue(false)); + jsonArray.set(3, "test"); // 第三个位置插入值,0~2都是null Assert.assertEquals(4, jsonArray.size()); } @@ -273,7 +278,7 @@ public class JSONArrayTest { @Test public void putNullTest(){ - final JSONArray array = JSONUtil.createArray(JSONConfig.create().setIgnoreNullValue(false)); + final JSONArray array = JSONUtil.createArray(JSONConfig.of().setIgnoreNullValue(false)); array.set(null); Assert.assertEquals("[null]", array.toString()); diff --git a/hutool-json/src/test/java/cn/hutool/json/JSONNullTest.java b/hutool-json/src/test/java/cn/hutool/json/JSONNullTest.java index 0883ed768..9f3783449 100644 --- a/hutool-json/src/test/java/cn/hutool/json/JSONNullTest.java +++ b/hutool-json/src/test/java/cn/hutool/json/JSONNullTest.java @@ -12,9 +12,9 @@ public class JSONNullTest { " \"device_status_date\": null,\n" + " \"imsi\": null,\n" + " \"act_date\": \"2021-07-23T06:23:26.000+00:00\"}"); - Assert.assertEquals(JSONNull.class, bodyjson.get("device_model").getClass()); - Assert.assertEquals(JSONNull.class, bodyjson.get("device_status_date").getClass()); - Assert.assertEquals(JSONNull.class, bodyjson.get("imsi").getClass()); + Assert.assertNull(bodyjson.get("device_model")); + Assert.assertNull(bodyjson.get("device_status_date")); + Assert.assertNull(bodyjson.get("imsi")); bodyjson.getConfig().setIgnoreNullValue(true); Assert.assertEquals("{\"act_date\":\"2021-07-23T06:23:26.000+00:00\"}", bodyjson.toString()); @@ -31,4 +31,26 @@ public class JSONNullTest { Assert.assertFalse(bodyjson.containsKey("device_status_date")); Assert.assertFalse(bodyjson.containsKey("imsi")); } + + @Test + public void setNullTest(){ + // 忽略null + String json1 = JSONUtil.createObj().set("key1", null).toString(); + Assert.assertEquals("{}", json1); + + // 不忽略null + json1 = JSONUtil.createObj(JSONConfig.of().setIgnoreNullValue(false)).set("key1", null).toString(); + Assert.assertEquals("{\"key1\":null}", json1); + } + + @Test + public void setNullOfJSONArrayTest(){ + // 忽略null + String json1 = JSONUtil.createArray().set(null).toString(); + Assert.assertEquals("[]", json1); + + // 不忽略null + json1 = JSONUtil.createArray(JSONConfig.of().setIgnoreNullValue(false)).set(null).toString(); + Assert.assertEquals("[null]", json1); + } } diff --git a/hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java b/hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java index b33f4cd2a..50596ac2e 100755 --- a/hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java +++ b/hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java @@ -116,7 +116,7 @@ public class JSONObjectTest { Assert.assertEquals(jsonObject.get("d"), true); Assert.assertTrue(jsonObject.containsKey("e")); - Assert.assertEquals(jsonObject.get("e"), JSONNull.NULL); + Assert.assertNull(jsonObject.get("e")); } @Test @@ -199,7 +199,7 @@ public class JSONObjectTest { @Test public void toBeanTest() { final JSONObject subJson = JSONUtil.createObj().set("value1", "strValue1").set("value2", "234"); - final JSONObject json = JSONUtil.createObj().set("strValue", "strTest").set("intValue", 123) + final JSONObject json = JSONUtil.createObj(JSONConfig.of().setIgnoreError(true)).set("strValue", "strTest").set("intValue", 123) // 测试空字符串转对象 .set("doubleValue", "") .set("beanValue", subJson) @@ -453,19 +453,19 @@ public class JSONObjectTest { @Test public void setDateFormatTest() { - final JSONConfig jsonConfig = JSONConfig.create(); + final JSONConfig jsonConfig = JSONConfig.of(); jsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss"); final JSONObject json = new JSONObject(jsonConfig); json.append("date", DateUtil.parse("2020-06-05 11:16:11")); json.append("bbb", "222"); json.append("aaa", "123"); - Assert.assertEquals("{\"date\":[\"2020-06-05 11:16:11\"],\"bbb\":[\"222\"],\"aaa\":[\"123\"]}", json.toString()); + Assert.assertEquals("{\"date\":\"2020-06-05 11:16:11\",\"bbb\":\"222\",\"aaa\":\"123\"}", json.toString()); } @Test public void setDateFormatTest2() { - final JSONConfig jsonConfig = JSONConfig.create(); + final JSONConfig jsonConfig = JSONConfig.of(); jsonConfig.setDateFormat("yyyy#MM#dd"); final Date date = DateUtil.parse("2020-06-05 11:16:11"); @@ -485,7 +485,7 @@ public class JSONObjectTest { @Test public void setCustomDateFormatTest() { - final JSONConfig jsonConfig = JSONConfig.create(); + final JSONConfig jsonConfig = JSONConfig.of(); jsonConfig.setDateFormat("#sss"); final Date date = DateUtil.parse("2020-06-05 11:16:11"); @@ -599,7 +599,7 @@ public class JSONObjectTest { @Test(expected = JSONException.class) public void createJSONObjectTest() { // 集合类不支持转为JSONObject - new JSONObject(new JSONArray(), JSONConfig.create()); + new JSONObject(new JSONArray(), JSONConfig.of()); } @Test @@ -612,14 +612,14 @@ public class JSONObjectTest { } @Test - public void accumulateTest() { - final JSONObject jsonObject = JSONUtil.createObj().accumulate("key1", "value1"); + public void appendTest() { + final JSONObject jsonObject = JSONUtil.createObj().append("key1", "value1"); Assert.assertEquals("{\"key1\":\"value1\"}", jsonObject.toString()); - jsonObject.accumulate("key1", "value2"); + jsonObject.append("key1", "value2"); Assert.assertEquals("{\"key1\":[\"value1\",\"value2\"]}", jsonObject.toString()); - jsonObject.accumulate("key1", "value3"); + jsonObject.append("key1", "value3"); Assert.assertEquals("{\"key1\":[\"value1\",\"value2\",\"value3\"]}", jsonObject.toString()); } @@ -646,7 +646,7 @@ public class JSONObjectTest { @Test public void filterIncludeTest() { - final JSONObject json1 = JSONUtil.createObj(JSONConfig.create()) + final JSONObject json1 = JSONUtil.createObj(JSONConfig.of()) .set("a", "value1") .set("b", "value2") .set("c", "value3") @@ -658,7 +658,7 @@ public class JSONObjectTest { @Test public void filterExcludeTest() { - final JSONObject json1 = JSONUtil.createObj(JSONConfig.create()) + final JSONObject json1 = JSONUtil.createObj(JSONConfig.of()) .set("a", "value1") .set("b", "value2") .set("c", "value3") @@ -670,7 +670,7 @@ public class JSONObjectTest { @Test public void editTest() { - final JSONObject json1 = JSONUtil.createObj(JSONConfig.create()) + final JSONObject json1 = JSONUtil.createObj(JSONConfig.of()) .set("a", "value1") .set("b", "value2") .set("c", "value3") @@ -690,7 +690,7 @@ public class JSONObjectTest { @Test public void toUnderLineCaseTest() { - final JSONObject json1 = JSONUtil.createObj(JSONConfig.create()) + final JSONObject json1 = JSONUtil.createObj(JSONConfig.of()) .set("aKey", "value1") .set("bJob", "value2") .set("cGood", "value3") @@ -705,7 +705,7 @@ public class JSONObjectTest { @Test public void nullToEmptyTest() { - final JSONObject json1 = JSONUtil.createObj(JSONConfig.create().setIgnoreNullValue(false)) + final JSONObject json1 = JSONUtil.createObj(JSONConfig.of().setIgnoreNullValue(false)) .set("a", null) .set("b", "value2"); diff --git a/hutool-json/src/test/java/cn/hutool/json/JSONUtilTest.java b/hutool-json/src/test/java/cn/hutool/json/JSONUtilTest.java index a79a4bffe..d187c267d 100644 --- a/hutool-json/src/test/java/cn/hutool/json/JSONUtilTest.java +++ b/hutool-json/src/test/java/cn/hutool/json/JSONUtilTest.java @@ -178,7 +178,7 @@ public class JSONUtilTest { @Test public void customValueTest() { final JSONObject jsonObject = JSONUtil.createObj() - .set("test2", (JSONString) () -> NumberUtil.decimalFormat("#.0", 12.00D)); + .set("test2", (JSONString) () -> NumberUtil.format("#.0", 12.00D)); Assert.assertEquals("{\"test2\":12.0}", jsonObject.toString()); } @@ -191,7 +191,7 @@ public class JSONUtilTest { Assert.assertEquals("{\"test2\":12}", jsonObjectDefault.toString()); // 不去除多余的0 - final JSONObject jsonObject = JSONUtil.createObj(JSONConfig.create().setStripTrailingZeros(false)) + final JSONObject jsonObject = JSONUtil.createObj(JSONConfig.of().setStripTrailingZeros(false)) .set("test2", 12.00D); Assert.assertEquals("{\"test2\":12.0}", jsonObject.toString()); diff --git a/hutool-json/src/test/java/cn/hutool/json/TransientTest.java b/hutool-json/src/test/java/cn/hutool/json/TransientTest.java index 400599c20..ee3f5ad5b 100644 --- a/hutool-json/src/test/java/cn/hutool/json/TransientTest.java +++ b/hutool-json/src/test/java/cn/hutool/json/TransientTest.java @@ -20,7 +20,7 @@ public class TransientTest { //noinspection MismatchedQueryAndUpdateOfCollection final JSONObject jsonObject = new JSONObject(detailBill, - JSONConfig.create().setTransientSupport(false)); + JSONConfig.of().setTransientSupport(false)); Assert.assertEquals("{\"id\":\"3243\",\"bizNo\":\"bizNo\"}", jsonObject.toString()); } @@ -32,7 +32,7 @@ public class TransientTest { //noinspection MismatchedQueryAndUpdateOfCollection final JSONObject jsonObject = new JSONObject(detailBill, - JSONConfig.create().setTransientSupport(true)); + JSONConfig.of().setTransientSupport(true)); Assert.assertEquals("{\"bizNo\":\"bizNo\"}", jsonObject.toString()); } @@ -43,7 +43,7 @@ public class TransientTest { detailBill.setBizNo("bizNo"); final JSONObject jsonObject = new JSONObject(detailBill, - JSONConfig.create().setTransientSupport(false)); + JSONConfig.of().setTransientSupport(false)); final Bill bill = jsonObject.toBean(Bill.class); Assert.assertEquals("3243", bill.getId()); @@ -57,7 +57,7 @@ public class TransientTest { detailBill.setBizNo("bizNo"); final JSONObject jsonObject = new JSONObject(detailBill, - JSONConfig.create().setTransientSupport(true)); + JSONConfig.of().setTransientSupport(true)); final Bill bill = jsonObject.toBean(Bill.class); Assert.assertNull(bill.getId()); diff --git a/hutool-log/src/main/java/cn/hutool/log/dialect/console/ConsoleColorLog.java b/hutool-log/src/main/java/cn/hutool/log/dialect/console/ConsoleColorLog.java index cab4902a7..61b3bb0be 100755 --- a/hutool-log/src/main/java/cn/hutool/log/dialect/console/ConsoleColorLog.java +++ b/hutool-log/src/main/java/cn/hutool/log/dialect/console/ConsoleColorLog.java @@ -16,6 +16,7 @@ import java.util.function.Function; * @since 5.8.0 */ public class ConsoleColorLog extends ConsoleLog { + private static final long serialVersionUID = 1L; /** * 控制台打印类名的颜色代码 diff --git a/hutool-poi/src/main/java/cn/hutool/poi/csv/CsvRow.java b/hutool-poi/src/main/java/cn/hutool/poi/csv/CsvRow.java index c6a48a0f2..5d7b77bf9 100755 --- a/hutool-poi/src/main/java/cn/hutool/poi/csv/CsvRow.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/csv/CsvRow.java @@ -107,7 +107,7 @@ public final class CsvRow implements List { * @since 5.3.6 */ public T toBean(final Class clazz){ - return BeanUtil.toBean(getFieldMap(), clazz, CopyOptions.create().setIgnoreError(true)); + return BeanUtil.toBean(getFieldMap(), clazz, CopyOptions.of().setIgnoreError(true)); } /** diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/reader/BeanSheetReader.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/reader/BeanSheetReader.java index 2a0c6fb64..699a73167 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/reader/BeanSheetReader.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/reader/BeanSheetReader.java @@ -42,7 +42,7 @@ public class BeanSheetReader implements SheetReader> { } final List beanList = new ArrayList<>(mapList.size()); - final CopyOptions copyOptions = CopyOptions.create().setIgnoreError(true); + final CopyOptions copyOptions = CopyOptions.of().setIgnoreError(true); for (final Map map : mapList) { beanList.add(BeanUtil.toBean(map, this.beanClass, copyOptions)); } diff --git a/hutool-setting/src/main/java/cn/hutool/setting/AbsSetting.java b/hutool-setting/src/main/java/cn/hutool/setting/AbsSetting.java index db8a3f0a8..14420bdbe 100644 --- a/hutool-setting/src/main/java/cn/hutool/setting/AbsSetting.java +++ b/hutool-setting/src/main/java/cn/hutool/setting/AbsSetting.java @@ -297,7 +297,7 @@ public abstract class AbsSetting implements OptNullBasicTypeFromStringGetter - * 来自:http://blog.51cto.com/cping1982/130066 + * 来自:http://blog.51cto.com/cping1982/130066 * * @param degree 旋转角度 * @return 旋转后的图片 diff --git a/hutool-swing/src/main/java/cn/hutool/swing/img/package-info.java b/hutool-swing/src/main/java/cn/hutool/swing/img/package-info.java index 7a921125d..50b91bf7d 100755 --- a/hutool-swing/src/main/java/cn/hutool/swing/img/package-info.java +++ b/hutool-swing/src/main/java/cn/hutool/swing/img/package-info.java @@ -4,4 +4,4 @@ * @author looly * */ -package cn.hutool.core.img; \ No newline at end of file +package cn.hutool.swing.img; diff --git a/hutool-swing/src/main/java/cn/hutool/swing/package-info.java b/hutool-swing/src/main/java/cn/hutool/swing/package-info.java index 4f6cb42b8..ff90aa63a 100755 --- a/hutool-swing/src/main/java/cn/hutool/swing/package-info.java +++ b/hutool-swing/src/main/java/cn/hutool/swing/package-info.java @@ -4,4 +4,4 @@ * @author looly * */ -package cn.hutool.core.swing; \ No newline at end of file +package cn.hutool.swing;