From 5aa10c06ee43496fd36d69eed9479ab05fe44d3b Mon Sep 17 00:00:00 2001 From: Looly Date: Wed, 9 Sep 2020 00:16:56 +0800 Subject: [PATCH] add DynabeanValueProvider --- .../java/cn/hutool/core/bean/DynaBean.java | 123 ++++++++++-------- .../hutool/core/bean/copier/BeanCopier.java | 5 + .../copier/provider/BeanValueProvider.java | 24 ++-- .../provider/DynaBeanValueProvider.java | 42 ++++++ 4 files changed, 125 insertions(+), 69 deletions(-) create mode 100644 hutool-core/src/main/java/cn/hutool/core/bean/copier/provider/DynaBeanValueProvider.java 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); + } + +}