mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
Merge branch 'v6-dev' of gitee.com:dromara/hutool into v6-dev
This commit is contained in:
commit
68d6116212
@ -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可以更好的兼容细化类型的转换
|
||||
|
||||
### ❌不兼容特性
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
// 目标赋值
|
||||
|
@ -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}不保留
|
||||
*
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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[]"风格
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -11,6 +11,86 @@ import java.util.function.Function;
|
||||
*/
|
||||
public class CompareUtil {
|
||||
|
||||
// ------------------------------------------------------------------------------------------- compare
|
||||
|
||||
/**
|
||||
* 比较两个值的大小
|
||||
*
|
||||
* @param x 第一个值
|
||||
* @param y 第二个值
|
||||
* @return x==y返回0,x<y返回小于0的数,x>y返回大于0的数
|
||||
* @see Character#compare(char, char)
|
||||
* @since 3.0.1
|
||||
*/
|
||||
public static int compare(final char x, final char y) {
|
||||
return Character.compare(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较两个值的大小
|
||||
*
|
||||
* @param x 第一个值
|
||||
* @param y 第二个值
|
||||
* @return x==y返回0,x<y返回小于0的数,x>y返回大于0的数
|
||||
* @see Double#compare(double, double)
|
||||
* @since 3.0.1
|
||||
*/
|
||||
public static int compare(final double x, final double y) {
|
||||
return Double.compare(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较两个值的大小
|
||||
*
|
||||
* @param x 第一个值
|
||||
* @param y 第二个值
|
||||
* @return x==y返回0,x<y返回小于0的数,x>y返回大于0的数
|
||||
* @see Integer#compare(int, int)
|
||||
* @since 3.0.1
|
||||
*/
|
||||
public static int compare(final int x, final int y) {
|
||||
return Integer.compare(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较两个值的大小
|
||||
*
|
||||
* @param x 第一个值
|
||||
* @param y 第二个值
|
||||
* @return x==y返回0,x<y返回小于0的数,x>y返回大于0的数
|
||||
* @see Long#compare(long, long)
|
||||
* @since 3.0.1
|
||||
*/
|
||||
public static int compare(final long x, final long y) {
|
||||
return Long.compare(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较两个值的大小
|
||||
*
|
||||
* @param x 第一个值
|
||||
* @param y 第二个值
|
||||
* @return x==y返回0,x<y返回小于0的数,x>y返回大于0的数
|
||||
* @see Short#compare(short, short)
|
||||
* @since 3.0.1
|
||||
*/
|
||||
public static int compare(final short x, final short y) {
|
||||
return Short.compare(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较两个值的大小
|
||||
*
|
||||
* @param x 第一个值
|
||||
* @param y 第二个值
|
||||
* @return x==y返回0,x<y返回-1,x>y返回1
|
||||
* @see Byte#compare(byte, byte)
|
||||
* @since 3.0.1
|
||||
*/
|
||||
public static int compare(final byte x, final byte y) {
|
||||
return Byte.compare(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取自然排序器,即默认排序器
|
||||
*
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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<Integer>转换为Collection<Number>
|
||||
*
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
//AtomicXXXArray,since 5.4.5
|
||||
@ -454,5 +400,21 @@ public class ConverterRegistry implements Serializable {
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用SPI加载转换器
|
||||
*/
|
||||
private void registerCustomBySpi() {
|
||||
ServiceLoaderUtil.load(Converter.class).forEach(converter -> {
|
||||
try {
|
||||
final Type type = TypeUtil.getTypeArgument(ClassUtil.getClass(converter));
|
||||
if (null != type) {
|
||||
putCustom(type, converter);
|
||||
}
|
||||
} catch (final Exception ignore) {
|
||||
// 忽略注册失败的
|
||||
}
|
||||
});
|
||||
}
|
||||
// ----------------------------------------------------------- Private method end
|
||||
}
|
||||
|
@ -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]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
@ -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){
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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)) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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){
|
||||
|
@ -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 值
|
||||
|
@ -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()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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 时区ID,null表示当前系统默认的时区
|
||||
* @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;
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -45,6 +45,15 @@ public class LocalDateTimeUtil {
|
||||
return LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 当天时间,默认时区
|
||||
*
|
||||
* @return {@link LocalDateTime}
|
||||
*/
|
||||
public static LocalDate today() {
|
||||
return LocalDate.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Instant}转{@link LocalDateTime},使用默认时区
|
||||
*
|
||||
|
@ -4,7 +4,6 @@ package cn.hutool.core.lang.ansi;
|
||||
* 生成ANSI格式的编码输出
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public abstract class AnsiEncoder {
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
@ -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返回0,x<y返回-1,x>y返回1
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(final MutableFloat other) {
|
||||
return NumberUtil.compare(this.value, other.value);
|
||||
return CompareUtil.compare(this.value, other.value);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
@ -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返回0,x<y返回-1,x>y返回1
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(final MutableShort other) {
|
||||
return NumberUtil.compare(this.value, other.value);
|
||||
return CompareUtil.compare(this.value, other.value);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
@ -565,7 +565,7 @@ public class MethodUtil {
|
||||
* @param method 方法(对象方法或static方法都可)
|
||||
* @param args 参数对象
|
||||
* @return 结果
|
||||
* @throws InvocationTargetRuntimeException 目标方法执行异常
|
||||
* @throws InvocationTargetException 目标方法执行异常
|
||||
* @throws IllegalAccessException 访问权限异常
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
||||
/**
|
||||
|
@ -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 {
|
||||
* 注意:此方法获取的是伪随机序列发生器PRNG(pseudo-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 {
|
||||
* 注意:此方法获取的是伪随机序列发生器PRNG(pseudo-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>
|
||||
* 注意:此方法获取的是伪随机序列发生器PRNG(pseudo-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);
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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()) {
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ public class JSONConfig implements Serializable {
|
||||
*
|
||||
* @return JSONConfig
|
||||
*/
|
||||
public static JSONConfig create() {
|
||||
public static JSONConfig of() {
|
||||
return new JSONConfig();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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)) {
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user