mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
add methods
This commit is contained in:
parent
2212ee7705
commit
46764f02b8
@ -18,6 +18,7 @@
|
|||||||
* 【core 】 TypeUtil增加getActualType,增加ActualTypeMapperPool类(issue#I1TBWH@Gitee)
|
* 【core 】 TypeUtil增加getActualType,增加ActualTypeMapperPool类(issue#I1TBWH@Gitee)
|
||||||
* 【extra 】 QRConfig中添加qrVersion属性(pr#1068@Github)
|
* 【extra 】 QRConfig中添加qrVersion属性(pr#1068@Github)
|
||||||
* 【core 】 ArrayUtil增加equals方法
|
* 【core 】 ArrayUtil增加equals方法
|
||||||
|
* 【core 】 BeanDesc增加方法
|
||||||
|
|
||||||
### Bug修复
|
### Bug修复
|
||||||
* 【core 】 重新整理农历节假日,解决一个pr过来的玩笑导致的问题
|
* 【core 】 重新整理农历节假日,解决一个pr过来的玩笑导致的问题
|
||||||
|
@ -61,6 +61,18 @@ public class AnnotationUtil {
|
|||||||
return (null == annotationEle) ? null : toCombination(annotationEle).getAnnotation(annotationType);
|
return (null == annotationEle) ? null : toCombination(annotationEle).getAnnotation(annotationType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否包含指定注解指定注解
|
||||||
|
*
|
||||||
|
* @param annotationEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
|
||||||
|
* @param annotationType 注解类型
|
||||||
|
* @return 是否包含指定注解
|
||||||
|
* @since 5.4.2
|
||||||
|
*/
|
||||||
|
public static boolean hasAnnotation(AnnotatedElement annotationEle, Class<? extends Annotation> annotationType) {
|
||||||
|
return null != getAnnotation(annotationEle, annotationType);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取指定注解默认值<br>
|
* 获取指定注解默认值<br>
|
||||||
* 如果无指定的属性方法返回null
|
* 如果无指定的属性方法返回null
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package cn.hutool.core.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 忽略注解,使用此注解的字段等会被忽略,主要用于Bean拷贝、Bean转Map等
|
||||||
|
*
|
||||||
|
* @author Looly
|
||||||
|
* @since 5.4.2
|
||||||
|
*/
|
||||||
|
@Documented
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
|
||||||
|
public @interface Ignore {
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
package cn.hutool.core.bean;
|
package cn.hutool.core.bean;
|
||||||
|
|
||||||
import cn.hutool.core.annotation.AnnotationUtil;
|
import cn.hutool.core.annotation.AnnotationUtil;
|
||||||
|
import cn.hutool.core.annotation.Ignore;
|
||||||
|
import cn.hutool.core.convert.Convert;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.map.CaseInsensitiveMap;
|
import cn.hutool.core.map.CaseInsensitiveMap;
|
||||||
import cn.hutool.core.util.BooleanUtil;
|
import cn.hutool.core.util.BooleanUtil;
|
||||||
@ -439,7 +441,7 @@ public class BeanDesc implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取字段值<br>
|
* 获取属性值<br>
|
||||||
* 首先调用字段对应的Getter方法获取值,如果Getter方法不存在,则判断字段如果为public,则直接获取字段值
|
* 首先调用字段对应的Getter方法获取值,如果Getter方法不存在,则判断字段如果为public,则直接获取字段值
|
||||||
*
|
*
|
||||||
* @param bean Bean对象
|
* @param bean Bean对象
|
||||||
@ -455,12 +457,42 @@ public class BeanDesc implements Serializable {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取属性值,自动转换属性值类型<br>
|
||||||
|
* 首先调用字段对应的Getter方法获取值,如果Getter方法不存在,则判断字段如果为public,则直接获取字段值
|
||||||
|
*
|
||||||
|
* @param bean Bean对象
|
||||||
|
* @param valueType 返回属性值类型,null表示不转换
|
||||||
|
* @param ignoreError 是否忽略错误,包括转换错误和注入错误
|
||||||
|
* @return this
|
||||||
|
* @since 5.4.2
|
||||||
|
*/
|
||||||
|
public Object getValueWithConvert(Object bean, Type valueType, boolean ignoreError) {
|
||||||
|
Object result = null;
|
||||||
|
try {
|
||||||
|
result = getValue(bean);
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (false == ignoreError) {
|
||||||
|
throw new BeanException(e, "Get value of [{}] error!", getFieldName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null != result && null != valueType) {
|
||||||
|
// 尝试将结果转换为目标类型,如果转换失败,返回原类型。
|
||||||
|
final Object convertValue = Convert.convertWithCheck(valueType, result, null, ignoreError);
|
||||||
|
if (null != convertValue) {
|
||||||
|
result = convertValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置Bean的字段值<br>
|
* 设置Bean的字段值<br>
|
||||||
* 首先调用字段对应的Setter方法,如果Setter方法不存在,则判断字段如果为public,则直接赋值字段值
|
* 首先调用字段对应的Setter方法,如果Setter方法不存在,则判断字段如果为public,则直接赋值字段值
|
||||||
*
|
*
|
||||||
* @param bean Bean对象
|
* @param bean Bean对象
|
||||||
* @param value 值
|
* @param value 值,必须与字段值类型匹配
|
||||||
* @return this
|
* @return this
|
||||||
* @since 4.0.5
|
* @since 4.0.5
|
||||||
*/
|
*/
|
||||||
@ -473,6 +505,44 @@ public class BeanDesc implements Serializable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置属性值,可以自动转换字段类型为目标类型
|
||||||
|
*
|
||||||
|
* @param bean Bean对象
|
||||||
|
* @param value 属性值,可以为任意类型
|
||||||
|
* @param ignoreNull 是否忽略{@code null}值,true表示忽略
|
||||||
|
* @param ignoreError 是否忽略错误,包括转换错误和注入错误
|
||||||
|
* @return this
|
||||||
|
* @since 5.4.2
|
||||||
|
*/
|
||||||
|
public PropDesc setValueWithConvert(Object bean, Object value, boolean ignoreNull, boolean ignoreError) {
|
||||||
|
if (ignoreNull && null == value) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 当类型不匹配的时候,执行默认转换
|
||||||
|
if (null != value) {
|
||||||
|
final Class<?> propClass = getFieldClass();
|
||||||
|
if (false == propClass.isInstance(value)) {
|
||||||
|
value = Convert.convertWithCheck(propClass, value, null, ignoreError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 属性赋值
|
||||||
|
if (null != value || false == ignoreNull) {
|
||||||
|
try {
|
||||||
|
this.setValue(bean, value);
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (false == ignoreError) {
|
||||||
|
throw new BeanException(e, "Set value of [{}] error!", getFieldName());
|
||||||
|
}
|
||||||
|
// 忽略注入失败
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 字段和Getter方法是否为Transient关键字修饰的
|
* 字段和Getter方法是否为Transient关键字修饰的
|
||||||
*
|
*
|
||||||
@ -488,13 +558,43 @@ public class BeanDesc implements Serializable {
|
|||||||
|
|
||||||
// 检查注解
|
// 检查注解
|
||||||
if (false == isTransient) {
|
if (false == isTransient) {
|
||||||
isTransient = null != AnnotationUtil.getAnnotation(this.getter, Transient.class);
|
isTransient = AnnotationUtil.hasAnnotation(this.getter, Transient.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return isTransient;
|
return isTransient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查字段是否被忽略读,通过{@link Ignore} 注解完成,规则为:
|
||||||
|
* <pre>
|
||||||
|
* 1. 在字段上有{@link Ignore} 注解
|
||||||
|
* 2. 在getXXX方法上有{@link Ignore} 注解
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @return 是否忽略读
|
||||||
|
* @since 5.4.2
|
||||||
|
*/
|
||||||
|
public boolean isIgnoreGet() {
|
||||||
|
return AnnotationUtil.hasAnnotation(this.field, Ignore.class)
|
||||||
|
|| AnnotationUtil.hasAnnotation(this.getter, Ignore.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查字段是否被忽略写,通过{@link Ignore} 注解完成,规则为:
|
||||||
|
* <pre>
|
||||||
|
* 1. 在字段上有{@link Ignore} 注解
|
||||||
|
* 2. 在setXXX方法上有{@link Ignore} 注解
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @return 是否忽略写
|
||||||
|
* @since 5.4.2
|
||||||
|
*/
|
||||||
|
public boolean isIgnoreSet() {
|
||||||
|
return AnnotationUtil.hasAnnotation(this.field, Ignore.class)
|
||||||
|
|| AnnotationUtil.hasAnnotation(this.setter, Ignore.class);
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------ Private method start
|
//------------------------------------------------------------------------------------ Private method start
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package cn.hutool.core.bean;
|
package cn.hutool.core.bean;
|
||||||
|
|
||||||
import cn.hutool.core.lang.SimpleCache;
|
import cn.hutool.core.lang.SimpleCache;
|
||||||
|
import cn.hutool.core.lang.func.Func0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bean属性缓存<br>
|
* Bean属性缓存<br>
|
||||||
@ -16,18 +17,11 @@ public enum BeanDescCache {
|
|||||||
/**
|
/**
|
||||||
* 获得属性名和{@link BeanDesc}Map映射
|
* 获得属性名和{@link BeanDesc}Map映射
|
||||||
* @param beanClass Bean的类
|
* @param beanClass Bean的类
|
||||||
|
* @param supplier 对象不存在时创建对象的函数
|
||||||
* @return 属性名和{@link BeanDesc}映射
|
* @return 属性名和{@link BeanDesc}映射
|
||||||
|
* @since 5.4.2
|
||||||
*/
|
*/
|
||||||
public BeanDesc getBeanDesc(Class<?> beanClass){
|
public BeanDesc getBeanDesc(Class<?> beanClass, Func0<BeanDesc> supplier){
|
||||||
return bdCache.get(beanClass);
|
return bdCache.get(beanClass, supplier);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 加入缓存
|
|
||||||
* @param beanClass Bean的类
|
|
||||||
* @param BeanDesc 属性名和{@link BeanDesc}映射
|
|
||||||
*/
|
|
||||||
public void putBeanDesc(Class<?> beanClass, BeanDesc BeanDesc){
|
|
||||||
bdCache.put(beanClass, BeanDesc);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,12 +166,7 @@ public class BeanUtil {
|
|||||||
* @since 3.1.2
|
* @since 3.1.2
|
||||||
*/
|
*/
|
||||||
public static BeanDesc getBeanDesc(Class<?> clazz) {
|
public static BeanDesc getBeanDesc(Class<?> clazz) {
|
||||||
BeanDesc beanDesc = BeanDescCache.INSTANCE.getBeanDesc(clazz);
|
return BeanDescCache.INSTANCE.getBeanDesc(clazz, ()-> new BeanDesc(clazz));
|
||||||
if (null == beanDesc) {
|
|
||||||
beanDesc = new BeanDesc(clazz);
|
|
||||||
BeanDescCache.INSTANCE.putBeanDesc(clazz, beanDesc);
|
|
||||||
}
|
|
||||||
return beanDesc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------- PropertyDescriptor
|
// --------------------------------------------------------------------------------------------------------- PropertyDescriptor
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
package cn.hutool.core.bean.copier;
|
package cn.hutool.core.bean.copier;
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanDesc.PropDesc;
|
import cn.hutool.core.bean.BeanDesc.PropDesc;
|
||||||
|
import cn.hutool.core.bean.BeanException;
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.bean.copier.provider.BeanValueProvider;
|
import cn.hutool.core.bean.copier.provider.BeanValueProvider;
|
||||||
import cn.hutool.core.bean.copier.provider.MapValueProvider;
|
import cn.hutool.core.bean.copier.provider.MapValueProvider;
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.convert.Convert;
|
|
||||||
import cn.hutool.core.exceptions.UtilException;
|
|
||||||
import cn.hutool.core.lang.copier.Copier;
|
import cn.hutool.core.lang.copier.Copier;
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.hutool.core.util.ModifierUtil;
|
import cn.hutool.core.util.ModifierUtil;
|
||||||
@ -23,7 +22,14 @@ import java.util.HashSet;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bean拷贝
|
* Bean拷贝,提供:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* 1. Bean 转 Bean
|
||||||
|
* 2. Bean 转 Map
|
||||||
|
* 3. Map 转 Bean
|
||||||
|
* 4. Map 转 Map
|
||||||
|
* </pre>
|
||||||
*
|
*
|
||||||
* @author looly
|
* @author looly
|
||||||
*
|
*
|
||||||
@ -158,28 +164,26 @@ public class BeanCopier<T> implements Copier<T>, Serializable {
|
|||||||
final CopyOptions copyOptions = this.copyOptions;
|
final CopyOptions copyOptions = this.copyOptions;
|
||||||
|
|
||||||
String key;
|
String key;
|
||||||
Method getter;
|
|
||||||
Object value;
|
Object value;
|
||||||
for (PropDesc prop : props) {
|
for (PropDesc prop : props) {
|
||||||
|
// 忽略注解的字段
|
||||||
|
if(prop.isIgnoreGet()){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
key = prop.getFieldName();
|
key = prop.getFieldName();
|
||||||
// 过滤class属性
|
if (CollUtil.contains(ignoreSet, key)) {
|
||||||
// 得到property对应的getter方法
|
// 目标属性值被忽略或值提供者无此key时跳过
|
||||||
getter = prop.getGetter();
|
continue;
|
||||||
if (null != getter) {
|
}
|
||||||
// 只读取有getter方法的属性
|
|
||||||
try {
|
try {
|
||||||
value = getter.invoke(bean);
|
value = prop.getValue(bean);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (copyOptions.ignoreError) {
|
if (copyOptions.ignoreError) {
|
||||||
continue;// 忽略反射失败
|
continue;// 忽略反射失败
|
||||||
} else {
|
} else {
|
||||||
throw new UtilException(e, "Get value of [{}] error!", prop.getFieldName());
|
throw new BeanException(e, "Get value of [{}] error!", prop.getFieldName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (CollUtil.contains(ignoreSet, key)) {
|
|
||||||
// 目标属性值被忽略或值提供者无此key时跳过
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (null == value && copyOptions.ignoreNullValue) {
|
if (null == value && copyOptions.ignoreNullValue) {
|
||||||
continue;// 当允许跳过空时,跳过
|
continue;// 当允许跳过空时,跳过
|
||||||
}
|
}
|
||||||
@ -189,7 +193,6 @@ public class BeanCopier<T> implements Copier<T>, Serializable {
|
|||||||
targetMap.put(mappingKey(copyOptions.fieldMapping, key), value);
|
targetMap.put(mappingKey(copyOptions.fieldMapping, key), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 值提供器转Bean
|
* 值提供器转Bean
|
||||||
@ -228,6 +231,17 @@ public class BeanCopier<T> implements Copier<T>, Serializable {
|
|||||||
// 目标属性值被忽略或值提供者无此key时跳过
|
// 目标属性值被忽略或值提供者无此key时跳过
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 在支持情况下,忽略transient修饰(包括修饰和注解)
|
||||||
|
if(copyOptions.isTransientSupport() && prop.isTransient()){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Ignore修饰的字段和setXXX方法忽略之
|
||||||
|
if(prop.isIgnoreSet()){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
final String providerKey = mappingKey(fieldReverseMapping, fieldName);
|
final String providerKey = mappingKey(fieldReverseMapping, fieldName);
|
||||||
if (false == valueProvider.containsKey(providerKey)) {
|
if (false == valueProvider.containsKey(providerKey)) {
|
||||||
// 无对应值可提供
|
// 无对应值可提供
|
||||||
@ -241,34 +255,18 @@ public class BeanCopier<T> implements Copier<T>, Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取目标字段真实类型
|
// 获取目标字段真实类型
|
||||||
Type fieldType = (null == setterMethod) ? TypeUtil.getType(field) : TypeUtil.getFirstParamType(setterMethod);
|
final Type fieldType = TypeUtil.getActualType(this.destType ,prop.getFieldType());
|
||||||
fieldType = TypeUtil.getActualType(this.destType ,fieldType);
|
|
||||||
|
|
||||||
value = valueProvider.value(providerKey, fieldType);
|
value = valueProvider.value(providerKey, fieldType);
|
||||||
if (null == value && copyOptions.ignoreNullValue) {
|
if (null == value && copyOptions.ignoreNullValue) {
|
||||||
continue;// 当允许跳过空时,跳过
|
continue;// 当允许跳过空时,跳过
|
||||||
}
|
}
|
||||||
if (bean == value) {
|
if (bean == value) {
|
||||||
continue;// 值不能为bean本身,防止循环引用
|
// 值不能为bean本身,防止循环引用
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
prop.setValueWithConvert(bean, value, copyOptions.ignoreNullValue, copyOptions.ignoreError);
|
||||||
// valueProvider在没有对值做转换且当类型不匹配的时候,执行默认转换
|
|
||||||
propClass = prop.getFieldClass();
|
|
||||||
if (false ==propClass.isInstance(value)) {
|
|
||||||
value = Convert.convertWithCheck(propClass, value, null, copyOptions.ignoreError);
|
|
||||||
if (null == value && copyOptions.ignoreNullValue) {
|
|
||||||
continue;// 当允许跳过空时,跳过
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prop.setValue(bean, value);
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (false ==copyOptions.ignoreError) {
|
|
||||||
throw new UtilException(e, "Inject [{}] error!", prop.getFieldName());
|
|
||||||
}
|
|
||||||
// 忽略注入失败
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package cn.hutool.core.bean.copier;
|
package cn.hutool.core.bean.copier;
|
||||||
|
|
||||||
|
import cn.hutool.core.map.MapUtil;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import cn.hutool.core.map.MapUtil;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 属性拷贝选项<br>
|
* 属性拷贝选项<br>
|
||||||
* 包括:<br>
|
* 包括:<br>
|
||||||
@ -14,21 +14,37 @@ import cn.hutool.core.map.MapUtil;
|
|||||||
*
|
*
|
||||||
* @author Looly
|
* @author Looly
|
||||||
*/
|
*/
|
||||||
public class CopyOptions implements Serializable{
|
public class CopyOptions implements Serializable {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/** 限制的类或接口,必须为目标对象的实现接口或父类,用于限制拷贝的属性,例如一个类我只想复制其父类的一些属性,就可以将editable设置为父类 */
|
/**
|
||||||
|
* 限制的类或接口,必须为目标对象的实现接口或父类,用于限制拷贝的属性,例如一个类我只想复制其父类的一些属性,就可以将editable设置为父类
|
||||||
|
*/
|
||||||
protected Class<?> editable;
|
protected Class<?> editable;
|
||||||
/** 是否忽略空值,当源对象的值为null时,true: 忽略而不注入此值,false: 注入null */
|
/**
|
||||||
|
* 是否忽略空值,当源对象的值为null时,true: 忽略而不注入此值,false: 注入null
|
||||||
|
*/
|
||||||
protected boolean ignoreNullValue;
|
protected boolean ignoreNullValue;
|
||||||
/** 忽略的目标对象中属性列表,设置一个属性列表,不拷贝这些属性值 */
|
/**
|
||||||
|
* 忽略的目标对象中属性列表,设置一个属性列表,不拷贝这些属性值
|
||||||
|
*/
|
||||||
protected String[] ignoreProperties;
|
protected String[] ignoreProperties;
|
||||||
/** 是否忽略字段注入错误 */
|
/**
|
||||||
|
* 是否忽略字段注入错误
|
||||||
|
*/
|
||||||
protected boolean ignoreError;
|
protected boolean ignoreError;
|
||||||
/** 是否忽略字段大小写 */
|
/**
|
||||||
|
* 是否忽略字段大小写
|
||||||
|
*/
|
||||||
protected boolean ignoreCase;
|
protected boolean ignoreCase;
|
||||||
/** 拷贝属性的字段映射,用于不同的属性之前拷贝做对应表用 */
|
/**
|
||||||
|
* 拷贝属性的字段映射,用于不同的属性之前拷贝做对应表用
|
||||||
|
*/
|
||||||
protected Map<String, String> fieldMapping;
|
protected Map<String, String> fieldMapping;
|
||||||
|
/**
|
||||||
|
* 是否支持transient关键字修饰和@Transient注解,如果支持,被修饰的字段或方法对应的字段将被忽略。
|
||||||
|
*/
|
||||||
|
private boolean transientSupport = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建拷贝选项
|
* 创建拷贝选项
|
||||||
@ -166,8 +182,31 @@ public class CopyOptions implements Serializable{
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否支持transient关键字修饰和@Transient注解,如果支持,被修饰的字段或方法对应的字段将被忽略。
|
||||||
|
*
|
||||||
|
* @return 是否支持
|
||||||
|
* @since 5.4.2
|
||||||
|
*/
|
||||||
|
public boolean isTransientSupport() {
|
||||||
|
return this.transientSupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置是否支持transient关键字修饰和@Transient注解,如果支持,被修饰的字段或方法对应的字段将被忽略。
|
||||||
|
*
|
||||||
|
* @param transientSupport 是否支持
|
||||||
|
* @return this
|
||||||
|
* @since 5.4.2
|
||||||
|
*/
|
||||||
|
public CopyOptions setTransientSupport(boolean transientSupport) {
|
||||||
|
this.transientSupport = transientSupport;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取反转之后的映射
|
* 获取反转之后的映射
|
||||||
|
*
|
||||||
* @return 反转映射
|
* @return 反转映射
|
||||||
* @since 4.1.10
|
* @since 4.1.10
|
||||||
*/
|
*/
|
||||||
|
@ -3,11 +3,8 @@ package cn.hutool.core.bean.copier.provider;
|
|||||||
import cn.hutool.core.bean.BeanDesc.PropDesc;
|
import cn.hutool.core.bean.BeanDesc.PropDesc;
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.bean.copier.ValueProvider;
|
import cn.hutool.core.bean.copier.ValueProvider;
|
||||||
import cn.hutool.core.convert.Convert;
|
|
||||||
import cn.hutool.core.exceptions.UtilException;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -46,29 +43,32 @@ public class BeanValueProvider implements ValueProvider<String> {
|
|||||||
|
|
||||||
Object result = null;
|
Object result = null;
|
||||||
if (null != sourcePd) {
|
if (null != sourcePd) {
|
||||||
final Method getter = sourcePd.getGetter();
|
result = sourcePd.getValueWithConvert(this.source, valueType, this.ignoreError);
|
||||||
if (null != getter) {
|
|
||||||
try {
|
|
||||||
result = getter.invoke(source);
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (false == ignoreError) {
|
|
||||||
throw new UtilException(e, "Inject [{}] error!", key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 尝试将结果转换为目标类型,如果转换失败,返回原类型。
|
|
||||||
final Object convertValue = Convert.convertWithCheck(valueType,result, null, ignoreError);
|
|
||||||
if(null != convertValue){
|
|
||||||
result = convertValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean containsKey(String key) {
|
public boolean containsKey(String key) {
|
||||||
return sourcePdMap.containsKey(key) || sourcePdMap.containsKey(StrUtil.upperFirstAndAddPre(key, "is"));
|
PropDesc sourcePd = getPropDesc(key);
|
||||||
|
|
||||||
|
// 字段描述不存在或忽略读的情况下,表示不存在
|
||||||
|
return null != sourcePd && false == sourcePd.isIgnoreGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得属性描述
|
||||||
|
*
|
||||||
|
* @param key 字段名
|
||||||
|
* @return 属性描述
|
||||||
|
*/
|
||||||
|
private PropDesc getPropDesc(String key){
|
||||||
|
PropDesc sourcePd = sourcePdMap.get(key);
|
||||||
|
if(null == sourcePd) {
|
||||||
|
//boolean类型字段字段名支持两种方式
|
||||||
|
sourcePd = sourcePdMap.get(StrUtil.upperFirstAndAddPre(key, "is"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sourcePd;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,10 +9,10 @@ import java.lang.reflect.Type;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map值提供者
|
* Map值提供者,支持驼峰和下划线的key兼容。<br>
|
||||||
|
* 假设目标属性为firstName,则Map中为firstName或first_name都可以对应到值。
|
||||||
*
|
*
|
||||||
* @author looly
|
* @author looly
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class MapValueProvider implements ValueProvider<String> {
|
public class MapValueProvider implements ValueProvider<String> {
|
||||||
|
|
||||||
@ -38,10 +38,10 @@ public class MapValueProvider implements ValueProvider<String> {
|
|||||||
* @since 5.3.2
|
* @since 5.3.2
|
||||||
*/
|
*/
|
||||||
public MapValueProvider(Map<?, ?> map, boolean ignoreCase, boolean ignoreError) {
|
public MapValueProvider(Map<?, ?> map, boolean ignoreCase, boolean ignoreError) {
|
||||||
if(false == ignoreCase || map instanceof CaseInsensitiveMap) {
|
if (false == ignoreCase || map instanceof CaseInsensitiveMap) {
|
||||||
//不忽略大小写或者提供的Map本身为CaseInsensitiveMap则无需转换
|
//不忽略大小写或者提供的Map本身为CaseInsensitiveMap则无需转换
|
||||||
this.map = map;
|
this.map = map;
|
||||||
}else {
|
} else {
|
||||||
//转换为大小写不敏感的Map
|
//转换为大小写不敏感的Map
|
||||||
this.map = new CaseInsensitiveMap<>(map);
|
this.map = new CaseInsensitiveMap<>(map);
|
||||||
}
|
}
|
||||||
@ -51,7 +51,7 @@ public class MapValueProvider implements ValueProvider<String> {
|
|||||||
@Override
|
@Override
|
||||||
public Object value(String key, Type valueType) {
|
public Object value(String key, Type valueType) {
|
||||||
Object value = map.get(key);
|
Object value = map.get(key);
|
||||||
if(null == value) {
|
if (null == value) {
|
||||||
//检查下划线模式
|
//检查下划线模式
|
||||||
value = map.get(StrUtil.toUnderlineCase(key));
|
value = map.get(StrUtil.toUnderlineCase(key));
|
||||||
}
|
}
|
||||||
@ -61,9 +61,9 @@ public class MapValueProvider implements ValueProvider<String> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean containsKey(String key) {
|
public boolean containsKey(String key) {
|
||||||
if(map.containsKey(key)) {
|
if (map.containsKey(key)) {
|
||||||
return true;
|
return true;
|
||||||
}else {
|
} else {
|
||||||
//检查下划线模式
|
//检查下划线模式
|
||||||
return map.containsKey(StrUtil.toUnderlineCase(key));
|
return map.containsKey(StrUtil.toUnderlineCase(key));
|
||||||
}
|
}
|
||||||
|
@ -32,9 +32,9 @@ public class JSONConfig implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private boolean ignoreNullValue = true;
|
private boolean ignoreNullValue = true;
|
||||||
/**
|
/**
|
||||||
* 是否忽略transient关键字修饰的字段
|
* 是否支持transient关键字修饰和@Transient注解,如果支持,被修饰的字段或方法对应的字段将被忽略。
|
||||||
*/
|
*/
|
||||||
private boolean ignoreTransient = true;
|
private boolean transientSupport = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建默认的配置项
|
* 创建默认的配置项
|
||||||
@ -150,9 +150,11 @@ public class JSONConfig implements Serializable {
|
|||||||
*
|
*
|
||||||
* @return 是否忽略transient关键字修饰的字段
|
* @return 是否忽略transient关键字修饰的字段
|
||||||
* @since 5.3.11
|
* @since 5.3.11
|
||||||
|
* @deprecated 此方法名称有二义性,请使用{@link #isTransientSupport()}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public boolean isIgnoreTransient() {
|
public boolean isIgnoreTransient() {
|
||||||
return this.ignoreTransient;
|
return isTransientSupport();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -161,9 +163,32 @@ public class JSONConfig implements Serializable {
|
|||||||
* @param ignoreTransient 是否忽略transient关键字修饰的字段
|
* @param ignoreTransient 是否忽略transient关键字修饰的字段
|
||||||
* @return this
|
* @return this
|
||||||
* @since 5.3.11
|
* @since 5.3.11
|
||||||
|
* @deprecated 此方法名称有二义性,请使用{@link #setTransientSupport(boolean)}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public JSONConfig setIgnoreTransient(boolean ignoreTransient) {
|
public JSONConfig setIgnoreTransient(boolean ignoreTransient) {
|
||||||
this.ignoreTransient = ignoreTransient;
|
return setTransientSupport(ignoreTransient);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否支持transient关键字修饰和@Transient注解,如果支持,被修饰的字段或方法对应的字段将被忽略。
|
||||||
|
*
|
||||||
|
* @return 是否支持
|
||||||
|
* @since 5.4.2
|
||||||
|
*/
|
||||||
|
public boolean isTransientSupport() {
|
||||||
|
return this.transientSupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置是否支持transient关键字修饰和@Transient注解,如果支持,被修饰的字段或方法对应的字段将被忽略。
|
||||||
|
*
|
||||||
|
* @param transientSupport 是否支持
|
||||||
|
* @return this
|
||||||
|
* @since 5.4.2
|
||||||
|
*/
|
||||||
|
public JSONConfig setTransientSupport(boolean transientSupport) {
|
||||||
|
this.transientSupport = transientSupport;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -625,7 +625,7 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
|
|||||||
Method getter;
|
Method getter;
|
||||||
Object value;
|
Object value;
|
||||||
for (PropDesc prop : props) {
|
for (PropDesc prop : props) {
|
||||||
if(this.config.isIgnoreTransient() && prop.isTransient()){
|
if(this.config.isTransientSupport() && prop.isTransient()){
|
||||||
// 忽略Transient字段和方法
|
// 忽略Transient字段和方法
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user