All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.dahuatech.hutool.core.bean.BeanUtil Maven / Gradle / Ivy

There is a newer version: 1.0.13.10
Show newest version
package com.dahuatech.hutool.core.bean;

import com.dahuatech.hutool.core.bean.BeanDesc.PropDesc;
import com.dahuatech.hutool.core.bean.copier.BeanCopier;
import com.dahuatech.hutool.core.bean.copier.CopyOptions;
import com.dahuatech.hutool.core.bean.copier.ValueProvider;
import com.dahuatech.hutool.core.collection.CollUtil;
import com.dahuatech.hutool.core.convert.Convert;
import com.dahuatech.hutool.core.lang.Editor;
import com.dahuatech.hutool.core.lang.Filter;
import com.dahuatech.hutool.core.map.CaseInsensitiveMap;
import com.dahuatech.hutool.core.map.MapUtil;
import com.dahuatech.hutool.core.util.ArrayUtil;
import com.dahuatech.hutool.core.util.ClassUtil;
import com.dahuatech.hutool.core.util.ReflectUtil;
import com.dahuatech.hutool.core.util.StrUtil;

import java.beans.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

/**
 * Bean工具类
 *
 * 

把一个拥有对属性进行set和get方法的类,我们就可以称之为JavaBean。 * * @author Looly * @since 3.1.2 */ public class BeanUtil { /** * 判断是否为Bean对象
* 判定方法是是否存在只有一个参数的setXXX方法 * * @param clazz 待测试类 * @return 是否为Bean对象 * @see #hasSetter(Class) */ public static boolean isBean(Class clazz) { return hasSetter(clazz); } /** * 判断是否有Setter方法
* 判定方法是是否存在只有一个参数的setXXX方法 * * @param clazz 待测试类 * @return 是否为Bean对象 * @since 4.2.2 */ public static boolean hasSetter(Class clazz) { if (ClassUtil.isNormalClass(clazz)) { final Method[] methods = clazz.getMethods(); for (Method method : methods) { if (method.getParameterTypes().length == 1 && method.getName().startsWith("set")) { // 检测包含标准的setXXX方法即视为标准的JavaBean return true; } } } return false; } /** * 判断是否为Bean对象
* 判定方法是是否存在只有一个参数的setXXX方法 * * @param clazz 待测试类 * @return 是否为Bean对象 * @since 4.2.2 */ public static boolean hasGetter(Class clazz) { if (ClassUtil.isNormalClass(clazz)) { final Method[] methods = clazz.getMethods(); for (Method method : methods) { if (method.getParameterTypes().length == 0) { if (method.getName().startsWith("get") || method.getName().startsWith("is")) { return true; } } } } return false; } /** * 创建动态Bean * * @param bean 普通Bean或Map * @return {@link DynaBean} * @since 3.0.7 */ public static DynaBean createDynaBean(Object bean) { return new DynaBean(bean); } /** * 查找类型转换器 {@link PropertyEditor} * * @param type 需要转换的目标类型 * @return {@link PropertyEditor} */ public static PropertyEditor findEditor(Class type) { return PropertyEditorManager.findEditor(type); } /** * 判断Bean中是否有值为null的字段 * * @param bean Bean * @return 是否有值为null的字段 * @deprecated 请使用{@link #hasNullField(Object)} */ @Deprecated public static boolean hasNull(Object bean) { final Field[] fields = ClassUtil.getDeclaredFields(bean.getClass()); Object fieldValue = null; for (Field field : fields) { field.setAccessible(true); try { fieldValue = field.get(bean); } catch (Exception e) { // ignore } if (null == fieldValue) { return true; } } return false; } /** * 获取{@link BeanDesc} Bean描述信息 * * @param clazz Bean类 * @return {@link BeanDesc} * @since 3.1.2 */ public static BeanDesc getBeanDesc(Class clazz) { BeanDesc beanDesc = BeanDescCache.INSTANCE.getBeanDesc(clazz); if (null == beanDesc) { beanDesc = new BeanDesc(clazz); BeanDescCache.INSTANCE.putBeanDesc(clazz, beanDesc); } return beanDesc; } // --------------------------------------------------------------------------------------------------------- PropertyDescriptor /** * 获得Bean字段描述数组 * * @param clazz Bean类 * @return 字段描述数组 * @throws BeanException 获取属性异常 */ public static PropertyDescriptor[] getPropertyDescriptors(Class clazz) throws BeanException { BeanInfo beanInfo; try { beanInfo = Introspector.getBeanInfo(clazz); } catch (IntrospectionException e) { throw new BeanException(e); } return ArrayUtil.filter( beanInfo.getPropertyDescriptors(), new Filter() { @Override public boolean accept(PropertyDescriptor t) { // 过滤掉getClass方法 return false == "class".equals(t.getName()); } }); } /** * 获得字段名和字段描述Map,获得的结果会缓存在 {@link BeanInfoCache}中 * * @param clazz Bean类 * @param ignoreCase 是否忽略大小写 * @return 字段名和字段描述Map * @throws BeanException 获取属性异常 */ public static Map getPropertyDescriptorMap( Class clazz, boolean ignoreCase) throws BeanException { Map map = BeanInfoCache.INSTANCE.getPropertyDescriptorMap(clazz, ignoreCase); if (null == map) { map = internalGetPropertyDescriptorMap(clazz, ignoreCase); BeanInfoCache.INSTANCE.putPropertyDescriptorMap(clazz, map, ignoreCase); } return map; } /** * 获得字段名和字段描述Map。内部使用,直接获取Bean类的PropertyDescriptor * * @param clazz Bean类 * @param ignoreCase 是否忽略大小写 * @return 字段名和字段描述Map * @throws BeanException 获取属性异常 */ private static Map internalGetPropertyDescriptorMap( Class clazz, boolean ignoreCase) throws BeanException { final PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(clazz); final Map map = ignoreCase ? new CaseInsensitiveMap(propertyDescriptors.length, 1) : new HashMap((int) (propertyDescriptors.length), 1); for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { map.put(propertyDescriptor.getName(), propertyDescriptor); } return map; } /** * 获得Bean类属性描述,大小写敏感 * * @param clazz Bean类 * @param fieldName 字段名 * @return PropertyDescriptor * @throws BeanException 获取属性异常 */ public static PropertyDescriptor getPropertyDescriptor(Class clazz, final String fieldName) throws BeanException { return getPropertyDescriptor(clazz, fieldName, false); } /** * 获得Bean类属性描述 * * @param clazz Bean类 * @param fieldName 字段名 * @param ignoreCase 是否忽略大小写 * @return PropertyDescriptor * @throws BeanException 获取属性异常 */ public static PropertyDescriptor getPropertyDescriptor( Class clazz, final String fieldName, boolean ignoreCase) throws BeanException { final Map map = getPropertyDescriptorMap(clazz, ignoreCase); return (null == map) ? null : map.get(fieldName); } /** * 获得字段值,通过反射直接获得字段值,并不调用getXXX方法
* 对象同样支持Map类型,fieldNameOrIndex即为key * * @param bean Bean对象 * @param fieldNameOrIndex 字段名或序号,序号支持负数 * @return 字段值 */ public static Object getFieldValue(Object bean, String fieldNameOrIndex) { if (null == bean || null == fieldNameOrIndex) { return null; } if (bean instanceof Map) { return ((Map) bean).get(fieldNameOrIndex); } else if (bean instanceof Collection) { return CollUtil.get((Collection) bean, Integer.parseInt(fieldNameOrIndex)); } else if (ArrayUtil.isArray(bean)) { return ArrayUtil.get(bean, Integer.parseInt(fieldNameOrIndex)); } else { // 普通Bean对象 return ReflectUtil.getFieldValue(bean, fieldNameOrIndex); } } /** * 设置字段值,,通过反射设置字段值,并不调用setXXX方法
* 对象同样支持Map类型,fieldNameOrIndex即为key * * @param bean Bean * @param fieldNameOrIndex 字段名或序号,序号支持负数 * @param value 值 */ @SuppressWarnings({"unchecked", "rawtypes"}) public static void setFieldValue(Object bean, String fieldNameOrIndex, Object value) { if (bean instanceof Map) { ((Map) bean).put(fieldNameOrIndex, value); } else if (bean instanceof List) { CollUtil.setOrAppend((List) bean, Convert.toInt(fieldNameOrIndex), value); } else if (ArrayUtil.isArray(bean)) { ArrayUtil.setOrAppend(bean, Convert.toInt(fieldNameOrIndex), value); } else { // 普通Bean对象 ReflectUtil.setFieldValue(bean, fieldNameOrIndex, value); } } /** * 解析Bean中的属性值 * * @param bean Bean对象,支持Map、List、Collection、Array * @param expression 表达式,例如:person.friend[5].name * @return Bean属性值 * @see BeanPath#get(Object) * @since 3.0.7 */ public static Object getProperty(Object bean, String expression) { return BeanPath.create(expression).get(bean); } /** * 解析Bean中的属性值 * * @param bean Bean对象,支持Map、List、Collection、Array * @param expression 表达式,例如:person.friend[5].name * @param value 属性值 * @see BeanPath#get(Object) * @since 4.0.6 */ public static void setProperty(Object bean, String expression, Object value) { BeanPath.create(expression).set(bean, value); } // --------------------------------------------------------------------------------------------- // mapToBean /** * Map转换为Bean对象 * * @param Bean类型 * @param map {@link Map} * @param beanClass Bean Class * @param isIgnoreError 是否忽略注入错误 * @return Bean */ public static T mapToBean(Map map, Class beanClass, boolean isIgnoreError) { return fillBeanWithMap(map, ReflectUtil.newInstance(beanClass), isIgnoreError); } /** * Map转换为Bean对象
* 忽略大小写 * * @param Bean类型 * @param map Map * @param beanClass Bean Class * @param isIgnoreError 是否忽略注入错误 * @return Bean */ public static T mapToBeanIgnoreCase( Map map, Class beanClass, boolean isIgnoreError) { return fillBeanWithMapIgnoreCase(map, ReflectUtil.newInstance(beanClass), isIgnoreError); } /** * Map转换为Bean对象 * * @param Bean类型 * @param map {@link Map} * @param beanClass Bean Class * @param copyOptions 转Bean选项 * @return Bean */ public static T mapToBean(Map map, Class beanClass, CopyOptions copyOptions) { return fillBeanWithMap(map, ReflectUtil.newInstance(beanClass), copyOptions); } // --------------------------------------------------------------------------------------------- // fillBeanWithMap /** * 使用Map填充Bean对象 * * @param Bean类型 * @param map Map * @param bean Bean * @param isIgnoreError 是否忽略注入错误 * @return Bean */ public static T fillBeanWithMap(Map map, T bean, boolean isIgnoreError) { return fillBeanWithMap(map, bean, false, isIgnoreError); } /** * 使用Map填充Bean对象,可配置将下划线转换为驼峰 * * @param Bean类型 * @param map Map * @param bean Bean * @param isToCamelCase 是否将下划线模式转换为驼峰模式 * @param isIgnoreError 是否忽略注入错误 * @return Bean */ public static T fillBeanWithMap( Map map, T bean, boolean isToCamelCase, boolean isIgnoreError) { return fillBeanWithMap( map, bean, isToCamelCase, CopyOptions.create().setIgnoreError(isIgnoreError)); } /** * 使用Map填充Bean对象,忽略大小写 * * @param Bean类型 * @param map Map * @param bean Bean * @param isIgnoreError 是否忽略注入错误 * @return Bean */ public static T fillBeanWithMapIgnoreCase(Map map, T bean, boolean isIgnoreError) { return fillBeanWithMap( map, bean, CopyOptions.create().setIgnoreCase(true).setIgnoreError(isIgnoreError)); } /** * 使用Map填充Bean对象 * * @param Bean类型 * @param map Map * @param bean Bean * @param copyOptions 属性复制选项 {@link CopyOptions} * @return Bean */ public static T fillBeanWithMap(Map map, T bean, CopyOptions copyOptions) { return fillBeanWithMap(map, bean, false, copyOptions); } /** * 使用Map填充Bean对象 * * @param Bean类型 * @param map Map * @param bean Bean * @param isToCamelCase 是否将Map中的下划线风格key转换为驼峰风格 * @param copyOptions 属性复制选项 {@link CopyOptions} * @return Bean * @since 3.3.1 */ public static T fillBeanWithMap( Map map, T bean, boolean isToCamelCase, CopyOptions copyOptions) { if (MapUtil.isEmpty(map)) { return bean; } if (isToCamelCase) { map = MapUtil.toCamelCaseMap(map); } return BeanCopier.create(map, bean, copyOptions).copy(); } // --------------------------------------------------------------------------------------------- // fillBean /** * 对象或Map转Bean * * @param 转换的Bean类型 * @param source Bean对象或Map * @param clazz 目标的Bean类型 * @return Bean对象 * @since 4.1.20 */ public static T toBean(Object source, Class clazz) { final T target = ReflectUtil.newInstance(clazz); copyProperties(source, target); return target; } /** * ServletRequest 参数转Bean * * @param Bean类型 * @param beanClass Bean Class * @param valueProvider 值提供者 * @param copyOptions 拷贝选项,见 {@link CopyOptions} * @return Bean */ public static T toBean( Class beanClass, ValueProvider valueProvider, CopyOptions copyOptions) { return fillBean(ReflectUtil.newInstance(beanClass), valueProvider, copyOptions); } /** * 填充Bean的核心方法 * * @param Bean类型 * @param bean Bean * @param valueProvider 值提供者 * @param copyOptions 拷贝选项,见 {@link CopyOptions} * @return Bean */ public static T fillBean( T bean, ValueProvider valueProvider, CopyOptions copyOptions) { if (null == valueProvider) { return bean; } return BeanCopier.create(valueProvider, bean, copyOptions).copy(); } // --------------------------------------------------------------------------------------------- // beanToMap /** * 对象转Map,不进行驼峰转下划线,不忽略值为空的字段 * * @param bean bean对象 * @return Map */ public static Map beanToMap(Object bean) { return beanToMap(bean, false, false); } /** * 对象转Map * * @param bean bean对象 * @param isToUnderlineCase 是否转换为下划线模式 * @param ignoreNullValue 是否忽略值为空的字段 * @return Map */ public static Map beanToMap( Object bean, boolean isToUnderlineCase, boolean ignoreNullValue) { return beanToMap(bean, new LinkedHashMap(), isToUnderlineCase, ignoreNullValue); } /** * 对象转Map * * @param bean bean对象 * @param targetMap 目标的Map * @param isToUnderlineCase 是否转换为下划线模式 * @param ignoreNullValue 是否忽略值为空的字段 * @return Map * @since 3.2.3 */ public static Map beanToMap( Object bean, Map targetMap, final boolean isToUnderlineCase, boolean ignoreNullValue) { if (bean == null) { return null; } return beanToMap( bean, targetMap, ignoreNullValue, new Editor() { @Override public String edit(String key) { return isToUnderlineCase ? StrUtil.toUnderlineCase(key) : key; } }); } /** * 对象转Map
* 通过实现{@link Editor} 可以自定义字段值,如果这个Editor返回null则忽略这个字段,以便实现: * *

   * 1. 字段筛选,可以去除不需要的字段
   * 2. 字段变换,例如实现驼峰转下划线
   * 3. 自定义字段前缀或后缀等等
   * 
* * @param bean bean对象 * @param targetMap 目标的Map * @param ignoreNullValue 是否忽略值为空的字段 * @param keyEditor 属性字段(Map的key)编辑器,用于筛选、编辑key * @return Map * @since 4.0.5 */ public static Map beanToMap( Object bean, Map targetMap, boolean ignoreNullValue, Editor keyEditor) { if (bean == null) { return null; } final Collection props = BeanUtil.getBeanDesc(bean.getClass()).getProps(); String key; Method getter; Object value; for (PropDesc prop : props) { key = prop.getFieldName(); // 过滤class属性 // 得到property对应的getter方法 getter = prop.getGetter(); if (null != getter) { // 只读取有getter方法的属性 try { value = getter.invoke(bean); } catch (Exception ignore) { continue; } if (false == ignoreNullValue || (null != value && false == value.equals(bean))) { key = keyEditor.edit(key); if (null != key) { targetMap.put(key, value); } } } } return targetMap; } // --------------------------------------------------------------------------------------------- // copyProperties /** * 复制Bean对象属性 * * @param source 源Bean对象 * @param target 目标Bean对象 */ public static void copyProperties(Object source, Object target) { copyProperties(source, target, CopyOptions.create()); } /** * 复制Bean对象属性
* 限制类用于限制拷贝的属性,例如一个类我只想复制其父类的一些属性,就可以将editable设置为父类 * * @param source 源Bean对象 * @param target 目标Bean对象 * @param ignoreProperties 不拷贝的的属性列表 */ public static void copyProperties(Object source, Object target, String... ignoreProperties) { copyProperties(source, target, CopyOptions.create().setIgnoreProperties(ignoreProperties)); } /** * 复制Bean对象属性
* * @param source 源Bean对象 * @param target 目标Bean对象 * @param ignoreCase 是否忽略大小写 */ public static void copyProperties(Object source, Object target, boolean ignoreCase) { BeanCopier.create(source, target, CopyOptions.create().setIgnoreCase(ignoreCase)).copy(); } /** * 复制Bean对象属性
* 限制类用于限制拷贝的属性,例如一个类我只想复制其父类的一些属性,就可以将editable设置为父类 * * @param source 源Bean对象 * @param target 目标Bean对象 * @param copyOptions 拷贝选项,见 {@link CopyOptions} */ public static void copyProperties(Object source, Object target, CopyOptions copyOptions) { if (null == copyOptions) { copyOptions = new CopyOptions(); } BeanCopier.create(source, target, copyOptions).copy(); } /** * 给定的Bean的类名是否匹配指定类名字符串
* 如果isSimple为{@code false},则只匹配类名而忽略包名,例如:com.dahuatech.hutool.TestEntity只匹配TestEntity
* 如果isSimple为{@code * true},则匹配包括包名的全类名,例如:com.dahuatech.hutool.TestEntity匹配com.dahuatech.hutool.TestEntity * * @param bean Bean * @param beanClassName Bean的类名 * @param isSimple 是否只匹配类名而忽略包名,true表示忽略包名 * @return 是否匹配 * @since 4.0.6 */ public static boolean isMatchName(Object bean, String beanClassName, boolean isSimple) { return ClassUtil.getClassName(bean, isSimple) .equals(isSimple ? StrUtil.upperFirst(beanClassName) : beanClassName); } /** * 把Bean里面的String属性做trim操作。此方法直接对传入的Bean做修改。 * *

通常bean直接用来绑定页面的input,用户的输入可能首尾存在空格,通常保存数据库前需要把首尾空格去掉 * * @param Bean类型 * @param bean Bean对象 * @param ignoreFields 不需要trim的Field名称列表(不区分大小写) * @return 处理后的Bean对象 */ public static T trimStrFields(T bean, String... ignoreFields) { if (bean == null) { return bean; } final Field[] fields = ReflectUtil.getFields(bean.getClass()); for (Field field : fields) { if (ignoreFields != null && ArrayUtil.containsIgnoreCase(ignoreFields, field.getName())) { // 不处理忽略的Fields continue; } if (String.class.equals(field.getType())) { // 只有String的Field才处理 final String val = (String) ReflectUtil.getFieldValue(bean, field); if (null != val) { final String trimVal = StrUtil.trim(val); if (false == val.equals(trimVal)) { // Field Value不为null,且首尾有空格才处理 ReflectUtil.setFieldValue(bean, field, trimVal); } } } } return bean; } /** * 判断Bean是否为空对象,空对象表示本身为null或者所有属性都为null * * @param bean Bean对象 * @return 是否为空,true - 空 / false - 非空 * @since 4.1.10 */ public static boolean isEmpty(Object bean) { if (null != bean) { for (Field field : ReflectUtil.getFields(bean.getClass())) { if (null != ReflectUtil.getFieldValue(bean, field)) { return false; } } } return true; } /** * 判断Bean是否包含值为null的属性
* 对象本身为null也返回true * * @param bean Bean对象 * @return 是否包含值为null的属性,true - 包含 / false - 不包含 * @since 4.1.10 */ public static boolean hasNullField(Object bean) { if (null == bean) { return true; } for (Field field : ReflectUtil.getFields(bean.getClass())) { if (null == ReflectUtil.getFieldValue(bean, field)) { return true; } } return false; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy