Merge branch 'v6-dev' of gitee.com:dromara/hutool into v6-dev

This commit is contained in:
阿超 2022-06-07 15:19:45 +00:00 committed by Gitee
commit 68d6116212
124 changed files with 1404 additions and 2381 deletions

View File

@ -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可以更好的兼容细化类型的转换
### ❌不兼容特性

View File

@ -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> 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> 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<String, Object> beanToMap(final Object bean, final String... properties) {
int mapSize = 16;
Editor<String> keyEditor = null;
Editor<MutableEntry<String, Object>> editor = null;
if (ArrayUtil.isNotEmpty(properties)) {
mapSize = properties.length;
final Set<String> 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<String, Object> beanToMap(final Object bean, final Map<String, Object> targetMap, final boolean ignoreNullValue, final Editor<String> keyEditor) {
public static Map<String, Object> beanToMap(final Object bean, final Map<String, Object> targetMap,
final boolean ignoreNullValue, final Editor<MutableEntry<String, Object>> 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 <T> List<T> copyToList(final Collection<?> collection, final Class<T> targetType) {
return copyToList(collection, targetType, CopyOptions.create());
return copyToList(collection, targetType, CopyOptions.of());
}
/**

View File

@ -23,6 +23,6 @@ public abstract class AbsCopier<S, T> implements Copier<T> {
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);
}
}

View File

@ -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<S, T> extends AbsCopier<S, T> {
return;
}
sFieldName = copyOptions.editFieldName(sFieldName);
// 检查源对象属性是否过滤属性
Object sValue = sDesc.getValue(this.source);
if (false == copyOptions.testPropertyFilter(sDesc.getField(), sValue)) {
return;
}
// 编辑键值对
final MutableEntry<String, Object> 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);

View File

@ -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<Object, Map> {
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<String, Object> 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);
}
// 目标赋值

View File

@ -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;
/**
* 属性过滤器断言通过的属性才会被复制<br>
* 断言参数中Field为源对象的字段对象,如果源对象为Map使用目标对象Object为源对象的对应值
*/
private BiPredicate<Field, Object> propertiesFilter;
/**
* 是否忽略字段注入错误
*/
@ -50,14 +45,16 @@ public class CopyOptions implements Serializable {
*/
protected boolean ignoreCase;
/**
* 字段属性编辑器用于自定义属性转换规则例如驼峰转下划线等<br>
* 规则为{@link Editor#edit(Object)}属性为源对象的字段名称或key返回值为目标对象的字段名称或key
* 属性过滤器断言通过的属性才会被复制<br>
* 断言参数中Field为源对象的字段对象,如果源对象为Map使用目标对象Object为源对象的对应值
*/
private Editor<String> fieldNameEditor;
private BiPredicate<Field, Object> propertiesFilter;
/**
* 字段属性值编辑器用于自定义属性值转换规则例如null转""
* 字段属性名和属性值编辑器用于自定义属性转换规则例如驼峰转下划线等自定义属性值转换规则例如null转""
*/
protected BiFunction<String, Object, Object> fieldValueEditor;
protected Editor<MutableEntry<String, Object>> 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<String, String> 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 {
* 此转换器只针对源端的字段做转换请确认转换后与目标端字段一致<br>
* 当转换后的字段名为null时忽略这个字段
*
* @param fieldNameEditor 字段属性编辑器用于自定义属性转换规则例如驼峰转下划线等
* @param editor 字段属性编辑器用于自定义属性转换规则例如驼峰转下划线等
* @return CopyOptions
* @since 5.4.2
*/
public CopyOptions setFieldNameEditor(final Editor<String> fieldNameEditor) {
this.fieldNameEditor = fieldNameEditor;
return this;
}
/**
* 设置字段属性值编辑器用于自定义属性值转换规则例如null转""<br>
*
* @param fieldValueEditor 字段属性值编辑器用于自定义属性值转换规则例如null转""
* @return CopyOptions
* @since 5.7.15
*/
public CopyOptions setFieldValueEditor(final BiFunction<String, Object, Object> fieldValueEditor) {
this.fieldValueEditor = fieldValueEditor;
public CopyOptions setFieldEditor(final Editor<MutableEntry<String, Object>> 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<String, Object> editField(final String fieldName, final Object fieldValue) {
final MutableEntry<String, Object> 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}不保留
*

View File

@ -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<T> extends AbsCopier<Map<?, ?>, T> {
if (null == sKey) {
return;
}
String sKeyStr = copyOptions.editFieldName(sKey.toString());
// 编辑键值对
final MutableEntry<String, Object> 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);

View File

@ -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<Map, Map> {
if (null == sKey) {
return;
}
final String sKeyStr = copyOptions.editFieldName(sKey.toString());
// 对key做转换转换后为null的跳过
if (null == sKeyStr) {
// 编辑键值对
final MutableEntry<String, Object> 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<Map, Map> {
// 获取目标值真实类型并转换源值
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;
}

View File

@ -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<T> extends AbsCopier<ValueProvider<String
// 获取目标字段真实类型
final Type fieldType = TypeUtil.getActualType(this.targetType ,tDesc.getFieldType());
Object sValue = source.value(tFieldName, fieldType);
// 编辑键值对
final MutableEntry<String, Object> 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);

View File

@ -140,7 +140,7 @@ public class ClassLoaderUtil {
* 3内部类例如java.lang.Thread.State会被转为java.lang.Thread$State加载
* </pre>
*
* @param <T> 目标类的类型
* @param <T> 目标类的类型
* @param name 类名
* @return 类名对应的类
* @throws UtilException 包装{@link ClassNotFoundException}没有类名对应的类时抛出此异常
@ -159,7 +159,7 @@ public class ClassLoaderUtil {
* 3内部类例如java.lang.Thread.State会被转为java.lang.Thread$State加载
* </pre>
*
* @param <T> 目标类的类型
* @param <T> 目标类的类型
* @param name 类名
* @param isInitialized 是否初始化类调用static模块内容和初始化static属性
* @return 类名对应的类
@ -181,6 +181,7 @@ public class ClassLoaderUtil {
* 3内部类例如java.lang.Thread.State会被转为java.lang.Thread$State加载
* </pre>
*
* @param <T> 加载的类的类型
* @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<T>) 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[]"风格

View File

@ -750,10 +750,11 @@ public class CollUtil {
* 根据函数生成的KEY去重集合如根据Bean的某个或者某些字段完成去重<br>
* 去重可选是保留最先加入的值还是后加入的值
*
* @param <T> 集合元素类型
* @param <K> 唯一键类型
* @param collection 集合
* @param override 是否覆盖模式如果为{@code true}加入的新值会覆盖相同key的旧值否则会忽略新加值
* @param <T> 集合元素类型
* @param <K> 唯一键类型
* @param collection 集合
* @param uniqueGenerator 唯一键生成器
* @param override 是否覆盖模式如果为{@code true}加入的新值会覆盖相同key的旧值否则会忽略新加值
* @return {@link ArrayList}
* @since 5.8.0
*/

View File

@ -11,6 +11,86 @@ import java.util.function.Function;
*/
public class CompareUtil {
// ------------------------------------------------------------------------------------------- compare
/**
* 比较两个值的大小
*
* @param x 第一个值
* @param y 第二个值
* @return x==y返回0x&lt;y返回小于0的数x&gt;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返回0x&lt;y返回小于0的数x&gt;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返回0x&lt;y返回小于0的数x&gt;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返回0x&lt;y返回小于0的数x&gt;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返回0x&lt;y返回小于0的数x&gt;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返回0x&lt;y返回-1x&gt;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);
}
/**
* 获取自然排序器即默认排序器
*

View File

@ -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<T> implements Converter<T>, Serializable {
public abstract class AbstractConverter implements Converter, Serializable {
private static final long serialVersionUID = 1L;
/**
* 不抛异常转换<br>
* 当转换失败时返回默认值
*
* @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<T> 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<T>) 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)} 调用实现基本转换逻辑<br>
* 内部转换器 {@link AbstractConverter#convert(Type, Object)} 调用实现基本转换逻辑<br>
* 内部转换器转换后如果转换失败可以做如下操作处理结果都为返回默认值
*
* <pre>
@ -72,10 +45,11 @@ public abstract class AbstractConverter<T> implements Converter<T>, Serializable
* 2抛出一个{@link RuntimeException}异常
* </pre>
*
* @param targetClass 目标类型
* @param value
* @return 转换后的类型
*/
protected abstract T convertInternal(Object value);
protected abstract Object convertInternal(Class<?> targetClass, Object value);
/**
* 值转为String用于内部转换中需要使用String中转的情况<br>
@ -98,20 +72,10 @@ public abstract class AbstractConverter<T> implements Converter<T>, 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<T> getTargetType() {
return (Class<T>) ClassUtil.getTypeArgument(getClass());
}
}

View File

@ -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 <T> 目标类型
* @param targetType 指定目标类型
* @param value 被转换的对象
* @return 转换后的对象
*/
public static <T> T castTo(Class<T> targetType, final Object value) {
return Assert.notNull(targetType).cast(value);
}
/**
* 泛型集合向上转型例如将Collection&lt;Integer&gt;转换为Collection&lt;Number&gt;
*

View File

@ -532,7 +532,11 @@ public class Convert {
*/
@SuppressWarnings("unchecked")
public static <E extends Enum<E>> E toEnum(final Class<E> 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 <K, V> Map<K, V> toMap(final Class<K> keyType, final Class<V> valueType, final Object value) {
return (Map<K, V>) new MapConverter(HashMap.class, keyType, valueType).convert(value, null);
return (Map<K, V>) new MapConverter().convert(HashMap.class, keyType, valueType, value);
}
/**

View File

@ -1,43 +1,41 @@
package cn.hutool.core.convert;
import cn.hutool.core.util.ObjUtil;
import java.lang.reflect.Type;
/**
* 转换器接口实现类型转换
* 类型转换接口函数根据给定的值和目标类型由用户自定义转换规则
*
* @param <T> 转换到的目标类型
* @author Looly
* @author looly
* @since 5.8.0
*/
public interface Converter<T> {
@FunctionalInterface
public interface Converter {
/**
* 转换为指定类型<br>
* 如果类型无法确定将读取默认值的类型做为目标类型
*
* @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;
/**
* 转换值为指定类型可选是否不抛异常转换<br>
* 当转换失败时返回默认值
*
* @param value
* @param <T> 目标类型
* @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> T convert(final Type targetType, final Object value, final T defaultValue) {
return ObjUtil.defaultIfNull((T) convert(targetType, value), defaultValue);
}
}

View File

@ -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<Type, Converter<?>> defaultConverterMap;
private Map<Type, Converter> defaultConverterMap;
/**
* 用户自定义类型转换器
*/
private volatile Map<Type, Converter<?>> customConverterMap;
private volatile Map<Type, Converter> 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<? extends Converter<?>> 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 {
/**
* 获得转换器<br>
*
* @param <T> 转换的目标类型
* @param type 类型
* @param isCustomFirst 是否自定义转换器优先
* @return 转换器
*/
public <T> Converter<T> getConverter(final Type type, final boolean isCustomFirst) {
Converter<T> 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 <T> 转换的目标类型转换器转换到的类型
* @param type 类型
* @return 转换器
*/
@SuppressWarnings("unchecked")
public <T> Converter<T> getDefaultConverter(final Type type) {
return (null == defaultConverterMap) ? null : (Converter<T>) defaultConverterMap.get(type);
public Converter getDefaultConverter(final Type type) {
return (null == defaultConverterMap) ? null : defaultConverterMap.get(type);
}
/**
* 获得自定义转换器
*
* @param <T> 转换的目标类型转换器转换到的类型
* @param type 类型
* @return 转换器
*/
@SuppressWarnings("unchecked")
public <T> Converter<T> getCustomConverter(final Type type) {
return (null == customConverterMap) ? null : (Converter<T>) 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<T> 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<T> rowType = (Class<T>) TypeUtil.getClass(type);
if (null == rowType) {
if (null != defaultValue) {
rowType = (Class<T>) 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<T>(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
//AtomicXXXArraysince 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
}

View File

@ -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]);
}
/**

View File

@ -1,24 +0,0 @@
package cn.hutool.core.convert;
import java.lang.reflect.Type;
/**
* 类型转换接口函数根据给定的值和目标类型由用户自定义转换规则
*
* @author looly
* @since 5.8.0
*/
@FunctionalInterface
public interface TypeConverter {
/**
* 转换为指定类型<br>
* 如果类型无法确定将读取默认值的类型做为目标类型
*
* @param targetType 目标Type非泛型类使用
* @param value 原始值
* @return 转换后的值
* @throws IllegalArgumentException 无法确定目标类型且默认值为{@code null}无法确定类型
*/
Object convert(Type targetType, Object value);
}

View File

@ -21,14 +21,10 @@ import java.util.List;
*
* @author Looly
*/
public class ArrayConverter extends AbstractConverter<Object> {
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<Object> {
/**
* 构造
*
* @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<Object> {
* @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<Object> {
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<Object> {
/**
* 非数组对数组转换
*
* @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<Object> {
// 单纯字符串情况下按照逗号分隔后劈开
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<Object> {
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<Object> {
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<Object> {
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<Object> {
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<Object> {
* @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<Object> {
* @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
}

View File

@ -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<AtomicBoolean> {
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));
}
}

View File

@ -11,11 +11,11 @@ import java.util.concurrent.atomic.AtomicIntegerArray;
* @author Looly
* @since 5.4.5
*/
public class AtomicIntegerArrayConverter extends AbstractConverter<AtomicIntegerArray> {
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));
}

View File

@ -11,11 +11,11 @@ import java.util.concurrent.atomic.AtomicLongArray;
* @author Looly
* @since 5.4.5
*/
public class AtomicLongArrayConverter extends AbstractConverter<AtomicLongArray> {
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));
}

View File

@ -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<AtomicReference> {
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;

View File

@ -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
* </pre>
*
* @param <T> Bean类型
* @author Looly
* @since 4.0.2
*/
public class BeanConverter<T> extends AbstractConverter<T> {
public class BeanConverter implements Converter, Serializable {
private static final long serialVersionUID = 1L;
private final Type beanType;
private final Class<T> 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<T> 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<T>) 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<T> getTargetType() {
return this.beanClass;
}
}

View File

@ -16,11 +16,11 @@ import cn.hutool.core.util.BooleanUtil;
*
* @author Looly
*/
public class BooleanConverter extends AbstractConverter<Boolean> {
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();

View File

@ -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<Calendar> {
public class CalendarConverter extends AbstractConverter {
private static final long serialVersionUID = 1L;
/** 日期格式化 */
@ -38,7 +38,7 @@ public class CalendarConverter extends AbstractConverter<Calendar> {
}
@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);

View File

@ -10,19 +10,13 @@ import cn.hutool.core.convert.ConvertException;
* @param <T> 强制转换到的类型
* @since 4.0.2
*/
public class CastConverter<T> extends AbstractConverter<T> {
public class CastConverter<T> extends AbstractConverter {
private static final long serialVersionUID = 1L;
private Class<T> 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<T> getTargetType() {
return this.targetType;
}
}

View File

@ -10,11 +10,11 @@ import cn.hutool.core.text.StrUtil;
* @author Looly
*
*/
public class CharacterConverter extends AbstractConverter<Character> {
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 {

View File

@ -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<Charset>{
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));
}

View File

@ -9,7 +9,7 @@ import cn.hutool.core.classloader.ClassLoaderUtil;
*
* @author Looly
*/
public class ClassConverter extends AbstractConverter<Class<?>> {
public class ClassConverter extends AbstractConverter {
private static final long serialVersionUID = 1L;
private final boolean isInitialized;
@ -32,7 +32,7 @@ public class ClassConverter extends AbstractConverter<Class<?>> {
}
@Override
protected Class<?> convertInternal(final Object value) {
protected Class<?> convertInternal(final Class<?> targetClass, final Object value) {
return ClassLoaderUtil.loadClass(convertToStr(value), isInitialized);
}

View File

@ -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<Collection<?>> {
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<Object> 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<Object> collection = CollUtil.create(TypeUtil.getClass(collectionType));
return CollUtil.addAll(collection, value, elementType);
}
}

View File

@ -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<Currency> {
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));
}

View File

@ -14,10 +14,11 @@ import java.util.Calendar;
*
* @author Looly
*/
public class DateConverter extends AbstractConverter<java.util.Date> {
public class DateConverter extends AbstractConverter {
private static final long serialVersionUID = 1L;
private final Class<? extends java.util.Date> targetType;
public static final DateConverter INSTANCE = new DateConverter();
/**
* 日期格式化
*/
@ -25,21 +26,17 @@ public class DateConverter extends AbstractConverter<java.util.Date> {
/**
* 构造
*
* @param targetType 目标类型
*/
public DateConverter(final Class<? extends java.util.Date> targetType) {
this.targetType = targetType;
public DateConverter() {
this(null);
}
/**
* 构造
*
* @param targetType 目标类型
* @param format 日期格式
* @param format 日期格式
*/
public DateConverter(final Class<? extends java.util.Date> targetType, final String format) {
this.targetType = targetType;
public DateConverter(final String format) {
this.format = format;
}
@ -62,16 +59,16 @@ public class DateConverter extends AbstractConverter<java.util.Date> {
}
@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<java.util.Date> {
? 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<java.util.Date> {
* @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<java.util.Date> {
* @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<java.util.Date> getTargetType() {
return (Class<java.util.Date>) this.targetType;
throw new UnsupportedOperationException(StrUtil.format("Unsupported target Date type: {}", targetClass.getName()));
}
}

View File

@ -12,11 +12,11 @@ import java.time.temporal.TemporalAmount;
* @author Looly
* @since 5.0.0
*/
public class DurationConverter extends AbstractConverter<Duration> {
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){

View File

@ -22,40 +22,26 @@ import java.util.stream.Collectors;
* @since 4.0.2
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public class EnumConverter extends AbstractConverter<Object> {
public class EnumConverter extends AbstractConverter {
private static final long serialVersionUID = 1L;
public static final EnumConverter INSTANCE = new EnumConverter();
private static final WeakConcurrentMap<Class<?>, Map<Class<?>, 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);
}
/**

View File

@ -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}对象转换器<br>
@ -13,11 +13,11 @@ import cn.hutool.core.text.StrUtil;
* @author Looly
* @since 4.5.2
*/
public class LocaleConverter extends AbstractConverter<Locale> {
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)) {

View File

@ -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<Map<?, ?>> {
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转Map
*
* @param srcMap 源Map
* @param srcMap 源Map
* @param targetMap 目标Map
*/
private void convertMapToMap(final Map<?, ?> srcMap, final Map<Object, Object> 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<Map<?, ?>> getTargetType() {
return (Class<Map<?, ?>>) TypeUtil.getClass(this.mapType);
}
}

View File

@ -36,33 +36,15 @@ import java.util.function.Function;
*
* @author Looly
*/
public class NumberConverter extends AbstractConverter<Number> {
public class NumberConverter extends AbstractConverter {
private static final long serialVersionUID = 1L;
private final Class<? extends Number> targetType;
public static final NumberConverter INSTANCE = new NumberConverter();
public NumberConverter() {
this.targetType = Number.class;
}
/**
* 构造<br>
*
* @param clazz 需要转换的数字类型默认 {@link Number}
*/
public NumberConverter(final Class<? extends Number> clazz) {
this.targetType = (null == clazz) ? Number.class : clazz;
}
@Override
@SuppressWarnings("unchecked")
public Class<Number> getTargetType() {
return (Class<Number>) 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<? extends Number>) targetClass, this::convertToStr);
}
@Override

View File

@ -10,11 +10,11 @@ import cn.hutool.core.lang.Opt;
* @author Looly
* @since 5.7.16
*/
public class OptConverter extends AbstractConverter<Opt<?>> {
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);
}

View File

@ -11,11 +11,11 @@ import java.util.Optional;
* @author Looly
* @since 5.0.0
*/
public class OptionalConverter extends AbstractConverter<Optional<?>> {
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);
}

View File

@ -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<Path>{
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);

View File

@ -12,11 +12,11 @@ import java.time.temporal.TemporalAmount;
* @author Looly
* @since 5.0.0
*/
public class PeriodConverter extends AbstractConverter<Period> {
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){

View File

@ -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<Object> {
public class PrimitiveConverter extends AbstractConverter {
private static final long serialVersionUID = 1L;
private final Class<?> targetType;
public static final PrimitiveConverter INSTANCE = new PrimitiveConverter();
/**
* 构造<br>
*
* @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<Object> {
return StrUtil.trim(super.convertToStr(value));
}
@Override
@SuppressWarnings("unchecked")
public Class<Object> getTargetType() {
return (Class<Object>) this.targetType;
}
/**
* 将指定值转换为原始类型的值
* @param value

View File

@ -17,26 +17,18 @@ import java.lang.reflect.Type;
* @since 3.0.8
*/
@SuppressWarnings("rawtypes")
public class ReferenceConverter extends AbstractConverter<Reference> {
public class ReferenceConverter extends AbstractConverter {
private static final long serialVersionUID = 1L;
private final Class<? extends Reference> targetType;
/**
* 构造
* @param targetType {@link Reference}实现类型
*/
public ReferenceConverter(final Class<? extends Reference> 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<Reference> {
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()));
}
}

View File

@ -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} 转换器<br>
* 只支持Map方式转换
@ -13,11 +13,11 @@ import cn.hutool.core.util.ObjUtil;
* @author Looly
* @since 3.0.8
*/
public class StackTraceElementConverter extends AbstractConverter<StackTraceElement> {
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;

View File

@ -19,11 +19,11 @@ import java.util.TimeZone;
*
* @author Looly
*/
public class StringConverter extends AbstractConverter<String> {
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) {

View File

@ -37,10 +37,11 @@ import java.util.Objects;
* @author looly
* @since 5.0.0
*/
public class TemporalAccessorConverter extends AbstractConverter<TemporalAccessor> {
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<TemporalAccesso
/**
* 构造
*
* @param targetType 目标类型
*/
public TemporalAccessorConverter(final Class<?> 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<TemporalAccesso
this.format = format;
}
@SuppressWarnings("unchecked")
@Override
public Class<TemporalAccessor> getTargetType() {
return (Class<TemporalAccessor>) 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<TemporalAccesso
* @param value 字符串值
* @return 日期对象
*/
private TemporalAccessor parseFromCharSequence(final CharSequence value) {
private TemporalAccessor parseFromCharSequence(final Class<?> targetClass, final CharSequence value) {
if (StrUtil.isBlank(value)) {
return null;
}
@ -129,17 +120,18 @@ public class TemporalAccessorConverter extends AbstractConverter<TemporalAccesso
instant = Objects.requireNonNull(dateTime).toInstant();
zoneId = dateTime.getZoneId();
}
return parseFromInstant(instant, zoneId);
return parseFromInstant(targetClass, instant, zoneId);
}
/**
* 将Long型时间戳转换为java.time中的对象
*
* @param targetClass 目标类型
* @param time 时间戳
* @return java.time中的对象
*/
private TemporalAccessor parseFromLong(final Long time) {
return parseFromInstant(Instant.ofEpochMilli(time), null);
private TemporalAccessor parseFromLong(final Class<?> targetClass, final Long time) {
return parseFromInstant(targetClass, Instant.ofEpochMilli(time), null);
}
/**
@ -148,16 +140,16 @@ public class TemporalAccessorConverter extends AbstractConverter<TemporalAccesso
* @param temporalAccessor TemporalAccessor对象
* @return java.time中的对象
*/
private TemporalAccessor parseFromTemporalAccessor(final TemporalAccessor temporalAccessor) {
private TemporalAccessor parseFromTemporalAccessor(final Class<?> 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<TemporalAccesso
/**
* 将TemporalAccessor型时间戳转换为java.time中的对象
*
* @param targetClass 目标类
* @param localDateTime {@link LocalDateTime}对象
* @return java.time中的对象
*/
private TemporalAccessor parseFromLocalDateTime(final LocalDateTime localDateTime) {
if (Instant.class.equals(this.targetType)) {
private TemporalAccessor parseFromLocalDateTime(final Class<?> 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<TemporalAccesso
* @param zonedDateTime {@link ZonedDateTime}对象
* @return java.time中的对象
*/
private TemporalAccessor parseFromZonedDateTime(final ZonedDateTime zonedDateTime) {
if (Instant.class.equals(this.targetType)) {
private TemporalAccessor parseFromZonedDateTime(final Class<?> 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<TemporalAccesso
* @param zoneId 时区IDnull表示当前系统默认的时区
* @return java.time中的对象
*/
private TemporalAccessor parseFromInstant(final Instant instant, ZoneId zoneId) {
if (Instant.class.equals(this.targetType)) {
private TemporalAccessor parseFromInstant(final Class<?> 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;

View File

@ -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<TimeZone>{
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));
}

View File

@ -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<URI>{
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();

View File

@ -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<URL>{
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();

View File

@ -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<UUID> {
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));
}

View File

@ -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) {

View File

@ -45,6 +45,15 @@ public class LocalDateTimeUtil {
return LocalDateTime.now();
}
/**
* 当天时间默认时区
*
* @return {@link LocalDateTime}
*/
public static LocalDate today() {
return LocalDate.now();
}
/**
* {@link Instant}{@link LocalDateTime}使用默认时区
*

View File

@ -4,7 +4,6 @@ package cn.hutool.core.lang.ansi;
* 生成ANSI格式的编码输出
*
* @author Phillip Webb
* @since 1.0.0
*/
public abstract class AnsiEncoder {

View File

@ -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<MutableByte>, Muta
*/
@Override
public int compareTo(final MutableByte other) {
return NumberUtil.compare(this.value, other.value);
return CompareUtil.compare(this.value, other.value);
}
// -----------------------------------------------------------------------

View File

@ -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<MutableDouble>,
*/
@Override
public int compareTo(final MutableDouble other) {
return NumberUtil.compare(this.value, other.value);
return CompareUtil.compare(this.value, other.value);
}
// -----------------------------------------------------------------------

View File

@ -1,9 +1,9 @@
package cn.hutool.core.lang.mutable;
import cn.hutool.core.math.NumberUtil;
import cn.hutool.core.comparator.CompareUtil;
/**
* 可变 <code>float</code> 类型
* 可变 {@code float} 类型
*
* @see Float
* @since 3.0.1
@ -152,12 +152,12 @@ public class MutableFloat extends Number implements Comparable<MutableFloat>, Mu
* 相等需同时满足如下条件
* <ol>
* <li>非空</li>
* <li>类型为 {@link MutableFloat}</li>
* <li>类型为 {@code MutableFloat}</li>
* <li>值相等</li>
* </ol>
*
* @param obj 比对的对象
* @return 相同返回<code>true</code>否则 <code>false</code>
* @return 相同返回<code>true</code>否则 {@code false}
*/
@Override
public boolean equals(final Object obj) {
@ -176,12 +176,12 @@ public class MutableFloat extends Number implements Comparable<MutableFloat>, Mu
/**
* 比较
*
* @param other 其它 {@link MutableFloat} 对象
* @param other 其它 {@code MutableFloat} 对象
* @return x==y返回0x&lt;y返回-1x&gt;y返回1
*/
@Override
public int compareTo(final MutableFloat other) {
return NumberUtil.compare(this.value, other.value);
return CompareUtil.compare(this.value, other.value);
}
// -----------------------------------------------------------------------

View File

@ -1,6 +1,6 @@
package cn.hutool.core.lang.mutable;
import cn.hutool.core.math.NumberUtil;
import cn.hutool.core.comparator.CompareUtil;
/**
* 可变 <code>int</code> 类型
@ -181,7 +181,7 @@ public class MutableInt extends Number implements Comparable<MutableInt>, Mutabl
*/
@Override
public int compareTo(final MutableInt other) {
return NumberUtil.compare(this.value, other.value);
return CompareUtil.compare(this.value, other.value);
}
// -----------------------------------------------------------------------

View File

@ -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<MutableLong>, Muta
*/
@Override
public int compareTo(final MutableLong other) {
return NumberUtil.compare(this.value, other.value);
return CompareUtil.compare(this.value, other.value);
}
// -----------------------------------------------------------------------

View File

@ -1,9 +1,9 @@
package cn.hutool.core.lang.mutable;
import cn.hutool.core.math.NumberUtil;
import cn.hutool.core.comparator.CompareUtil;
/**
* 可变 <code>short</code> 类型
* 可变 {@code short} 类型
*
* @see Short
* @since 3.0.1
@ -157,12 +157,12 @@ public class MutableShort extends Number implements Comparable<MutableShort>, Mu
* 相等需同时满足如下条件
* <ol>
* <li>非空</li>
* <li>类型为 {@link MutableShort}</li>
* <li>类型为 {@code MutableShort}</li>
* <li>值相等</li>
* </ol>
*
* @param obj 比对的对象
* @return 相同返回<code>true</code>否则 <code>false</code>
* @return 相同返回<code>true</code>否则 {@code false}
*/
@Override
public boolean equals(final Object obj) {
@ -181,12 +181,12 @@ public class MutableShort extends Number implements Comparable<MutableShort>, Mu
/**
* 比较
*
* @param other 其它 {@link MutableShort} 对象
* @param other 其它 {@code MutableShort} 对象
* @return x==y返回0x&lt;y返回-1x&gt;y返回1
*/
@Override
public int compareTo(final MutableShort other) {
return NumberUtil.compare(this.value, other.value);
return CompareUtil.compare(this.value, other.value);
}
// -----------------------------------------------------------------------

View File

@ -247,7 +247,7 @@ public class Dict extends LinkedHashMap<String, Object> implements BasicTypeGett
* @return vo
*/
public <T> T toBeanIgnoreCase(final Class<T> clazz) {
return BeanUtil.toBean(this, clazz, CopyOptions.create().setIgnoreCase(true));
return BeanUtil.toBean(this, clazz, CopyOptions.of().setIgnoreCase(true));
}
/**

View File

@ -9,7 +9,7 @@ import java.util.List;
/**
* 排列A(n, m)<br>
* 排列组合相关类 参考http://cgs1999.iteye.com/blog/2327664
* 排列组合相关类 参考<a href="http://cgs1999.iteye.com/blog/2327664">http://cgs1999.iteye.com/blog/2327664</a>
*
* @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;
}
/**

View File

@ -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)<br>
* 排列组合相关类 参考http://cgs1999.iteye.com/blog/2327664
* 排列组合相关类 参考<a href="http://cgs1999.iteye.com/blog/2327664">http://cgs1999.iteye.com/blog/2327664</a>
*
* @author looly
* @since 4.0.6
@ -21,7 +21,7 @@ public class Combination implements Serializable {
/**
* 组合即C(n, m)<br>
* 排列组合相关类 参考http://cgs1999.iteye.com/blog/2327664
* 排列组合相关类 参考<a href="http://cgs1999.iteye.com/blog/2327664">http://cgs1999.iteye.com/blog/2327664</a>
*
* @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;
}
/**

View File

@ -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();
}
/**
* 计算阶乘
* <p>
* n! = n * (n-1) * ... * 2 * 1
* </p>
*
* @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);
}
/**
* 计算范围阶乘
* <p>
* factorial(start, end) = start * (start - 1) * ... * (end + 1)
* </p>
*
* @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;
}
/**
* 计算范围阶乘
* <p>
* factorial(start, end) = start * (start - 1) * ... * (end + 1)
* </p>
*
* @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));
}
/**
* 计算阶乘
* <p>
* n! = n * (n-1) * ... * 2 * 1
* </p>
*
* @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];
}
/**
* 平方根算法<br>
* 推荐使用 {@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;
}
/**
* 可以用于计算双色球大乐透注数的方法<br>
* 比如大乐透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);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -565,7 +565,7 @@ public class MethodUtil {
* @param method 方法对象方法或static方法都可
* @param args 参数对象
* @return 结果
* @throws InvocationTargetRuntimeException 目标方法执行异常
* @throws InvocationTargetException 目标方法执行异常
* @throws IllegalAccessException 访问权限异常
*/
@SuppressWarnings("unchecked")

View File

@ -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 {
/**
* 最长公共子串采用动态规划算法 其不要求所求得的字符在所给的字符串中是连续的<br>
* 算法解析见https://leetcode-cn.com/problems/longest-common-subsequence/solution/zui-chang-gong-gong-zi-xu-lie-by-leetcod-y7u0/
* 算法解析见<a href="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</a>
*
* @param strA 字符串1
* @param strB 字符串2

View File

@ -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<String, Number> hashFunc) {
return new FuncFilter(size, hashFunc);

View File

@ -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 {
* 去重数组中的元素去重后生成新的数组原数组不变<br>
* 此方法通过{@link LinkedHashSet} 去重
*
* @param <T> 数组元素类型
* @param <K> 唯一键类型
* @param array 数组
* @param override 是否覆盖模式如果为{@code true}加入的新值会覆盖相同key的旧值否则会忽略新加值
* @param <T> 数组元素类型
* @param <K> 唯一键类型
* @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<K, T> set = new UniqueKeySet<>(true, uniqueGenerator);
if(override){
if (override) {
Collections.addAll(set, array);
} else{
} else {
for (final T t : array) {
set.addIfAbsent(t);
}

View File

@ -638,6 +638,9 @@ public class IdcardUtil {
* 参考文档港澳居民来往内地通行证号码规则
* <a href="https://www.hmo.gov.cn/fwga_new/wldjnd/201711/t20171120_1333.html">https://www.hmo.gov.cn/fwga_new/wldjnd/201711/t20171120_1333.html</a>
* </p>
*
* @param idCard 身份证号码
* @return 是否有效
*/
public static boolean isValidHkMoHomeReturn(final String idCard) {
if (StrUtil.isEmpty(idCard)) {

View File

@ -186,15 +186,13 @@ public class ObjUtil {
*
* <pre>
* 1. == null
* 2. equals(null)
* </pre>
*
* @param obj 对象
* @return 是否为null
*/
public static boolean isNull(final Object obj) {
//noinspection ConstantConditions
return null == obj || obj.equals(null);
return null == obj;
}
/**

View File

@ -462,63 +462,6 @@ public class PrimitiveArrayUtil {
return result;
}
// ---------------------------------------------------------------------- range
/**
* 生成一个从0开始的数字列表<br>
*
* @param excludedEnd 结束的数字不包含
* @return 数字列表
*/
public static int[] range(final int excludedEnd) {
return range(0, excludedEnd, 1);
}
/**
* 生成一个数字列表<br>
* 自动判定正序反序
*
* @param includedStart 开始的数字包含
* @param excludedEnd 结束的数字不包含
* @return 数字列表
*/
public static int[] range(final int includedStart, final int excludedEnd) {
return range(includedStart, excludedEnd, 1);
}
/**
* 生成一个数字列表<br>
* 自动判定正序反序
*
* @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
/**

View File

@ -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 {
*
* <p>
* 注意此方法返回的{@link ThreadLocalRandom}不可以在多线程环境下共享对象否则有重复随机数问题
* https://www.jianshu.com/p/89dfe990295c
* <a href="https://www.jianshu.com/p/89dfe990295c">https://www.jianshu.com/p/89dfe990295c</a>
* </p>
*
* @return {@link ThreadLocalRandom}
@ -76,7 +77,7 @@ public class RandomUtil {
* 注意此方法获取的是伪随机序列发生器PRNGpseudo-random number generator
*
* <p>
* 相关说明见https://stackoverflow.com/questions/137212/how-to-solve-slow-java-securerandom
* 相关说明见<a href="https://stackoverflow.com/questions/137212/how-to-solve-slow-java-securerandom">how-to-solve-slow-java-securerandom</a>
*
* @return {@link SecureRandom}
* @since 3.1.2
@ -90,7 +91,7 @@ public class RandomUtil {
* 注意此方法获取的是伪随机序列发生器PRNGpseudo-random number generator
*
* <p>
* 相关说明见https://stackoverflow.com/questions/137212/how-to-solve-slow-java-securerandom
* 相关说明见<a href="https://stackoverflow.com/questions/137212/how-to-solve-slow-java-securerandom">how-to-solve-slow-java-securerandom</a>
*
* @param seed 随机数种子
* @return {@link SecureRandom}
@ -104,10 +105,10 @@ public class RandomUtil {
/**
* 获取SHA1PRNG的{@link SecureRandom}类提供加密的强随机数生成器 (RNG)<br>
* 注意此方法获取的是伪随机序列发生器PRNGpseudo-random number generator,在Linux下噪声生成时可能造成较长时间停顿<br>
* see: http://ifeve.com/jvm-random-and-entropy-source/
* see: <a href="http://ifeve.com/jvm-random-and-entropy-source/">http://ifeve.com/jvm-random-and-entropy-source/</a>
*
* <p>
* 相关说明见https://stackoverflow.com/questions/137212/how-to-solve-slow-java-securerandom
* 相关说明见<a href="https://stackoverflow.com/questions/137212/how-to-solve-slow-java-securerandom">how-to-solve-slow-java-securerandom</a>
*
* @param seed 随机数种子
* @return {@link SecureRandom}
@ -443,7 +444,7 @@ public class RandomUtil {
* @return 随机列表
* @since 5.2.1
*/
public static <T> List<T> randomEleList(final List<T> source, final int count) {
public static <T> List<T> randomPick(final List<T> 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);

View File

@ -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());
}

View File

@ -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<String, Object> 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());
}

View File

@ -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);

View File

@ -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());

View File

@ -12,13 +12,13 @@ public class BeanCopierTest {
public void beanToMapIgnoreNullTest() {
final A a = new A();
HashMap<Object, Object> map = BeanCopier.create(a, new HashMap<>(), CopyOptions.create()).copy();
HashMap<Object, Object> 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<B> copier = BeanCopier.create(a, b, CopyOptions.create().setOverride(false));
final BeanCopier<B> 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<B> copier = BeanCopier.create(a, b, CopyOptions.create());
final BeanCopier<B> copier = BeanCopier.create(a, b, CopyOptions.of());
copier.copy();
Assert.assertEquals("123", b.getValue());

View File

@ -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<Integer> iter = new PartitionIter<>(list.iterator(), 3);
int max = 0;
for (final List<Integer> 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);
}

View File

@ -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);
}

View File

@ -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());
}
}

View File

@ -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<Object> 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<CharSequence>{
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();
}
}

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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

View File

@ -169,7 +169,7 @@ public class JakartaServletUtil {
* @return Bean
*/
public static <T> 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));
}
/**

View File

@ -169,7 +169,7 @@ public class ServletUtil {
* @return Bean
*/
public static <T> 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));
}
/**

View File

@ -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<String, Object> createRawMap(final int capacity, JSONConfig config) {
final Map<String, Object> rawHashMap;
if (null == config) {
config = JSONConfig.create();
config = JSONConfig.of();
}
final Comparator<String> keyComparator = config.getKeyComparator();
if (config.isIgnoreCase()) {

View File

@ -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对应的值<br>
@ -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中嵌套的对象<br>

View File

@ -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<Integer>, List<Object>, 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<Integer>, List<Object>, 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<Integer>, List<Object>, 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<Integer>, List<Object>, 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> T getByPath(final String expression, final Class<T> 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<Integer>, List<Object>, Rando
@Override
@SuppressWarnings({"unchecked"})
public <T> 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<Integer>, List<Object>, Rando
}
final ArrayList<Object> 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<Integer>, List<Object>, 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<Integer>, List<Object>, 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<Integer>, List<Object>, Rando
* @since 3.0.8
*/
public <T> List<T> toList(final Class<T> elementType) {
return JSONConverter.toList(this, elementType);
return Convert.toList(elementType, this);
}
/**
@ -581,6 +587,10 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
return false;
}
}
if(null == obj && config.isIgnoreNullValue()){
// 忽略空则不添加
return false;
}
return this.rawList.add(obj);
}
}

View File

@ -49,7 +49,7 @@ public class JSONConfig implements Serializable {
*
* @return JSONConfig
*/
public static JSONConfig create() {
public static JSONConfig of() {
return new JSONConfig();
}

View File

@ -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<JSON> {
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 <T> 元素类型
* @param jsonArray JSONArray
* @param elementType 对象元素类型
* @return 对象列表
*/
protected static <T> List<T> toList(final JSONArray jsonArray, final Class<T> 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<JSON> {
*/
@SuppressWarnings("unchecked")
protected static <T> 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<JSON> {
*/
@SuppressWarnings("unchecked")
protected static <T> 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<JSON> {
if(value instanceof JSONGetter
&& targetType instanceof Class && BeanUtil.hasSetter((Class<?>) targetType)){
final JSONConfig config = ((JSONGetter<?>) value).getConfig();
final Converter<T> 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<JSON> {
return targetValue;
}
@Override
public JSON convert(final Object value, final JSON defaultValue) throws IllegalArgumentException {
return JSONUtil.parse(value);
}
}

View File

@ -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<K> extends OptNullBasicTypeFromObjectGetter<K> {
* 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<K> extends OptNullBasicTypeFromObjectGetter<K> {
*/
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<K> extends OptNullBasicTypeFromObjectGetter<K> {
*/
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<K> extends OptNullBasicTypeFromObjectGetter<K> {
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<K> extends OptNullBasicTypeFromObjectGetter<K> {
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<K> extends OptNullBasicTypeFromObjectGetter<K> {
*/
default <T> T get(final K key, final Class<T> 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);

View File

@ -1,46 +0,0 @@
package cn.hutool.json;
import cn.hutool.core.text.StrUtil;
import java.io.Serializable;
/**
* 用于定义{@code null}与Javascript中null相对应<br>
* Java中的{@code null}值在js中表示为undefined
*
* @author Looly
*/
public class JSONNull implements Serializable {
private static final long serialVersionUID = 2633815155870764938L;
/**
* {@code NULL} 对象用于减少歧义来表示Java 中的{@code null} <br>
* {@code NULL.equals(null)} 返回 {@code true}. <br>
* {@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;
}
}

View File

@ -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<String, Object> implements JSON, JSON
* 构造初始容量为 {@link #DEFAULT_CAPACITY}KEY有序
*/
public JSONObject() {
this(JSONConfig.create());
this(JSONConfig.of());
}
/**
@ -67,8 +66,8 @@ public class JSONObject extends MapWrapper<String, Object> 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<String, Object> 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<String, Object> implements JSON, JSON
return this.getOrDefault(key, defaultValue);
}
@Override
public Object getByPath(final String expression) {
return BeanPath.of(expression).get(this);
}
@Override
public <T> T getByPath(final String expression, final Class<T> 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<String, Object> 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<MutableEntry<String, Object>> filter) throws JSONException {
put(key, value, filter, true);
return this;
}
/**
@ -238,32 +243,6 @@ public class JSONObject extends MapWrapper<String, Object> 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<MutableEntry<String, Object>> filter) throws JSONException {
return set(key, value, filter, true);
}
/**
* 在键和值都为非空的情况下put到JSONObject中
*
@ -272,7 +251,7 @@ public class JSONObject extends MapWrapper<String, Object> 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<String, Object> implements JSON, JSON
}
/**
* 积累值类似于set当key对应value已经存在时与value组成新的JSONArray. <br>
* 如果只有一个值此值就是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中
* 追加值.
* <ul>
* <li>如果键值对不存在或对应值为{@code null}则value为单独值</li>
* <li>如果值是一个{@link JSONArray}追加之</li>
* <li>如果值是一个其他值则和旧值共同组合为一个{@link JSONArray}</li>
* </ul>
*
* @param key
* @param value
@ -320,11 +282,11 @@ public class JSONObject extends MapWrapper<String, Object> 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<String, Object> 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<MutableEntry<String, Object>> filter, final boolean checkDuplicate) throws JSONException {
if (null == key) {
return this;
return null;
}
// 添加前置过滤通过MutablePair实现过滤修改键值对等
@ -453,12 +415,12 @@ public class JSONObject extends MapWrapper<String, Object> 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)) {

View File

@ -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);

Some files were not shown because too many files have changed in this diff Show More