All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
cn.hutool.core.bean.PropDesc Maven / Gradle / Ivy
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
}