add DynabeanValueProvider

This commit is contained in:
Looly 2020-09-09 00:16:56 +08:00
parent a5624e6f94
commit 5aa10c06ee
4 changed files with 125 additions and 69 deletions

View File

@ -6,7 +6,6 @@ import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.ReflectUtil;
import java.io.Serializable; import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Map; import java.util.Map;
/** /**
@ -16,7 +15,7 @@ import java.util.Map;
* @author Looly * @author Looly
* @since 3.0.7 * @since 3.0.7
*/ */
public class DynaBean extends CloneSupport<DynaBean> implements Serializable{ public class DynaBean extends CloneSupport<DynaBean> implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final Class<?> beanClass; private final Class<?> beanClass;
@ -24,40 +23,46 @@ public class DynaBean extends CloneSupport<DynaBean> implements Serializable{
/** /**
* 创建一个{@link DynaBean} * 创建一个{@link DynaBean}
*
* @param bean 普通Bean * @param bean 普通Bean
* @return {@link DynaBean} * @return {@link DynaBean}
*/ */
public static DynaBean create(Object bean){ public static DynaBean create(Object bean) {
return new DynaBean(bean); return new DynaBean(bean);
} }
/** /**
* 创建一个{@link DynaBean} * 创建一个{@link DynaBean}
*
* @param beanClass Bean类 * @param beanClass Bean类
* @param params 构造Bean所需要的参数 * @param params 构造Bean所需要的参数
* @return {@link DynaBean} * @return {@link DynaBean}
*/ */
public static DynaBean create(Class<?> beanClass, Object... params){ public static DynaBean create(Class<?> beanClass, Object... params) {
return new DynaBean(beanClass, params); return new DynaBean(beanClass, params);
} }
//------------------------------------------------------------------------ Constructor start //------------------------------------------------------------------------ Constructor start
/** /**
* 构造 * 构造
*
* @param beanClass Bean类 * @param beanClass Bean类
* @param params 构造Bean所需要的参数 * @param params 构造Bean所需要的参数
*/ */
public DynaBean(Class<?> beanClass, Object... params){ public DynaBean(Class<?> beanClass, Object... params) {
this(ReflectUtil.newInstance(beanClass, params)); this(ReflectUtil.newInstance(beanClass, params));
} }
/** /**
* 构造 * 构造
*
* @param bean 原始Bean * @param bean 原始Bean
*/ */
public DynaBean(Object bean){ public DynaBean(Object bean) {
Assert.notNull(bean); Assert.notNull(bean);
if(bean instanceof DynaBean){ if (bean instanceof DynaBean) {
bean = ((DynaBean)bean).getBean(); bean = ((DynaBean) bean).getBean();
} }
this.bean = bean; this.bean = bean;
this.beanClass = ClassUtil.getClass(bean); this.beanClass = ClassUtil.getClass(bean);
@ -66,37 +71,45 @@ public class DynaBean extends CloneSupport<DynaBean> implements Serializable{
/** /**
* 获得字段对应值 * 获得字段对应值
* @param <T> 属性值类型 *
* @param <T> 属性值类型
* @param fieldName 字段名 * @param fieldName 字段名
* @return 字段值 * @return 字段值
* @throws BeanException 反射获取属性值或字段值导致的异常 * @throws BeanException 反射获取属性值或字段值导致的异常
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> T get(String fieldName) throws BeanException{ public <T> T get(String fieldName) throws BeanException {
if(Map.class.isAssignableFrom(beanClass)){ if (Map.class.isAssignableFrom(beanClass)) {
return (T) ((Map<?, ?>)bean).get(fieldName); return (T) ((Map<?, ?>) bean).get(fieldName);
}else{ } else {
try { final BeanDesc.PropDesc prop = BeanUtil.getBeanDesc(beanClass).getProp(fieldName);
final Method method = BeanUtil.getBeanDesc(beanClass).getGetter(fieldName); if(null == prop){
if(null == method){ throw new BeanException("No public field or get method for {}", fieldName);
throw new BeanException("No get method for {}", fieldName);
}
return (T) method.invoke(this.bean);
} catch (Exception e) {
throw new BeanException(e);
} }
return (T) prop.getValue(bean);
} }
} }
/**
* 检查是否有指定名称的bean属性
*
* @param fieldName 字段名
* @return 是否有bean属性
* @since 5.4.2
*/
public boolean containsProp(String fieldName){
return null != BeanUtil.getBeanDesc(beanClass).getProp(fieldName);
}
/** /**
* 获得字段对应值获取异常返回{@code null} * 获得字段对应值获取异常返回{@code null}
* *
* @param <T> 属性值类型 * @param <T> 属性值类型
* @param fieldName 字段名 * @param fieldName 字段名
* @return 字段值 * @return 字段值
* @since 3.1.1 * @since 3.1.1
*/ */
public <T> T safeGet(String fieldName){ public <T> T safeGet(String fieldName) {
try { try {
return get(fieldName); return get(fieldName);
} catch (Exception e) { } catch (Exception e) {
@ -106,54 +119,54 @@ public class DynaBean extends CloneSupport<DynaBean> implements Serializable{
/** /**
* 设置字段值 * 设置字段值
*
* @param fieldName 字段名 * @param fieldName 字段名
* @param value 字段值 * @param value 字段值
* @throws BeanException 反射获取属性值或字段值导致的异常 * @throws BeanException 反射获取属性值或字段值导致的异常
*/ */
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({"unchecked", "rawtypes"})
public void set(String fieldName, Object value) throws BeanException{ public void set(String fieldName, Object value) throws BeanException {
if(Map.class.isAssignableFrom(beanClass)){ if (Map.class.isAssignableFrom(beanClass)) {
((Map)bean).put(fieldName, value); ((Map) bean).put(fieldName, value);
}else{ } else {
try { final BeanDesc.PropDesc prop = BeanUtil.getBeanDesc(beanClass).getProp(fieldName);
final Method setter = BeanUtil.getBeanDesc(beanClass).getSetter(fieldName); if(null == prop){
if(null == setter){ throw new BeanException("No public field or set method for {}", fieldName);
throw new BeanException("No set method for {}", fieldName);
}
setter.invoke(this.bean, value);
} catch (Exception e) {
throw new BeanException(e);
} }
prop.setValue(bean, value);
} }
} }
/** /**
* 执行原始Bean中的方法 * 执行原始Bean中的方法
*
* @param methodName 方法名 * @param methodName 方法名
* @param params 参数 * @param params 参数
* @return 执行结果可能为null * @return 执行结果可能为null
*/ */
public Object invoke(String methodName, Object... params){ public Object invoke(String methodName, Object... params) {
return ReflectUtil.invoke(this.bean, methodName, params); return ReflectUtil.invoke(this.bean, methodName, params);
} }
/** /**
* 获得原始Bean * 获得原始Bean
*
* @param <T> Bean类型 * @param <T> Bean类型
* @return bean * @return bean
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> T getBean(){ public <T> T getBean() {
return (T)this.bean; return (T) this.bean;
} }
/** /**
* 获得Bean的类型 * 获得Bean的类型
*
* @param <T> Bean类型 * @param <T> Bean类型
* @return Bean类型 * @return Bean类型
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> Class<T> getBeanClass(){ public <T> Class<T> getBeanClass() {
return (Class<T>) this.beanClass; return (Class<T>) this.beanClass;
} }

View File

@ -3,7 +3,9 @@ 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.BeanException;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.DynaBean;
import cn.hutool.core.bean.copier.provider.BeanValueProvider; import cn.hutool.core.bean.copier.provider.BeanValueProvider;
import cn.hutool.core.bean.copier.provider.DynaBeanValueProvider;
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.lang.copier.Copier; import cn.hutool.core.lang.copier.Copier;
@ -97,6 +99,9 @@ public class BeanCopier<T> implements Copier<T>, Serializable {
if (this.source instanceof ValueProvider) { if (this.source instanceof ValueProvider) {
// 目标只支持Bean // 目标只支持Bean
valueProviderToBean((ValueProvider<String>) this.source, this.dest); valueProviderToBean((ValueProvider<String>) this.source, this.dest);
} else if (this.source instanceof DynaBean) {
// 目标只支持Bean
valueProviderToBean(new DynaBeanValueProvider((DynaBean) this.source, copyOptions.ignoreError), this.dest);
} else if (this.source instanceof Map) { } else if (this.source instanceof Map) {
if (this.dest instanceof Map) { if (this.dest instanceof Map) {
mapToMap((Map<?, ?>) this.source, (Map<?, ?>) this.dest); mapToMap((Map<?, ?>) this.source, (Map<?, ?>) this.dest);

View File

@ -12,7 +12,6 @@ import java.util.Map;
* Bean的值提供者 * Bean的值提供者
* *
* @author looly * @author looly
*
*/ */
public class BeanValueProvider implements ValueProvider<String> { public class BeanValueProvider implements ValueProvider<String> {
@ -23,8 +22,8 @@ public class BeanValueProvider implements ValueProvider<String> {
/** /**
* 构造 * 构造
* *
* @param bean Bean * @param bean Bean
* @param ignoreCase 是否忽略字段大小写 * @param ignoreCase 是否忽略字段大小写
* @param ignoreError 是否忽略字段值读取错误 * @param ignoreError 是否忽略字段值读取错误
*/ */
public BeanValueProvider(Object bean, boolean ignoreCase, boolean ignoreError) { public BeanValueProvider(Object bean, boolean ignoreCase, boolean ignoreError) {
@ -35,11 +34,7 @@ public class BeanValueProvider implements ValueProvider<String> {
@Override @Override
public Object value(String key, Type valueType) { public Object value(String key, Type valueType) {
PropDesc sourcePd = sourcePdMap.get(key); final PropDesc sourcePd = getPropDesc(key, valueType);
if(null == sourcePd && (Boolean.class == valueType || boolean.class == valueType)) {
//boolean类型字段字段名支持两种方式
sourcePd = sourcePdMap.get(StrUtil.upperFirstAndAddPre(key, "is"));
}
Object result = null; Object result = null;
if (null != sourcePd) { if (null != sourcePd) {
@ -50,7 +45,7 @@ public class BeanValueProvider implements ValueProvider<String> {
@Override @Override
public boolean containsKey(String key) { public boolean containsKey(String key) {
PropDesc sourcePd = getPropDesc(key); final PropDesc sourcePd = getPropDesc(key, null);
// 字段描述不存在或忽略读的情况下表示不存在 // 字段描述不存在或忽略读的情况下表示不存在
return null != sourcePd && false == sourcePd.isIgnoreGet(); return null != sourcePd && false == sourcePd.isIgnoreGet();
@ -59,12 +54,13 @@ public class BeanValueProvider implements ValueProvider<String> {
/** /**
* 获得属性描述 * 获得属性描述
* *
* @param key 字段名 * @param key 字段名
* @param valueType 值类型用于判断是否为Boolean可以为null
* @return 属性描述 * @return 属性描述
*/ */
private PropDesc getPropDesc(String key){ private PropDesc getPropDesc(String key, Type valueType) {
PropDesc sourcePd = sourcePdMap.get(key); PropDesc sourcePd = sourcePdMap.get(key);
if(null == sourcePd) { if (null == sourcePd && (null == valueType || Boolean.class == valueType || boolean.class == valueType)) {
//boolean类型字段字段名支持两种方式 //boolean类型字段字段名支持两种方式
sourcePd = sourcePdMap.get(StrUtil.upperFirstAndAddPre(key, "is")); sourcePd = sourcePdMap.get(StrUtil.upperFirstAndAddPre(key, "is"));
} }

View File

@ -0,0 +1,42 @@
package cn.hutool.core.bean.copier.provider;
import cn.hutool.core.bean.DynaBean;
import cn.hutool.core.bean.copier.ValueProvider;
import cn.hutool.core.convert.Convert;
import java.lang.reflect.Type;
/**
* DynaBean值提供者
*
* @author looly
* @since 5.4.2
*/
public class DynaBeanValueProvider implements ValueProvider<String> {
private final DynaBean dynaBean;
private final boolean ignoreError;
/**
* 构造
*
* @param dynaBean DynaBean
* @param ignoreError 是否忽略错误
*/
public DynaBeanValueProvider(DynaBean dynaBean, boolean ignoreError) {
this.dynaBean = dynaBean;
this.ignoreError = ignoreError;
}
@Override
public Object value(String key, Type valueType) {
final Object value = dynaBean.get(key);
return Convert.convertWithCheck(valueType, value, null, this.ignoreError);
}
@Override
public boolean containsKey(String key) {
return dynaBean.containsProp(key);
}
}