com.dahuatech.hutool.core.bean.BeanDesc Maven / Gradle / Ivy
package com.dahuatech.hutool.core.bean;
import com.dahuatech.hutool.core.lang.Assert;
import com.dahuatech.hutool.core.map.CaseInsensitiveMap;
import com.dahuatech.hutool.core.util.*;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Bean信息描述做为BeanInfo替代方案,此对象持有JavaBean中的setters和getters等相关信息描述
* 查找Getter和Setter方法时会:
*
*
* 1. 忽略字段和方法名的大小写
* 2. Getter查找getXXX、isXXX、getIsXXX
* 3. Setter查找setXXX、setIsXXX
* 4. Setter忽略参数值与字段值不匹配的情况,因此有多个参数类型的重载时,会调用首次匹配的
*
*
* @author looly
* @since 3.1.2
*/
public class BeanDesc implements Serializable {
private static final long serialVersionUID = 1L;
/** Bean类 */
private Class> beanClass;
/** 属性Map */
private Map propMap = new LinkedHashMap<>();
/**
* 构造
*
* @param beanClass Bean类
*/
public BeanDesc(Class> beanClass) {
Assert.notNull(beanClass);
this.beanClass = beanClass;
init();
}
/**
* 获取Bean的全类名
*
* @return Bean的类名
*/
public String getName() {
return this.beanClass.getName();
}
/**
* 获取Bean的简单类名
*
* @return Bean的类名
*/
public String getSimpleName() {
return this.beanClass.getSimpleName();
}
/**
* 获取字段名-字段属性Map
*
* @param ignoreCase 是否忽略大小写,true为忽略,false不忽略
* @return 字段名-字段属性Map
*/
public Map getPropMap(boolean ignoreCase) {
return ignoreCase ? new CaseInsensitiveMap<>(1, this.propMap) : this.propMap;
}
/**
* 获取字段属性列表
*
* @return {@link PropDesc} 列表
*/
public Collection getProps() {
return this.propMap.values();
}
/**
* 获取属性,如果不存在返回null
*
* @param fieldName 字段名
* @return {@link PropDesc}
*/
public PropDesc getProp(String fieldName) {
return this.propMap.get(fieldName);
}
/**
* 获得字段名对应的字段对象,如果不存在返回null
*
* @param fieldName 字段名
* @return 字段值
*/
public Field getField(String fieldName) {
final PropDesc desc = this.propMap.get(fieldName);
return null == desc ? null : desc.getField();
}
/**
* 获取Getter方法,如果不存在返回null
*
* @param fieldName 字段名
* @return Getter方法
*/
public Method getGetter(String fieldName) {
final PropDesc desc = this.propMap.get(fieldName);
return null == desc ? null : desc.getGetter();
}
/**
* 获取Setter方法,如果不存在返回null
*
* @param fieldName 字段名
* @return Setter方法
*/
public Method getSetter(String fieldName) {
final PropDesc desc = this.propMap.get(fieldName);
return null == desc ? null : desc.getSetter();
}
// ------------------------------------------------------------------------------------------------------ Private method start
/**
* 初始化
* 只有与属性关联的相关Getter和Setter方法才会被读取,无关的getXXX和setXXX都被忽略
*
* @return this
*/
private BeanDesc init() {
for (Field field : ReflectUtil.getFields(this.beanClass)) {
if (false == ModifierUtil.isStatic(field)) {
// 只针对非static属性
this.propMap.put(field.getName(), createProp(field));
}
}
return this;
}
/**
* 根据字段创建属性描述
* 查找Getter和Setter方法时会:
*
*
* 1. 忽略字段和方法名的大小写
* 2. Getter查找getXXX、isXXX、getIsXXX
* 3. Setter查找setXXX、setIsXXX
* 4. Setter忽略参数值与字段值不匹配的情况,因此有多个参数类型的重载时,会调用首次匹配的
*
*
* @param field 字段
* @return {@link PropDesc}
* @since 4.0.2
*/
private PropDesc createProp(Field field) {
final String fieldName = field.getName();
final Class> fieldType = field.getType();
final boolean isBooeanField = BooleanUtil.isBoolean(fieldType);
Method getter = null;
Method setter = null;
String methodName;
Class>[] parameterTypes;
for (Method method : ReflectUtil.getMethods(this.beanClass)) {
parameterTypes = method.getParameterTypes();
if (parameterTypes.length > 1) {
// 多于1个参数说明非Getter或Setter
continue;
}
methodName = method.getName();
if (parameterTypes.length == 0) {
// 无参数,可能为Getter方法
if (isMatchGetter(methodName, fieldName, isBooeanField)) {
// 方法名与字段名匹配,则为Getter方法
getter = method;
}
} else if (isMatchSetter(methodName, fieldName, isBooeanField)) {
// 只有一个参数的情况下方法名与字段名对应匹配,则为Setter方法
setter = method;
}
if (null != getter && null != setter) {
// 如果Getter和Setter方法都找到了,不再继续寻找
break;
}
}
return new PropDesc(field, getter, setter);
}
/**
* 方法是否为Getter方法
* 匹配规则如下(忽略大小写):
*
*
* 字段名 -》 方法名
* isName -》 isName
* isName -》 isIsName
* isName -》 getIsName
* name -》 isName
* name -》 getName
*
*
* @param methodName 方法名
* @param fieldName 字段名
* @param isBooeanField 是否为Boolean类型字段
* @return 是否匹配
*/
private boolean isMatchGetter(String methodName, String fieldName, boolean isBooeanField) {
// 全部转为小写,忽略大小写比较
methodName = methodName.toLowerCase();
fieldName = fieldName.toLowerCase();
if (false == methodName.startsWith("get") && false == methodName.startsWith("is")) {
// 非标准Getter方法
return false;
}
if ("getclass".equals(methodName)) {
// 跳过getClass方法
return false;
}
// 针对Boolean类型特殊检查
if (isBooeanField) {
if (fieldName.startsWith("is")) {
// 字段已经是is开头
if (methodName.equals(fieldName) // isName -》 isName
|| methodName.equals("get" + fieldName) // isName -》 getIsName
|| methodName.equals("is" + fieldName) // isName -》 isIsName
) {
return true;
}
} else if (methodName.equals("is" + fieldName)) {
// 字段非is开头, name -》 isName
return true;
}
}
// 包括boolean的任何类型只有一种匹配情况:name -》 getName
return methodName.equals("get" + fieldName);
}
/**
* 方法是否为Setter方法
* 匹配规则如下(忽略大小写):
*
*
* 字段名 -》 方法名
* isName -》 setName
* isName -》 setIsName
* name -》 setName
*
*
* @param methodName 方法名
* @param fieldName 字段名
* @param isBooeanField 是否为Boolean类型字段
* @return 是否匹配
*/
private boolean isMatchSetter(String methodName, String fieldName, boolean isBooeanField) {
// 全部转为小写,忽略大小写比较
methodName = methodName.toLowerCase();
fieldName = fieldName.toLowerCase();
// 非标准Setter方法跳过
if (false == methodName.startsWith("set")) {
return false;
}
// 针对Boolean类型特殊检查
if (isBooeanField && fieldName.startsWith("is")) {
// 字段是is开头
if (methodName.equals("set" + StrUtil.removePrefix(fieldName, "is")) // isName -》 setName
|| methodName.equals("set" + fieldName) // isName -》 setIsName
) {
return true;
}
}
// 包括boolean的任何类型只有一种匹配情况:name -》 setName
return methodName.equals("set" + fieldName);
}
// ------------------------------------------------------------------------------------------------------ Private method end
/**
* 属性描述
*
* @author looly
*/
public static class PropDesc {
/** 字段 */
private Field field;
/** Getter方法 */
private Method getter;
/** Setter方法 */
private Method setter;
/**
* 构造
* Getter和Setter方法设置为默认可访问
*
* @param field 字段
* @param getter get方法
* @param setter set方法
*/
public PropDesc(Field field, Method getter, Method setter) {
this.field = field;
this.getter = ClassUtil.setAccessible(getter);
this.setter = ClassUtil.setAccessible(setter);
}
/**
* 获取字段名
*
* @return 字段名
*/
public String getFieldName() {
return null == this.field ? null : this.field.getName();
}
/**
* 获取字段
*
* @return 字段
*/
public Field getField() {
return this.field;
}
/**
* 获得字段类型
* 先获取字段的类型,如果字段不存在,则获取Getter方法的返回类型,否则获取Setter的第一个参数类型
*
* @return 字段类型
*/
public Type getFieldType() {
if (null != this.field) {
return TypeUtil.getType(this.field);
}
return findPropType(getter, setter);
}
/**
* 获得字段类型
* 先获取字段的类型,如果字段不存在,则获取Getter方法的返回类型,否则获取Setter的第一个参数类型
*
* @return 字段类型
*/
public Class> getFieldClass() {
if (null != this.field) {
return TypeUtil.getClass(this.field);
}
return findPropClass(getter, setter);
}
/**
* 获取Getter方法,可能为{@code null}
*
* @return Getter方法
*/
public Method getGetter() {
return this.getter;
}
/**
* 获取Setter方法,可能为{@code null}
*
* @return {@link Method}Setter 方法对象
*/
public Method getSetter() {
return this.setter;
}
/**
* 获取字段值
* 首先调用字段对应的Getter方法获取值,如果Getter方法不存在,则判断字段如果为public,则直接获取字段值
*
* @param bean Bean对象
* @return 字段值
* @since 4.0.5
*/
public Object getValue(Object bean) {
if (null != this.getter) {
return ReflectUtil.invoke(bean, this.getter);
} else if (ModifierUtil.isPublic(this.field)) {
return ReflectUtil.getFieldValue(bean, this.field);
}
return null;
}
/**
* 设置Bean的字段值
* 首先调用字段对应的Setter方法,如果Setter方法不存在,则判断字段如果为public,则直接赋值字段值
*
* @param bean Bean对象
* @param value 值
* @return this
* @since 4.0.5
*/
public PropDesc setValue(Object bean, Object value) {
if (null != this.setter) {
ReflectUtil.invoke(bean, this.setter, value);
} else if (ModifierUtil.isPublic(this.field)) {
ReflectUtil.setFieldValue(bean, this.field, value);
}
return this;
}
// ------------------------------------------------------------------------------------ Private
// method start
/**
* 通过Getter和Setter方法中找到属性类型
*
* @param getter Getter方法
* @param setter Setter方法
* @return {@link Type}
*/
private Type findPropType(Method getter, Method setter) {
Type type = null;
if (null != getter) {
type = TypeUtil.getReturnType(getter);
}
if (null == type && null != setter) {
type = TypeUtil.getParamType(setter, 0);
}
return type;
}
/**
* 通过Getter和Setter方法中找到属性类型
*
* @param getter Getter方法
* @param setter Setter方法
* @return {@link Type}
*/
private Class> findPropClass(Method getter, Method setter) {
Class> type = null;
if (null != getter) {
type = TypeUtil.getReturnClass(getter);
}
if (null == type && null != setter) {
type = TypeUtil.getFirstParamClass(setter);
}
return type;
}
// ------------------------------------------------------------------------------------ Private
// method end
}
}