diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/DynaBean.java b/hutool-core/src/main/java/cn/hutool/core/bean/DynaBean.java
index 8df3da986..e9a3a6621 100644
--- a/hutool-core/src/main/java/cn/hutool/core/bean/DynaBean.java
+++ b/hutool-core/src/main/java/cn/hutool/core/bean/DynaBean.java
@@ -6,154 +6,167 @@ import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import java.io.Serializable;
-import java.lang.reflect.Method;
import java.util.Map;
/**
* 动态Bean,通过反射对Bean的相关方法做操作
* 支持Map和普通Bean
- *
+ *
* @author Looly
* @since 3.0.7
*/
-public class DynaBean extends CloneSupport implements Serializable{
+public class DynaBean extends CloneSupport implements Serializable {
private static final long serialVersionUID = 1L;
private final Class> beanClass;
private final Object bean;
-
+
/**
* 创建一个{@link DynaBean}
+ *
* @param bean 普通Bean
* @return {@link DynaBean}
*/
- public static DynaBean create(Object bean){
+ public static DynaBean create(Object bean) {
return new DynaBean(bean);
}
+
/**
* 创建一个{@link DynaBean}
+ *
* @param beanClass Bean类
- * @param params 构造Bean所需要的参数
+ * @param params 构造Bean所需要的参数
* @return {@link DynaBean}
*/
- public static DynaBean create(Class> beanClass, Object... params){
+ public static DynaBean create(Class> beanClass, Object... params) {
return new DynaBean(beanClass, params);
}
-
+
//------------------------------------------------------------------------ Constructor start
+
/**
* 构造
+ *
* @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));
}
-
+
/**
* 构造
+ *
* @param bean 原始Bean
*/
- public DynaBean(Object bean){
+ public DynaBean(Object bean) {
Assert.notNull(bean);
- if(bean instanceof DynaBean){
- bean = ((DynaBean)bean).getBean();
+ if (bean instanceof DynaBean) {
+ bean = ((DynaBean) bean).getBean();
}
this.bean = bean;
this.beanClass = ClassUtil.getClass(bean);
}
//------------------------------------------------------------------------ Constructor end
-
+
/**
* 获得字段对应值
- * @param 属性值类型
+ *
+ * @param 属性值类型
* @param fieldName 字段名
* @return 字段值
* @throws BeanException 反射获取属性值或字段值导致的异常
*/
@SuppressWarnings("unchecked")
- public T get(String fieldName) throws BeanException{
- if(Map.class.isAssignableFrom(beanClass)){
- return (T) ((Map, ?>)bean).get(fieldName);
- }else{
- try {
- final Method method = BeanUtil.getBeanDesc(beanClass).getGetter(fieldName);
- if(null == method){
- throw new BeanException("No get method for {}", fieldName);
- }
- return (T) method.invoke(this.bean);
- } catch (Exception e) {
- throw new BeanException(e);
+ public T get(String fieldName) throws BeanException {
+ if (Map.class.isAssignableFrom(beanClass)) {
+ return (T) ((Map, ?>) bean).get(fieldName);
+ } else {
+ final BeanDesc.PropDesc prop = BeanUtil.getBeanDesc(beanClass).getProp(fieldName);
+ if(null == prop){
+ throw new BeanException("No public field or get method for {}", fieldName);
}
+ 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}
- *
- * @param 属性值类型
+ *
+ * @param 属性值类型
* @param fieldName 字段名
* @return 字段值
* @since 3.1.1
*/
- public T safeGet(String fieldName){
+ public T safeGet(String fieldName) {
try {
return get(fieldName);
} catch (Exception e) {
return null;
}
}
-
+
/**
* 设置字段值
+ *
* @param fieldName 字段名
- * @param value 字段值
+ * @param value 字段值
* @throws BeanException 反射获取属性值或字段值导致的异常
*/
- @SuppressWarnings({ "unchecked", "rawtypes" })
- public void set(String fieldName, Object value) throws BeanException{
- if(Map.class.isAssignableFrom(beanClass)){
- ((Map)bean).put(fieldName, value);
- }else{
- try {
- final Method setter = BeanUtil.getBeanDesc(beanClass).getSetter(fieldName);
- if(null == setter){
- throw new BeanException("No set method for {}", fieldName);
- }
- setter.invoke(this.bean, value);
- } catch (Exception e) {
- throw new BeanException(e);
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public void set(String fieldName, Object value) throws BeanException {
+ if (Map.class.isAssignableFrom(beanClass)) {
+ ((Map) bean).put(fieldName, value);
+ } else {
+ final BeanDesc.PropDesc prop = BeanUtil.getBeanDesc(beanClass).getProp(fieldName);
+ if(null == prop){
+ throw new BeanException("No public field or set method for {}", fieldName);
}
+ prop.setValue(bean, value);
}
}
-
+
/**
* 执行原始Bean中的方法
+ *
* @param methodName 方法名
- * @param params 参数
+ * @param params 参数
* @return 执行结果,可能为null
*/
- public Object invoke(String methodName, Object... params){
+ public Object invoke(String methodName, Object... params) {
return ReflectUtil.invoke(this.bean, methodName, params);
}
-
+
/**
* 获得原始Bean
+ *
* @param Bean类型
* @return bean
*/
@SuppressWarnings("unchecked")
- public T getBean(){
- return (T)this.bean;
+ public T getBean() {
+ return (T) this.bean;
}
-
+
/**
* 获得Bean的类型
+ *
* @param Bean类型
* @return Bean类型
*/
@SuppressWarnings("unchecked")
- public Class getBeanClass(){
+ public Class getBeanClass() {
return (Class) this.beanClass;
}
diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanCopier.java b/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanCopier.java
index 756c260f4..4cb9792e6 100644
--- a/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanCopier.java
+++ b/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanCopier.java
@@ -3,7 +3,9 @@ package cn.hutool.core.bean.copier;
import cn.hutool.core.bean.BeanDesc.PropDesc;
import cn.hutool.core.bean.BeanException;
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.DynaBeanValueProvider;
import cn.hutool.core.bean.copier.provider.MapValueProvider;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.copier.Copier;
@@ -97,6 +99,9 @@ public class BeanCopier implements Copier, Serializable {
if (this.source instanceof ValueProvider) {
// 目标只支持Bean
valueProviderToBean((ValueProvider) 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) {
if (this.dest instanceof Map) {
mapToMap((Map, ?>) this.source, (Map, ?>) this.dest);
diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/copier/provider/BeanValueProvider.java b/hutool-core/src/main/java/cn/hutool/core/bean/copier/provider/BeanValueProvider.java
index d92c82641..bdbae6880 100644
--- a/hutool-core/src/main/java/cn/hutool/core/bean/copier/provider/BeanValueProvider.java
+++ b/hutool-core/src/main/java/cn/hutool/core/bean/copier/provider/BeanValueProvider.java
@@ -10,9 +10,8 @@ import java.util.Map;
/**
* Bean的值提供者
- *
- * @author looly
*
+ * @author looly
*/
public class BeanValueProvider implements ValueProvider {
@@ -22,9 +21,9 @@ public class BeanValueProvider implements ValueProvider {
/**
* 构造
- *
- * @param bean Bean
- * @param ignoreCase 是否忽略字段大小写
+ *
+ * @param bean Bean
+ * @param ignoreCase 是否忽略字段大小写
* @param ignoreError 是否忽略字段值读取错误
*/
public BeanValueProvider(Object bean, boolean ignoreCase, boolean ignoreError) {
@@ -35,11 +34,7 @@ public class BeanValueProvider implements ValueProvider {
@Override
public Object value(String key, Type valueType) {
- PropDesc sourcePd = sourcePdMap.get(key);
- if(null == sourcePd && (Boolean.class == valueType || boolean.class == valueType)) {
- //boolean类型字段字段名支持两种方式
- sourcePd = sourcePdMap.get(StrUtil.upperFirstAndAddPre(key, "is"));
- }
+ final PropDesc sourcePd = getPropDesc(key, valueType);
Object result = null;
if (null != sourcePd) {
@@ -50,7 +45,7 @@ public class BeanValueProvider implements ValueProvider {
@Override
public boolean containsKey(String key) {
- PropDesc sourcePd = getPropDesc(key);
+ final PropDesc sourcePd = getPropDesc(key, null);
// 字段描述不存在或忽略读的情况下,表示不存在
return null != sourcePd && false == sourcePd.isIgnoreGet();
@@ -59,12 +54,13 @@ public class BeanValueProvider implements ValueProvider {
/**
* 获得属性描述
*
- * @param key 字段名
+ * @param key 字段名
+ * @param valueType 值类型,用于判断是否为Boolean,可以为null
* @return 属性描述
*/
- private PropDesc getPropDesc(String key){
+ private PropDesc getPropDesc(String key, Type valueType) {
PropDesc sourcePd = sourcePdMap.get(key);
- if(null == sourcePd) {
+ if (null == sourcePd && (null == valueType || Boolean.class == valueType || boolean.class == valueType)) {
//boolean类型字段字段名支持两种方式
sourcePd = sourcePdMap.get(StrUtil.upperFirstAndAddPre(key, "is"));
}
diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/copier/provider/DynaBeanValueProvider.java b/hutool-core/src/main/java/cn/hutool/core/bean/copier/provider/DynaBeanValueProvider.java
new file mode 100644
index 000000000..32a8c58ed
--- /dev/null
+++ b/hutool-core/src/main/java/cn/hutool/core/bean/copier/provider/DynaBeanValueProvider.java
@@ -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 {
+
+ 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);
+ }
+
+}