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

cn.hutool.core.bean.PropDesc Maven / Gradle / Ivy

There is a newer version: 5.8.33
Show newest version
package cn.hutool.core.bean;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.annotation.PropIgnore;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ModifierUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.TypeUtil;

import java.beans.Transient;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;

/**
 * 属性描述,包括了字段、getter、setter和相应的方法执行
 *
 * @author looly
 */
public class PropDesc {

	/**
	 * 字段
	 */
	final Field field;
	/**
	 * Getter方法
	 */
	protected Method getter;
	/**
	 * Setter方法
	 */
	protected 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); } /** * 获取字段名,如果存在Alias注解,读取注解的值作为名称 * * @return 字段名 */ public String getFieldName() { return ReflectUtil.getFieldName(this.field); } /** * 获取字段名称 * * @return 字段名 * @since 5.1.6 */ public String getRawFieldName() { 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; } /** * 检查属性是否可读(即是否可以通过{@link #getValue(Object)}获取到值) * * @param checkTransient 是否检查Transient关键字或注解 * @return 是否可读 * @since 5.4.2 */ public boolean isReadable(boolean checkTransient) { // 检查是否有getter方法或是否为public修饰 if (null == this.getter && false == ModifierUtil.isPublic(this.field)) { return false; } // 检查transient关键字和@Transient注解 if (checkTransient && isTransientForGet()) { return false; } // 检查@PropIgnore注解 return false == isIgnoreGet(); } /** * 获取属性值
* 首先调用字段对应的Getter方法获取值,如果Getter方法不存在,则判断字段如果为public,则直接获取字段值
* 此方法不检查任何注解,使用前需调用 {@link #isReadable(boolean)} 检查是否可读 * * @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; } /** * 获取属性值,自动转换属性值类型
* 首先调用字段对应的Getter方法获取值,如果Getter方法不存在,则判断字段如果为public,则直接获取字段值 * * @param bean Bean对象 * @param targetType 返回属性值需要转换的类型,null表示不转换 * @param ignoreError 是否忽略错误,包括转换错误和注入错误 * @return this * @since 5.4.2 */ public Object getValue(Object bean, Type targetType, boolean ignoreError) { Object result = null; try { result = getValue(bean); } catch (Exception e) { if (false == ignoreError) { throw new BeanException(e, "Get value of [{}] error!", getFieldName()); } } if (null != result && null != targetType) { // 尝试将结果转换为目标类型,如果转换失败,返回null,即跳过此属性值。 // 来自:issues#I41WKP@Gitee,当忽略错误情况下,目标类型转换失败应返回null // 如果返回原值,在集合注入时会成功,但是集合取值时会报类型转换错误 return Convert.convertWithCheck(targetType, result, null, ignoreError); } return result; } /** * 检查属性是否可读(即是否可以通过{@link #getValue(Object)}获取到值) * * @param checkTransient 是否检查Transient关键字或注解 * @return 是否可读 * @since 5.4.2 */ public boolean isWritable(boolean checkTransient) { // 检查是否有getter方法或是否为public修饰 if (null == this.setter && false == ModifierUtil.isPublic(this.field)) { return false; } // 检查transient关键字和@Transient注解 if (checkTransient && isTransientForSet()) { return false; } // 检查@PropIgnore注解 return false == isIgnoreSet(); } /** * 设置Bean的字段值
* 首先调用字段对应的Setter方法,如果Setter方法不存在,则判断字段如果为public,则直接赋值字段值
* 此方法不检查任何注解,使用前需调用 {@link #isWritable(boolean)} 检查是否可写 * * @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; } /** * 设置属性值,可以自动转换字段类型为目标类型 * * @param bean Bean对象 * @param value 属性值,可以为任意类型 * @param ignoreNull 是否忽略{@code null}值,true表示忽略 * @param ignoreError 是否忽略错误,包括转换错误和注入错误 * @return this * @since 5.4.2 */ public PropDesc setValue(Object bean, Object value, boolean ignoreNull, boolean ignoreError) { return setValue(bean, value, ignoreNull, ignoreError, true); } /** * 设置属性值,可以自动转换字段类型为目标类型 * * @param bean Bean对象 * @param value 属性值,可以为任意类型 * @param ignoreNull 是否忽略{@code null}值,true表示忽略 * @param ignoreError 是否忽略错误,包括转换错误和注入错误 * @param override 是否覆盖目标值,如果不覆盖,会先读取bean的值,{@code null}则写,否则忽略。如果覆盖,则不判断直接写 * @return this * @since 5.7.17 */ public PropDesc setValue(Object bean, Object value, boolean ignoreNull, boolean ignoreError, boolean override) { if (null == value && ignoreNull) { return this; } // issue#I4JQ1N@Gitee // 非覆盖模式下,如果目标值存在,则跳过 if (false == override && null != getValue(bean)) { return this; } // 当类型不匹配的时候,执行默认转换 if (null != value) { final Class propClass = getFieldClass(); if (false == propClass.isInstance(value)) { value = Convert.convertWithCheck(propClass, value, null, ignoreError); } } // 属性赋值 if (null != value || false == ignoreNull) { try { this.setValue(bean, value); } catch (Exception e) { if (false == ignoreError) { throw new BeanException(e, "Set value of [{}] error!", getFieldName()); } // 忽略注入失败 } } 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; } /** * 检查字段是否被忽略写,通过{@link PropIgnore} 注解完成,规则为: *
	 *     1. 在字段上有{@link PropIgnore} 注解
	 *     2. 在setXXX方法上有{@link PropIgnore} 注解
	 * 
* * @return 是否忽略写 * @since 5.4.2 */ private boolean isIgnoreSet() { return AnnotationUtil.hasAnnotation(this.field, PropIgnore.class) || AnnotationUtil.hasAnnotation(this.setter, PropIgnore.class); } /** * 检查字段是否被忽略读,通过{@link PropIgnore} 注解完成,规则为: *
	 *     1. 在字段上有{@link PropIgnore} 注解
	 *     2. 在getXXX方法上有{@link PropIgnore} 注解
	 * 
* * @return 是否忽略读 * @since 5.4.2 */ private boolean isIgnoreGet() { return AnnotationUtil.hasAnnotation(this.field, PropIgnore.class) || AnnotationUtil.hasAnnotation(this.getter, PropIgnore.class); } /** * 字段和Getter方法是否为Transient关键字修饰的 * * @return 是否为Transient关键字修饰的 * @since 5.3.11 */ private boolean isTransientForGet() { boolean isTransient = ModifierUtil.hasModifier(this.field, ModifierUtil.ModifierType.TRANSIENT); // 检查Getter方法 if (false == isTransient && null != this.getter) { isTransient = ModifierUtil.hasModifier(this.getter, ModifierUtil.ModifierType.TRANSIENT); // 检查注解 if (false == isTransient) { isTransient = AnnotationUtil.hasAnnotation(this.getter, Transient.class); } } return isTransient; } /** * 字段和Getter方法是否为Transient关键字修饰的 * * @return 是否为Transient关键字修饰的 * @since 5.3.11 */ private boolean isTransientForSet() { boolean isTransient = ModifierUtil.hasModifier(this.field, ModifierUtil.ModifierType.TRANSIENT); // 检查Getter方法 if (false == isTransient && null != this.setter) { isTransient = ModifierUtil.hasModifier(this.setter, ModifierUtil.ModifierType.TRANSIENT); // 检查注解 if (false == isTransient) { isTransient = AnnotationUtil.hasAnnotation(this.setter, Transient.class); } } return isTransient; } //------------------------------------------------------------------------------------ Private method end }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy