mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-29 19:56:44 +08:00
fix code
This commit is contained in:
parent
7999baec85
commit
3a73cdea51
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2023 looly(loolly@aliyun.com)
|
||||
* Copyright (c) 2024. looly(loolly@aliyun.com)
|
||||
* Hutool is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
@ -12,95 +12,31 @@
|
||||
|
||||
package org.dromara.hutool.core.bean;
|
||||
|
||||
import org.dromara.hutool.core.array.ArrayUtil;
|
||||
import org.dromara.hutool.core.lang.Assert;
|
||||
import org.dromara.hutool.core.map.CaseInsensitiveMap;
|
||||
import org.dromara.hutool.core.reflect.FieldUtil;
|
||||
import org.dromara.hutool.core.reflect.ModifierUtil;
|
||||
import org.dromara.hutool.core.reflect.method.MethodUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.util.BooleanUtil;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Bean信息描述做为BeanInfo替代方案,此对象持有JavaBean中的setters和getters等相关信息描述<br>
|
||||
* 查找Getter和Setter方法时会:
|
||||
* Bean描述,通过反射等方式获取Bean的setter、getter、字段等信息
|
||||
*
|
||||
* <pre>
|
||||
* 1. 忽略字段和方法名的大小写
|
||||
* 2. Getter查找getXXX、isXXX、getIsXXX
|
||||
* 3. Setter查找setXXX、setIsXXX
|
||||
* 4. Setter忽略参数值与字段值不匹配的情况,因此有多个参数类型的重载时,会调用首次匹配的
|
||||
* </pre>
|
||||
*
|
||||
* @author looly
|
||||
* @since 3.1.2
|
||||
* @author Looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class BeanDesc implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Bean类
|
||||
*/
|
||||
private final Class<?> beanClass;
|
||||
/**
|
||||
* 属性Map
|
||||
*/
|
||||
private final Map<String, PropDesc> propMap = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param beanClass Bean类
|
||||
*/
|
||||
public BeanDesc(final 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();
|
||||
}
|
||||
|
||||
public interface BeanDesc extends Serializable {
|
||||
/**
|
||||
* 获取字段名-字段属性Map
|
||||
*
|
||||
* @param ignoreCase 是否忽略大小写,true为忽略,false不忽略
|
||||
* @return 字段名-字段属性Map
|
||||
*/
|
||||
public Map<String, PropDesc> getPropMap(final boolean ignoreCase) {
|
||||
return ignoreCase ? new CaseInsensitiveMap<>(1, this.propMap) : this.propMap;
|
||||
}
|
||||
Map<String, PropDesc> getPropMap(final boolean ignoreCase);
|
||||
|
||||
/**
|
||||
* 获取字段属性列表
|
||||
*
|
||||
* @return {@link PropDesc} 列表
|
||||
*/
|
||||
public Collection<PropDesc> getProps() {
|
||||
return this.propMap.values();
|
||||
}
|
||||
Collection<PropDesc> getProps();
|
||||
|
||||
/**
|
||||
* 获取属性,如果不存在返回null
|
||||
@ -108,272 +44,5 @@ public class BeanDesc implements Serializable {
|
||||
* @param fieldName 字段名
|
||||
* @return {@link PropDesc}
|
||||
*/
|
||||
public PropDesc getProp(final String fieldName) {
|
||||
return this.propMap.get(fieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得字段名对应的字段对象,如果不存在返回null
|
||||
*
|
||||
* @param fieldName 字段名
|
||||
* @return 字段值
|
||||
*/
|
||||
public Field getField(final String fieldName) {
|
||||
final PropDesc desc = this.propMap.get(fieldName);
|
||||
return null == desc ? null : desc.getField();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Getter方法,如果不存在返回null
|
||||
*
|
||||
* @param fieldName 字段名
|
||||
* @return Getter方法
|
||||
*/
|
||||
public Method getGetter(final String fieldName) {
|
||||
final PropDesc desc = this.propMap.get(fieldName);
|
||||
return null == desc ? null : desc.getGetter();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Setter方法,如果不存在返回null
|
||||
*
|
||||
* @param fieldName 字段名
|
||||
* @return Setter方法
|
||||
*/
|
||||
public Method getSetter(final String fieldName) {
|
||||
final PropDesc desc = this.propMap.get(fieldName);
|
||||
return null == desc ? null : desc.getSetter();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------ Private method start
|
||||
|
||||
/**
|
||||
* 初始化<br>
|
||||
* 只有与属性关联的相关Getter和Setter方法才会被读取,无关的getXXX和setXXX都被忽略
|
||||
*/
|
||||
private void init() {
|
||||
if (RecordUtil.isRecord(this.beanClass)) {
|
||||
initForRecord();
|
||||
} else{
|
||||
initForBean();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 针对Record类的反射初始化
|
||||
*/
|
||||
private void initForRecord() {
|
||||
final Method[] getters = MethodUtil.getPublicMethods(this.beanClass, method -> 0 == method.getParameterCount());
|
||||
// 排除静态属性和对象子类
|
||||
final Field[] fields = FieldUtil.getFields(this.beanClass, field -> !ModifierUtil.isStatic(field) && !FieldUtil.isOuterClassField(field));
|
||||
for (final Field field : fields) {
|
||||
for (final Method getter : getters) {
|
||||
if (field.getName().equals(getter.getName())) {
|
||||
//record对象,getter方法与字段同名
|
||||
final PropDesc prop = new PropDesc(field, getter, null);
|
||||
this.propMap.putIfAbsent(prop.getFieldName(), prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通Bean初始化
|
||||
*/
|
||||
private void initForBean() {
|
||||
final Method[] gettersAndSetters = MethodUtil.getPublicMethods(this.beanClass, MethodUtil::isGetterOrSetterIgnoreCase);
|
||||
// 排除静态属性和对象子类
|
||||
final Field[] fields = FieldUtil.getFields(this.beanClass, field -> !ModifierUtil.isStatic(field) && !FieldUtil.isOuterClassField(field));
|
||||
PropDesc prop;
|
||||
for (final Field field : fields) {
|
||||
prop = createProp(field, gettersAndSetters);
|
||||
// 只有不存在时才放入,防止父类属性覆盖子类属性
|
||||
this.propMap.putIfAbsent(prop.getFieldName(), prop);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据字段创建属性描述<br>
|
||||
* 查找Getter和Setter方法时会:
|
||||
*
|
||||
* <pre>
|
||||
* 1. 忽略字段和方法名的大小写
|
||||
* 2. Getter查找getXXX、isXXX、getIsXXX
|
||||
* 3. Setter查找setXXX、setIsXXX
|
||||
* 4. Setter忽略参数值与字段值不匹配的情况,因此有多个参数类型的重载时,会调用首次匹配的
|
||||
* </pre>
|
||||
*
|
||||
* @param field 字段
|
||||
* @param methods 类中所有的方法
|
||||
* @return {@link PropDesc}
|
||||
* @since 4.0.2
|
||||
*/
|
||||
private PropDesc createProp(final Field field, final Method[] methods) {
|
||||
final PropDesc prop = findProp(field, methods, false);
|
||||
// 忽略大小写重新匹配一次
|
||||
if (null == prop.getter || null == prop.setter) {
|
||||
final PropDesc propIgnoreCase = findProp(field, methods, true);
|
||||
if (null == prop.getter) {
|
||||
prop.getter = propIgnoreCase.getter;
|
||||
}
|
||||
if (null == prop.setter) {
|
||||
prop.setter = propIgnoreCase.setter;
|
||||
}
|
||||
}
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找字段对应的Getter和Setter方法
|
||||
*
|
||||
* @param field 字段
|
||||
* @param gettersOrSetters 类中所有的Getter或Setter方法
|
||||
* @param ignoreCase 是否忽略大小写匹配
|
||||
* @return PropDesc
|
||||
*/
|
||||
private PropDesc findProp(final Field field, final Method[] gettersOrSetters, final boolean ignoreCase) {
|
||||
final String fieldName = field.getName();
|
||||
final Class<?> fieldType = field.getType();
|
||||
final boolean isBooleanField = BooleanUtil.isBoolean(fieldType);
|
||||
|
||||
// Getter: name -> getName, Setter: name -> setName
|
||||
final Method[] getterAndSetter = findGetterAndSetter(fieldName, fieldType, gettersOrSetters, ignoreCase);
|
||||
|
||||
if (isBooleanField) {
|
||||
if (null == getterAndSetter[0]) {
|
||||
// isName -> isName or isIsName
|
||||
// name -> isName
|
||||
getterAndSetter[0] = findGetterForBoolean(fieldName, gettersOrSetters, ignoreCase);
|
||||
}
|
||||
if (null == getterAndSetter[1]) {
|
||||
// isName -> setName
|
||||
getterAndSetter[1] = findSetterForBoolean(fieldName, gettersOrSetters, ignoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
return new PropDesc(field, getterAndSetter[0], getterAndSetter[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找字段对应的Getter和Setter方法<br>
|
||||
* 此方法不区分是否为boolean字段,查找规则为:
|
||||
* <ul>
|
||||
* <li>Getter要求无参数且返回值是字段类型或字段的父类</li>
|
||||
* <li>Getter中,如果字段为name,匹配getName</li>
|
||||
* <li>Setter要求一个参数且参数必须为字段类型或字段的子类</li>
|
||||
* <li>Setter中,如果字段为name,匹配setName</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param fieldName 字段名
|
||||
* @param fieldType 字段类型
|
||||
* @param gettersOrSetters 类中所有的Getter或Setter方法
|
||||
* @return PropDesc
|
||||
*/
|
||||
private Method[] findGetterAndSetter(final String fieldName, final Class<?> fieldType,
|
||||
final Method[] gettersOrSetters, final boolean ignoreCase) {
|
||||
Method getter = null;
|
||||
Method setter = null;
|
||||
String methodName;
|
||||
for (final Method method : gettersOrSetters) {
|
||||
methodName = method.getName();
|
||||
if (0 == method.getParameterCount()) {
|
||||
// 无参数,可能为Getter方法
|
||||
if (StrUtil.equals(methodName, StrUtil.genGetter(fieldName), ignoreCase) &&
|
||||
method.getReturnType().isAssignableFrom(fieldType)) {
|
||||
// getter的返回类型必须为字段类型或字段的父类
|
||||
getter = method;
|
||||
}
|
||||
} else if (StrUtil.equals(methodName, StrUtil.genSetter(fieldName), ignoreCase) &&
|
||||
fieldType.isAssignableFrom(method.getParameterTypes()[0])) {
|
||||
// setter方法的参数必须为字段类型或字段的子类
|
||||
setter = method;
|
||||
}
|
||||
if (null != getter && null != setter) {
|
||||
// 如果Getter和Setter方法都找到了,不再继续寻找
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new Method[]{getter, setter};
|
||||
}
|
||||
|
||||
/**
|
||||
* 针对Boolean或boolean类型字段,查找其对应的Getter方法,规则为:
|
||||
* <ul>
|
||||
* <li>方法必须无参数且返回boolean或Boolean</li>
|
||||
* <li>如果字段为isName, 匹配isName、isIsName方法,两个方法均存在,则按照提供的方法数组优先匹配。</li>
|
||||
* <li>如果字段为name, 匹配isName方法</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* 需要注意的是,以下两种格式不匹配,由{@link #findGetterAndSetter(String, Class, Method[], boolean)}完成:
|
||||
* <ul>
|
||||
* <li>如果字段为name, 匹配getName</li>
|
||||
* <li>如果字段为isName, 匹配getIsName</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param fieldName 字段名
|
||||
* @param gettersOrSetters 所有方法
|
||||
* @param ignoreCase 是否忽略大小写
|
||||
* @return 查找到的方法,{@code null}表示未找到
|
||||
*/
|
||||
private Method findGetterForBoolean(final String fieldName, final Method[] gettersOrSetters, final boolean ignoreCase) {
|
||||
// 查找isXXX
|
||||
return ArrayUtil.get(gettersOrSetters, m -> {
|
||||
if (0 != m.getParameterCount() || false == BooleanUtil.isBoolean(m.getReturnType())) {
|
||||
// getter方法要求无参数且返回boolean或Boolean
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StrUtil.startWith(fieldName, "is", ignoreCase)) {
|
||||
// isName -》 isName
|
||||
if (StrUtil.equals(fieldName, m.getName(), ignoreCase)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// name -》 isName
|
||||
// isName -》 isIsName
|
||||
return StrUtil.equals(StrUtil.upperFirstAndAddPre(fieldName, "is"), m.getName(), ignoreCase);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 针对Boolean或boolean类型字段,查找其对应的Setter方法,规则为:
|
||||
* <ul>
|
||||
* <li>方法必须为1个boolean或Boolean参数</li>
|
||||
* <li>如果字段为isName,匹配setName</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* 需要注意的是,以下两种格式不匹配,由{@link #findGetterAndSetter(String, Class, Method[], boolean)}完成:
|
||||
* <ul>
|
||||
* <li>如果字段为name, 匹配setName</li>
|
||||
* <li>如果字段为isName, 匹配setIsName</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param fieldName 字段名
|
||||
* @param gettersOrSetters 所有方法
|
||||
* @param ignoreCase 是否忽略大小写
|
||||
* @return 查找到的方法,{@code null}表示未找到
|
||||
*/
|
||||
private Method findSetterForBoolean(final String fieldName, final Method[] gettersOrSetters, final boolean ignoreCase) {
|
||||
// 查找isXXX
|
||||
return ArrayUtil.get(gettersOrSetters, m -> {
|
||||
if (1 != m.getParameterCount() || false == BooleanUtil.isBoolean(m.getParameterTypes()[0])) {
|
||||
// setter方法要求1个boolean或Boolean参数
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StrUtil.startWith(fieldName, "is", ignoreCase)) {
|
||||
// isName -》 setName
|
||||
return StrUtil.equals(
|
||||
"set" + StrUtil.removePrefix(fieldName, "is", ignoreCase),
|
||||
m.getName(), ignoreCase);
|
||||
}
|
||||
|
||||
// 其它不匹配
|
||||
return false;
|
||||
});
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------------ Private method end
|
||||
PropDesc getProp(final String fieldName);
|
||||
}
|
||||
|
@ -27,17 +27,17 @@ public enum BeanDescCache {
|
||||
*/
|
||||
INSTANCE;
|
||||
|
||||
private final WeakConcurrentMap<Class<?>, BeanDesc> bdCache = new WeakConcurrentMap<>();
|
||||
private final WeakConcurrentMap<Class<?>, StrictBeanDesc> bdCache = new WeakConcurrentMap<>();
|
||||
|
||||
/**
|
||||
* 获得属性名和{@link BeanDesc}Map映射
|
||||
* 获得属性名和{@link StrictBeanDesc}Map映射
|
||||
*
|
||||
* @param beanClass Bean的类
|
||||
* @param supplier 对象不存在时创建对象的函数
|
||||
* @return 属性名和 {@link BeanDesc}映射
|
||||
* @return 属性名和 {@link StrictBeanDesc}映射
|
||||
* @since 5.4.2
|
||||
*/
|
||||
public BeanDesc getBeanDesc(final Class<?> beanClass, final SerSupplier<BeanDesc> supplier) {
|
||||
public StrictBeanDesc getBeanDesc(final Class<?> beanClass, final SerSupplier<StrictBeanDesc> supplier) {
|
||||
return bdCache.computeIfAbsent(beanClass, (key) -> supplier.get());
|
||||
}
|
||||
|
||||
|
@ -76,14 +76,14 @@ public class BeanUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取{@link BeanDesc} Bean描述信息
|
||||
* 获取{@link StrictBeanDesc} Bean描述信息
|
||||
*
|
||||
* @param clazz Bean类
|
||||
* @return {@link BeanDesc}
|
||||
* @return {@link StrictBeanDesc}
|
||||
* @since 3.1.2
|
||||
*/
|
||||
public static BeanDesc getBeanDesc(final Class<?> clazz) {
|
||||
return BeanDescCache.INSTANCE.getBeanDesc(clazz, () -> new BeanDesc(clazz));
|
||||
public static StrictBeanDesc getBeanDesc(final Class<?> clazz) {
|
||||
return BeanDescCache.INSTANCE.getBeanDesc(clazz, () -> new StrictBeanDesc(clazz));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -16,10 +16,7 @@ import org.dromara.hutool.core.annotation.AnnotationUtil;
|
||||
import org.dromara.hutool.core.annotation.PropIgnore;
|
||||
import org.dromara.hutool.core.convert.Convert;
|
||||
import org.dromara.hutool.core.func.LambdaUtil;
|
||||
import org.dromara.hutool.core.reflect.FieldUtil;
|
||||
import org.dromara.hutool.core.reflect.ModifierUtil;
|
||||
import org.dromara.hutool.core.reflect.ReflectUtil;
|
||||
import org.dromara.hutool.core.reflect.TypeUtil;
|
||||
import org.dromara.hutool.core.reflect.*;
|
||||
import org.dromara.hutool.core.reflect.method.MethodUtil;
|
||||
|
||||
import java.beans.Transient;
|
||||
@ -392,11 +389,11 @@ public class PropDesc {
|
||||
* @since 5.3.11
|
||||
*/
|
||||
private boolean isTransientForGet() {
|
||||
boolean isTransient = ModifierUtil.hasModifier(this.field, ModifierUtil.ModifierType.TRANSIENT);
|
||||
boolean isTransient = ModifierUtil.hasModifier(this.field, ModifierType.TRANSIENT);
|
||||
|
||||
// 检查Getter方法
|
||||
if (!isTransient && null != this.getter) {
|
||||
isTransient = ModifierUtil.hasModifier(this.getter, ModifierUtil.ModifierType.TRANSIENT);
|
||||
isTransient = ModifierUtil.hasModifier(this.getter, ModifierType.TRANSIENT);
|
||||
|
||||
// 检查注解
|
||||
if (!isTransient) {
|
||||
@ -414,11 +411,11 @@ public class PropDesc {
|
||||
* @since 5.3.11
|
||||
*/
|
||||
private boolean isTransientForSet() {
|
||||
boolean isTransient = ModifierUtil.hasModifier(this.field, ModifierUtil.ModifierType.TRANSIENT);
|
||||
boolean isTransient = ModifierUtil.hasModifier(this.field, ModifierType.TRANSIENT);
|
||||
|
||||
// 检查Getter方法
|
||||
if (!isTransient && null != this.setter) {
|
||||
isTransient = ModifierUtil.hasModifier(this.setter, ModifierUtil.ModifierType.TRANSIENT);
|
||||
isTransient = ModifierUtil.hasModifier(this.setter, ModifierType.TRANSIENT);
|
||||
|
||||
// 检查注解
|
||||
if (!isTransient) {
|
||||
|
@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (c) 2023 looly(loolly@aliyun.com)
|
||||
* Hutool is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* https://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.core.bean;
|
||||
|
||||
import org.dromara.hutool.core.bean.path.AbstractBeanDesc;
|
||||
import org.dromara.hutool.core.reflect.FieldUtil;
|
||||
import org.dromara.hutool.core.reflect.ModifierUtil;
|
||||
import org.dromara.hutool.core.reflect.method.MethodUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.util.BooleanUtil;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 严格的Bean信息描述做为BeanInfo替代方案,此对象持有JavaBean中的setters和getters等相关信息描述<br>
|
||||
* 查找Getter和Setter方法时会:
|
||||
*
|
||||
* <pre>
|
||||
* 1. 忽略字段和方法名的大小写
|
||||
* 2. Getter查找getXXX、isXXX、getIsXXX
|
||||
* 3. Setter查找setXXX、setIsXXX
|
||||
* 4. Setter忽略参数值与字段值不匹配的情况,因此有多个参数类型的重载时,会调用首次匹配的
|
||||
* </pre>
|
||||
*
|
||||
* @author looly
|
||||
* @since 3.1.2
|
||||
*/
|
||||
public class StrictBeanDesc extends AbstractBeanDesc {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param beanClass Bean类
|
||||
*/
|
||||
public StrictBeanDesc(final Class<?> beanClass) {
|
||||
super(beanClass);
|
||||
init();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------ Private method start
|
||||
|
||||
/**
|
||||
* 初始化<br>
|
||||
* 只有与属性关联的相关Getter和Setter方法才会被读取,无关的getXXX和setXXX都被忽略
|
||||
*/
|
||||
private void init() {
|
||||
if (RecordUtil.isRecord(getBeanClass())) {
|
||||
initForRecord();
|
||||
} else{
|
||||
initForBean();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 针对Record类的反射初始化
|
||||
*/
|
||||
private void initForRecord() {
|
||||
final Class<?> beanClass = this.beanClass;
|
||||
final Map<String, PropDesc> propMap = this.propMap;
|
||||
|
||||
final Method[] getters = MethodUtil.getPublicMethods(beanClass, method -> 0 == method.getParameterCount());
|
||||
// 排除静态属性和对象子类
|
||||
final Field[] fields = FieldUtil.getFields(beanClass, field -> !ModifierUtil.isStatic(field) && !FieldUtil.isOuterClassField(field));
|
||||
for (final Field field : fields) {
|
||||
for (final Method getter : getters) {
|
||||
if (field.getName().equals(getter.getName())) {
|
||||
//record对象,getter方法与字段同名
|
||||
final PropDesc prop = new PropDesc(field, getter, null);
|
||||
propMap.putIfAbsent(prop.getFieldName(), prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通Bean初始化
|
||||
*/
|
||||
private void initForBean() {
|
||||
final Class<?> beanClass = this.beanClass;
|
||||
final Map<String, PropDesc> propMap = this.propMap;
|
||||
|
||||
final Method[] gettersAndSetters = MethodUtil.getPublicMethods(beanClass, MethodUtil::isGetterOrSetterIgnoreCase);
|
||||
// 排除静态属性和对象子类
|
||||
final Field[] fields = FieldUtil.getFields(beanClass, field -> !ModifierUtil.isStatic(field) && !FieldUtil.isOuterClassField(field));
|
||||
PropDesc prop;
|
||||
for (final Field field : fields) {
|
||||
prop = createProp(field, gettersAndSetters);
|
||||
// 只有不存在时才放入,防止父类属性覆盖子类属性
|
||||
propMap.putIfAbsent(prop.getFieldName(), prop);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据字段创建属性描述<br>
|
||||
* 查找Getter和Setter方法时会:
|
||||
*
|
||||
* <pre>
|
||||
* 1. 忽略字段和方法名的大小写
|
||||
* 2. Getter查找getXXX、isXXX、getIsXXX
|
||||
* 3. Setter查找setXXX、setIsXXX
|
||||
* 4. Setter忽略参数值与字段值不匹配的情况,因此有多个参数类型的重载时,会调用首次匹配的
|
||||
* </pre>
|
||||
*
|
||||
* @param field 字段
|
||||
* @param methods 类中所有的方法
|
||||
* @return {@link PropDesc}
|
||||
* @since 4.0.2
|
||||
*/
|
||||
private PropDesc createProp(final Field field, final Method[] methods) {
|
||||
final PropDesc prop = findProp(field, methods, false);
|
||||
// 忽略大小写重新匹配一次
|
||||
if (null == prop.getter || null == prop.setter) {
|
||||
final PropDesc propIgnoreCase = findProp(field, methods, true);
|
||||
if (null == prop.getter) {
|
||||
prop.getter = propIgnoreCase.getter;
|
||||
}
|
||||
if (null == prop.setter) {
|
||||
prop.setter = propIgnoreCase.setter;
|
||||
}
|
||||
}
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找字段对应的Getter和Setter方法
|
||||
*
|
||||
* @param field 字段
|
||||
* @param gettersOrSetters 类中所有的Getter或Setter方法
|
||||
* @param ignoreCase 是否忽略大小写匹配
|
||||
* @return PropDesc
|
||||
*/
|
||||
private PropDesc findProp(final Field field, final Method[] gettersOrSetters, final boolean ignoreCase) {
|
||||
final String fieldName = field.getName();
|
||||
final Class<?> fieldType = field.getType();
|
||||
final boolean isBooleanField = BooleanUtil.isBoolean(fieldType);
|
||||
|
||||
// Getter: name -> getName, Setter: name -> setName
|
||||
final Method[] getterAndSetter = findGetterAndSetter(fieldName, fieldType, gettersOrSetters, ignoreCase);
|
||||
|
||||
if (isBooleanField) {
|
||||
if (null == getterAndSetter[0]) {
|
||||
// isName -> isName or isIsName
|
||||
// name -> isName
|
||||
getterAndSetter[0] = getGetterForBoolean(gettersOrSetters, fieldName, ignoreCase);
|
||||
}
|
||||
if (null == getterAndSetter[1]) {
|
||||
// isName -> setName
|
||||
getterAndSetter[1] = getSetterForBoolean(gettersOrSetters, fieldName, ignoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
return new PropDesc(field, getterAndSetter[0], getterAndSetter[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找字段对应的Getter和Setter方法<br>
|
||||
* 此方法不区分是否为boolean字段,查找规则为:
|
||||
* <ul>
|
||||
* <li>Getter要求无参数且返回值是字段类型或字段的父类</li>
|
||||
* <li>Getter中,如果字段为name,匹配getName</li>
|
||||
* <li>Setter要求一个参数且参数必须为字段类型或字段的子类</li>
|
||||
* <li>Setter中,如果字段为name,匹配setName</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param fieldName 字段名
|
||||
* @param fieldType 字段类型
|
||||
* @param gettersOrSetters 类中所有的Getter或Setter方法
|
||||
* @return PropDesc
|
||||
*/
|
||||
private Method[] findGetterAndSetter(final String fieldName, final Class<?> fieldType,
|
||||
final Method[] gettersOrSetters, final boolean ignoreCase) {
|
||||
Method getter = null;
|
||||
Method setter = null;
|
||||
String methodName;
|
||||
for (final Method method : gettersOrSetters) {
|
||||
methodName = method.getName();
|
||||
if (0 == method.getParameterCount()) {
|
||||
// 无参数,可能为Getter方法
|
||||
if (StrUtil.equals(methodName, StrUtil.genGetter(fieldName), ignoreCase) &&
|
||||
method.getReturnType().isAssignableFrom(fieldType)) {
|
||||
// getter的返回类型必须为字段类型或字段的父类
|
||||
getter = method;
|
||||
}
|
||||
} else if (StrUtil.equals(methodName, StrUtil.genSetter(fieldName), ignoreCase) &&
|
||||
fieldType.isAssignableFrom(method.getParameterTypes()[0])) {
|
||||
// setter方法的参数必须为字段类型或字段的子类
|
||||
setter = method;
|
||||
}
|
||||
if (null != getter && null != setter) {
|
||||
// 如果Getter和Setter方法都找到了,不再继续寻找
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new Method[]{getter, setter};
|
||||
}
|
||||
|
||||
/**
|
||||
* 针对Boolean或boolean类型字段,查找其对应的Getter方法,规则为:
|
||||
* <ul>
|
||||
* <li>方法必须无参数且返回boolean或Boolean</li>
|
||||
* <li>如果字段为isName, 匹配isName、isIsName方法,两个方法均存在,则按照提供的方法数组优先匹配。</li>
|
||||
* <li>如果字段为name, 匹配isName方法</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param gettersOrSetters 所有方法
|
||||
* @param fieldName 字段名
|
||||
* @param ignoreCase 是否忽略大小写
|
||||
* @return 查找到的方法,{@code null}表示未找到
|
||||
*/
|
||||
private static Method getGetterForBoolean(final Method[] gettersOrSetters, final String fieldName, final boolean ignoreCase) {
|
||||
// 查找isXXX
|
||||
return MethodUtil.getMethod(gettersOrSetters, m -> {
|
||||
if (0 != m.getParameterCount() || false == BooleanUtil.isBoolean(m.getReturnType())) {
|
||||
// getter方法要求无参数且返回boolean或Boolean
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StrUtil.startWith(fieldName, "is", ignoreCase)) {
|
||||
// isName -》 isName
|
||||
if (StrUtil.equals(fieldName, m.getName(), ignoreCase)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// name -》 isName
|
||||
// isName -》 isIsName
|
||||
return StrUtil.equals(StrUtil.upperFirstAndAddPre(fieldName, "is"), m.getName(), ignoreCase);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 针对Boolean或boolean类型字段,查找其对应的Setter方法,规则为:
|
||||
* <ul>
|
||||
* <li>方法必须为1个boolean或Boolean参数</li>
|
||||
* <li>如果字段为isName,匹配setName</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param fieldName 字段名
|
||||
* @param gettersOrSetters 所有方法
|
||||
* @param ignoreCase 是否忽略大小写
|
||||
* @return 查找到的方法,{@code null}表示未找到
|
||||
*/
|
||||
private static Method getSetterForBoolean(final Method[] gettersOrSetters, final String fieldName, final boolean ignoreCase) {
|
||||
// 查找isXXX
|
||||
return MethodUtil.getMethod(gettersOrSetters, m -> {
|
||||
if (1 != m.getParameterCount() || false == BooleanUtil.isBoolean(m.getParameterTypes()[0])) {
|
||||
// setter方法要求1个boolean或Boolean参数
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StrUtil.startWith(fieldName, "is", ignoreCase)) {
|
||||
// isName -》 setName
|
||||
return StrUtil.equals(
|
||||
"set" + StrUtil.removePrefix(fieldName, "is", ignoreCase),
|
||||
m.getName(), ignoreCase);
|
||||
}
|
||||
|
||||
// 其它不匹配
|
||||
return false;
|
||||
});
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------------ Private method end
|
||||
}
|
@ -12,7 +12,7 @@
|
||||
|
||||
package org.dromara.hutool.core.bean.copier.provider;
|
||||
|
||||
import org.dromara.hutool.core.bean.BeanDesc;
|
||||
import org.dromara.hutool.core.bean.StrictBeanDesc;
|
||||
import org.dromara.hutool.core.bean.BeanUtil;
|
||||
import org.dromara.hutool.core.bean.PropDesc;
|
||||
import org.dromara.hutool.core.bean.copier.ValueProvider;
|
||||
@ -28,7 +28,7 @@ import java.lang.reflect.Type;
|
||||
public class BeanValueProvider implements ValueProvider<String> {
|
||||
|
||||
private final Object bean;
|
||||
private final BeanDesc beanDesc;
|
||||
private final StrictBeanDesc beanDesc;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
|
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2024. looly(loolly@aliyun.com)
|
||||
* Hutool is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* https://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.core.bean.path;
|
||||
|
||||
import org.dromara.hutool.core.bean.BeanDesc;
|
||||
import org.dromara.hutool.core.bean.PropDesc;
|
||||
import org.dromara.hutool.core.lang.Assert;
|
||||
import org.dromara.hutool.core.map.CaseInsensitiveMap;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Bean描述抽象类
|
||||
*
|
||||
* @author Looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public abstract class AbstractBeanDesc implements BeanDesc {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Bean类
|
||||
*/
|
||||
protected final Class<?> beanClass;
|
||||
|
||||
/**
|
||||
* 属性Map
|
||||
*/
|
||||
protected final Map<String, PropDesc> propMap = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param beanClass Bean类
|
||||
*/
|
||||
public AbstractBeanDesc(final Class<?> beanClass) {
|
||||
this.beanClass = Assert.notNull(beanClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Bean的全类名
|
||||
*
|
||||
* @return Bean的类名
|
||||
*/
|
||||
public String getName() {
|
||||
return this.beanClass.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Bean的简单类名
|
||||
*
|
||||
* @return Bean的类名
|
||||
*/
|
||||
public String getSimpleName() {
|
||||
return this.beanClass.getSimpleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Bean类
|
||||
*
|
||||
* @return Bean类
|
||||
*/
|
||||
public Class<?> getBeanClass() {
|
||||
return this.beanClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, PropDesc> getPropMap(final boolean ignoreCase) {
|
||||
return ignoreCase ? new CaseInsensitiveMap<>(1, this.propMap) : this.propMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<PropDesc> getProps() {
|
||||
return this.propMap.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropDesc getProp(final String fieldName) {
|
||||
return this.propMap.get(fieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得字段名对应的字段对象,如果不存在返回null
|
||||
*
|
||||
* @param fieldName 字段名
|
||||
* @return 字段值
|
||||
*/
|
||||
public Field getField(final String fieldName) {
|
||||
final PropDesc desc = this.propMap.get(fieldName);
|
||||
return null == desc ? null : desc.getField();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Getter方法,如果不存在返回null
|
||||
*
|
||||
* @param fieldName 字段名
|
||||
* @return Getter方法
|
||||
*/
|
||||
public Method getGetter(final String fieldName) {
|
||||
final PropDesc desc = this.propMap.get(fieldName);
|
||||
return null == desc ? null : desc.getGetter();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Setter方法,如果不存在返回null
|
||||
*
|
||||
* @param fieldName 字段名
|
||||
* @return Setter方法
|
||||
*/
|
||||
public Method getSetter(final String fieldName) {
|
||||
final PropDesc desc = this.propMap.get(fieldName);
|
||||
return null == desc ? null : desc.getSetter();
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@ package org.dromara.hutool.core.func;
|
||||
import org.dromara.hutool.core.stream.StreamUtil;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 一些{@link Predicate}相关封装
|
||||
@ -103,4 +104,16 @@ public class PredicateUtil {
|
||||
public static <T> Predicate<T> or(final Predicate<T>... components) {
|
||||
return StreamUtil.of(components).reduce(Predicate::or).orElseGet(() -> o -> false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于组合多个方法匹配器的方法匹配器,即所有条件都为false时,才返回true,也可理解为,任一条件为true时,返回false
|
||||
*
|
||||
* @param <T> 判断条件的对象类型
|
||||
* @param components 多个条件
|
||||
* @return 复合条件
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static <T> Predicate<T> none(final Predicate<T>... components){
|
||||
return t -> Stream.of(components).noneMatch(matcher -> matcher.test(t));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2024. looly(loolly@aliyun.com)
|
||||
* Hutool is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* https://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.core.reflect;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
/**
|
||||
* 修饰符枚举
|
||||
*
|
||||
* @author looly
|
||||
* @since 4.0.5
|
||||
*/
|
||||
public enum ModifierType {
|
||||
/**
|
||||
* public修饰符,所有类都能访问
|
||||
*/
|
||||
PUBLIC(Modifier.PUBLIC),
|
||||
/**
|
||||
* private修饰符,只能被自己访问和修改
|
||||
*/
|
||||
PRIVATE(Modifier.PRIVATE),
|
||||
/**
|
||||
* protected修饰符,自身、子类及同一个包中类可以访问
|
||||
*/
|
||||
PROTECTED(Modifier.PROTECTED),
|
||||
/**
|
||||
* static修饰符,(静态修饰符)指定变量被所有对象共享,即所有实例都可以使用该变量。变量属于这个类
|
||||
*/
|
||||
STATIC(Modifier.STATIC),
|
||||
/**
|
||||
* final修饰符,最终修饰符,指定此变量的值不能变,使用在方法上表示不能被重载
|
||||
*/
|
||||
FINAL(Modifier.FINAL),
|
||||
/**
|
||||
* synchronized,同步修饰符,在多个线程中,该修饰符用于在运行前,对他所属的方法加锁,以防止其他线程的访问,运行结束后解锁。
|
||||
*/
|
||||
SYNCHRONIZED(Modifier.SYNCHRONIZED),
|
||||
/**
|
||||
* (易失修饰符)指定该变量可以同时被几个线程控制和修改
|
||||
*/
|
||||
VOLATILE(Modifier.VOLATILE),
|
||||
/**
|
||||
* (过度修饰符)指定该变量是系统保留,暂无特别作用的临时性变量,序列化时忽略
|
||||
*/
|
||||
TRANSIENT(Modifier.TRANSIENT),
|
||||
/**
|
||||
* native,本地修饰符。指定此方法的方法体是用其他语言在程序外部编写的。
|
||||
*/
|
||||
NATIVE(Modifier.NATIVE),
|
||||
|
||||
/**
|
||||
* abstract,将一个类声明为抽象类,没有实现的方法,需要子类提供方法实现。
|
||||
*/
|
||||
ABSTRACT(Modifier.ABSTRACT),
|
||||
/**
|
||||
* strictfp,一旦使用了关键字strictfp来声明某个类、接口或者方法时,那么在这个关键字所声明的范围内所有浮点运算都是精确的,符合IEEE-754规范的。
|
||||
*/
|
||||
STRICT(Modifier.STRICT);
|
||||
|
||||
/**
|
||||
* 修饰符枚举对应的int修饰符值
|
||||
*/
|
||||
private final int value;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param modifier 修饰符int表示,见{@link Modifier}
|
||||
*/
|
||||
ModifierType(final int modifier) {
|
||||
this.value = modifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取修饰符枚举对应的int修饰符值,值见{@link Modifier}
|
||||
*
|
||||
* @return 修饰符枚举对应的int修饰符值
|
||||
*/
|
||||
public int getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 多个修饰符做“或”操作,表示存在任意一个修饰符
|
||||
*
|
||||
* @param modifierTypes 修饰符列表,元素不能为空
|
||||
* @return “或”之后的修饰符
|
||||
*/
|
||||
public static int orToInt(final ModifierType... modifierTypes) {
|
||||
int modifier = modifierTypes[0].getValue();
|
||||
for (int i = 1; i < modifierTypes.length; i++) {
|
||||
modifier |= modifierTypes[i].getValue();
|
||||
}
|
||||
return modifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* 多个修饰符做“或”操作,表示存在任意一个修饰符
|
||||
*
|
||||
* @param modifierTypes 修饰符列表,元素不能为空
|
||||
* @return “或”之后的修饰符
|
||||
*/
|
||||
public static int orToInt(final int... modifierTypes) {
|
||||
int modifier = modifierTypes[0];
|
||||
for (int i = 1; i < modifierTypes.length; i++) {
|
||||
modifier |= modifierTypes[i];
|
||||
}
|
||||
return modifier;
|
||||
}
|
||||
}
|
@ -28,83 +28,6 @@ import java.lang.reflect.Modifier;
|
||||
*/
|
||||
public class ModifierUtil {
|
||||
|
||||
/**
|
||||
* 修饰符枚举
|
||||
*
|
||||
* @author looly
|
||||
* @since 4.0.5
|
||||
*/
|
||||
public enum ModifierType {
|
||||
/**
|
||||
* public修饰符,所有类都能访问
|
||||
*/
|
||||
PUBLIC(Modifier.PUBLIC),
|
||||
/**
|
||||
* private修饰符,只能被自己访问和修改
|
||||
*/
|
||||
PRIVATE(Modifier.PRIVATE),
|
||||
/**
|
||||
* protected修饰符,自身、子类及同一个包中类可以访问
|
||||
*/
|
||||
PROTECTED(Modifier.PROTECTED),
|
||||
/**
|
||||
* static修饰符,(静态修饰符)指定变量被所有对象共享,即所有实例都可以使用该变量。变量属于这个类
|
||||
*/
|
||||
STATIC(Modifier.STATIC),
|
||||
/**
|
||||
* final修饰符,最终修饰符,指定此变量的值不能变,使用在方法上表示不能被重载
|
||||
*/
|
||||
FINAL(Modifier.FINAL),
|
||||
/**
|
||||
* synchronized,同步修饰符,在多个线程中,该修饰符用于在运行前,对他所属的方法加锁,以防止其他线程的访问,运行结束后解锁。
|
||||
*/
|
||||
SYNCHRONIZED(Modifier.SYNCHRONIZED),
|
||||
/**
|
||||
* (易失修饰符)指定该变量可以同时被几个线程控制和修改
|
||||
*/
|
||||
VOLATILE(Modifier.VOLATILE),
|
||||
/**
|
||||
* (过度修饰符)指定该变量是系统保留,暂无特别作用的临时性变量,序列化时忽略
|
||||
*/
|
||||
TRANSIENT(Modifier.TRANSIENT),
|
||||
/**
|
||||
* native,本地修饰符。指定此方法的方法体是用其他语言在程序外部编写的。
|
||||
*/
|
||||
NATIVE(Modifier.NATIVE),
|
||||
|
||||
/**
|
||||
* abstract,将一个类声明为抽象类,没有实现的方法,需要子类提供方法实现。
|
||||
*/
|
||||
ABSTRACT(Modifier.ABSTRACT),
|
||||
/**
|
||||
* strictfp,一旦使用了关键字strictfp来声明某个类、接口或者方法时,那么在这个关键字所声明的范围内所有浮点运算都是精确的,符合IEEE-754规范的。
|
||||
*/
|
||||
STRICT(Modifier.STRICT);
|
||||
|
||||
/**
|
||||
* 修饰符枚举对应的int修饰符值
|
||||
*/
|
||||
private final int value;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param modifier 修饰符int表示,见{@link Modifier}
|
||||
*/
|
||||
ModifierType(final int modifier) {
|
||||
this.value = modifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取修饰符枚举对应的int修饰符值,值见{@link Modifier}
|
||||
*
|
||||
* @return 修饰符枚举对应的int修饰符值
|
||||
*/
|
||||
public int getValue() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否同时存在一个或多个修饰符(可能有多个修饰符,如果有指定的修饰符则返回true)
|
||||
*
|
||||
@ -116,7 +39,7 @@ public class ModifierUtil {
|
||||
if (null == clazz || ArrayUtil.isEmpty(modifierTypes)) {
|
||||
return false;
|
||||
}
|
||||
return 0 != (clazz.getModifiers() & modifiersToInt(modifierTypes));
|
||||
return 0 != (clazz.getModifiers() & ModifierType.orToInt(modifierTypes));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -130,7 +53,34 @@ public class ModifierUtil {
|
||||
if (null == member || ArrayUtil.isEmpty(modifierTypes)) {
|
||||
return false;
|
||||
}
|
||||
return 0 != (member.getModifiers() & modifiersToInt(modifierTypes));
|
||||
return 0 != (member.getModifiers() & ModifierType.orToInt(modifierTypes));
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否同时存在一个或多个修饰符(可能有多个修饰符,如果有指定的修饰符则返回true)
|
||||
*
|
||||
* @param modifiers 类、构造、字段或方法的修饰符
|
||||
* @param checkedModifiers 需要检查的修饰符,如果为空返回{@code false}
|
||||
* @return 是否有指定修饰符,如果有返回true,否则false,如果提供参数为null返回false
|
||||
*/
|
||||
public static boolean hasModifier(final int modifiers, final int... checkedModifiers) {
|
||||
return 0 != (modifiers & ModifierType.orToInt(checkedModifiers));
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否同时存在一个或多个修饰符(可能有多个修饰符,如果有指定的修饰符则返回true)
|
||||
*
|
||||
* @param modifiers 类、构造、字段或方法的修饰符
|
||||
* @param checkedModifiers 需要检查的修饰符,如果为空返回{@code false}
|
||||
* @return 是否有指定修饰符,如果有返回true,否则false,如果提供参数为null返回false
|
||||
*/
|
||||
public static boolean hasAllModifier(final int modifiers, final int... checkedModifiers) {
|
||||
for (final int checkedModifier : checkedModifiers) {
|
||||
if (0 == (modifiers & checkedModifier)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -318,20 +268,4 @@ public class ModifierUtil {
|
||||
throw new HutoolException(e, "IllegalAccess for [{}.{}]", field.getDeclaringClass(), field.getName());
|
||||
}
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------- Private method start
|
||||
|
||||
/**
|
||||
* 多个修饰符做“与”操作,表示同时存在多个修饰符
|
||||
*
|
||||
* @param modifierTypes 修饰符列表,元素不能为空
|
||||
* @return “与”之后的修饰符
|
||||
*/
|
||||
private static int modifiersToInt(final ModifierType... modifierTypes) {
|
||||
int modifier = modifierTypes[0].getValue();
|
||||
for (int i = 1; i < modifierTypes.length; i++) {
|
||||
modifier |= modifierTypes[i].getValue();
|
||||
}
|
||||
return modifier;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------- Private method end
|
||||
}
|
||||
|
@ -14,7 +14,9 @@ package org.dromara.hutool.core.reflect.method;
|
||||
|
||||
import org.dromara.hutool.core.annotation.AnnotatedElementUtil;
|
||||
import org.dromara.hutool.core.array.ArrayUtil;
|
||||
import org.dromara.hutool.core.func.PredicateUtil;
|
||||
import org.dromara.hutool.core.reflect.ClassUtil;
|
||||
import org.dromara.hutool.core.reflect.ModifierUtil;
|
||||
import org.dromara.hutool.core.text.CharSequenceUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@ -22,7 +24,6 @@ import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Predicate;
|
||||
@ -45,7 +46,7 @@ public class MethodMatcherUtil {
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static Predicate<Method> noneMatch(final Predicate<Method>... matchers) {
|
||||
return method -> Stream.of(matchers).noneMatch(matcher -> matcher.test(method));
|
||||
return PredicateUtil.none(matchers);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,7 +58,7 @@ public class MethodMatcherUtil {
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static Predicate<Method> anyMatch(final Predicate<Method>... matchers) {
|
||||
return method -> Stream.of(matchers).anyMatch(matcher -> matcher.test(method));
|
||||
return PredicateUtil.or(matchers);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -69,7 +70,7 @@ public class MethodMatcherUtil {
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static Predicate<Method> allMatch(final Predicate<Method>... matchers) {
|
||||
return method -> Stream.of(matchers).allMatch(matcher -> matcher.test(method));
|
||||
return PredicateUtil.and(matchers);
|
||||
}
|
||||
|
||||
// region ============= 访问修饰符 =============
|
||||
@ -108,10 +109,7 @@ public class MethodMatcherUtil {
|
||||
* @return 方法匹配器
|
||||
*/
|
||||
public static Predicate<Method> forModifiers(final int... modifiers) {
|
||||
return method -> {
|
||||
final int methodModifiers = method.getModifiers();
|
||||
return Arrays.stream(modifiers).allMatch(modifier -> (methodModifiers & modifier) != 0);
|
||||
};
|
||||
return method -> ModifierUtil.hasAllModifier(method.getModifiers(), modifiers);
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
@ -54,6 +54,18 @@ public class MethodUtil {
|
||||
|
||||
// region ----- getMethods
|
||||
|
||||
/**
|
||||
* 通过给定的条件(Predicate)从一个Method数组中查找第一个匹配的方法。
|
||||
*
|
||||
* @param methods Method数组,是被搜索的目标对象。
|
||||
* @param predicate 一个Predicate接口实例,用于定义查找方法的条件。
|
||||
* @return 返回第一个满足predicate条件的Method对象,如果没有找到匹配的方法则返回null。
|
||||
*/
|
||||
public static Method getMethod(final Method[] methods, final Predicate<Method> predicate) {
|
||||
// 使用ArrayUtil的get方法,通过predicate对methods数组进行搜索
|
||||
return ArrayUtil.get(methods, predicate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得指定类本类及其父类中的Public方法名<br>
|
||||
* 去重重载的方法
|
||||
@ -81,15 +93,7 @@ public class MethodUtil {
|
||||
if (null == clazz || StrUtil.isBlank(methodName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Method[] methods = getPublicMethods(clazz, method ->
|
||||
StrUtil.equals(methodName, method.getName(), ignoreCase)
|
||||
&& ClassUtil.isAllAssignableFrom(method.getParameterTypes(), paramTypes)
|
||||
//排除桥接方法,pr#1965@Github
|
||||
//排除协变桥接方法,pr#1965@Github
|
||||
&& (method.getReturnType().isAssignableFrom(method.getReturnType())));
|
||||
|
||||
return ArrayUtil.isEmpty(methods) ? null : methods[0];
|
||||
return getMethod(getPublicMethods(clazz), ignoreCase, methodName, paramTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -164,15 +168,40 @@ public class MethodUtil {
|
||||
if (null == clazz || StrUtil.isBlank(methodName)) {
|
||||
return null;
|
||||
}
|
||||
return getMethod(getMethods(clazz), ignoreCase, methodName, paramTypes);
|
||||
}
|
||||
|
||||
final Method[] methods = getMethods(clazz, method ->
|
||||
StrUtil.equals(methodName, method.getName(), ignoreCase)
|
||||
&& ClassUtil.isAllAssignableFrom(method.getParameterTypes(), paramTypes)
|
||||
//排除桥接方法,pr#1965@Github
|
||||
//排除协变桥接方法,pr#1965@Github
|
||||
&& (method.getReturnType().isAssignableFrom(method.getReturnType())));
|
||||
/**
|
||||
* 查找指定方法 如果找不到对应的方法则返回{@code null}<br>
|
||||
* 此方法为精准获取方法名,即方法名和参数数量和类型必须一致,否则返回{@code null}。<br>
|
||||
* 如果查找的方法有多个同参数类型重载,查找最后一个非协变桥接方法
|
||||
*
|
||||
* @param methods 方法列表
|
||||
* @param ignoreCase 是否忽略大小写
|
||||
* @param methodName 方法名,如果为空字符串返回{@code null}
|
||||
* @param paramTypes 参数类型,指定参数类型如果是方法的子类也算
|
||||
* @return 方法
|
||||
* @throws SecurityException 无权访问抛出异常
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static Method getMethod(final Method[] methods, final boolean ignoreCase, final String methodName, final Class<?>... paramTypes) throws SecurityException {
|
||||
if (ArrayUtil.isEmpty(methods) || StrUtil.isBlank(methodName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ArrayUtil.isEmpty(methods) ? null : methods[0];
|
||||
Method res = null;
|
||||
if (ArrayUtil.isNotEmpty(methods)) {
|
||||
for (final Method method : methods) {
|
||||
if (StrUtil.equals(methodName, method.getName(), ignoreCase)
|
||||
&& ClassUtil.isAllAssignableFrom(method.getParameterTypes(), paramTypes)
|
||||
//排除协变桥接方法,pr#1965@Github
|
||||
&& (res == null
|
||||
|| res.getReturnType().isAssignableFrom(method.getReturnType()))) {
|
||||
res = method;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -724,5 +753,4 @@ public class MethodUtil {
|
||||
|
||||
return actualArgs;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
package org.dromara.hutool.core.text.placeholder.template;
|
||||
|
||||
import org.dromara.hutool.core.array.ArrayUtil;
|
||||
import org.dromara.hutool.core.bean.BeanDesc;
|
||||
import org.dromara.hutool.core.bean.StrictBeanDesc;
|
||||
import org.dromara.hutool.core.bean.BeanUtil;
|
||||
import org.dromara.hutool.core.collection.CollUtil;
|
||||
import org.dromara.hutool.core.collection.ListUtil;
|
||||
@ -344,7 +344,7 @@ public class NamedPlaceholderStrTemplate extends StrTemplate {
|
||||
if (beanOrMap instanceof Map) {
|
||||
return format((Map<String, ?>) beanOrMap);
|
||||
} else if (BeanUtil.isReadableBean(beanOrMap.getClass())) {
|
||||
final BeanDesc beanDesc = BeanUtil.getBeanDesc(beanOrMap.getClass());
|
||||
final StrictBeanDesc beanDesc = BeanUtil.getBeanDesc(beanOrMap.getClass());
|
||||
return format(fieldName -> {
|
||||
final Method getterMethod = beanDesc.getGetter(fieldName);
|
||||
if (getterMethod == null) {
|
||||
@ -553,7 +553,7 @@ public class NamedPlaceholderStrTemplate extends StrTemplate {
|
||||
@SuppressWarnings("unchecked") final Map<String, String> map = (Map<String, String>) obj;
|
||||
matchesByKey(str, map::put);
|
||||
} else if (BeanUtil.isReadableBean(obj.getClass())) {
|
||||
final BeanDesc beanDesc = BeanUtil.getBeanDesc(obj.getClass());
|
||||
final StrictBeanDesc beanDesc = BeanUtil.getBeanDesc(obj.getClass());
|
||||
matchesByKey(str, (key, value) -> {
|
||||
final Field field = beanDesc.getField(key);
|
||||
final Method setterMethod = beanDesc.getSetter(key);
|
||||
|
@ -16,7 +16,7 @@ import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* {@link BeanDesc} 单元测试类
|
||||
* {@link StrictBeanDesc} 单元测试类
|
||||
*
|
||||
* @author looly
|
||||
*
|
||||
@ -25,7 +25,7 @@ public class BeanDescTest {
|
||||
|
||||
@Test
|
||||
public void propDescTes() {
|
||||
final BeanDesc desc = BeanUtil.getBeanDesc(User.class);
|
||||
final StrictBeanDesc desc = BeanUtil.getBeanDesc(User.class);
|
||||
Assertions.assertEquals("User", desc.getSimpleName());
|
||||
|
||||
Assertions.assertEquals("age", desc.getField("age").getName());
|
||||
@ -38,7 +38,7 @@ public class BeanDescTest {
|
||||
|
||||
@Test
|
||||
public void propDescTes2() {
|
||||
final BeanDesc desc = BeanUtil.getBeanDesc(User.class);
|
||||
final StrictBeanDesc desc = BeanUtil.getBeanDesc(User.class);
|
||||
|
||||
final PropDesc prop = desc.getProp("name");
|
||||
Assertions.assertEquals("name", prop.getFieldName());
|
||||
@ -50,7 +50,7 @@ public class BeanDescTest {
|
||||
|
||||
@Test
|
||||
public void propDescOfBooleanTest() {
|
||||
final BeanDesc desc = BeanUtil.getBeanDesc(User.class);
|
||||
final StrictBeanDesc desc = BeanUtil.getBeanDesc(User.class);
|
||||
|
||||
Assertions.assertEquals("isAdmin", desc.getGetter("isAdmin").getName());
|
||||
Assertions.assertEquals("setAdmin", desc.getSetter("isAdmin").getName());
|
||||
@ -60,7 +60,7 @@ public class BeanDescTest {
|
||||
|
||||
@Test
|
||||
public void propDescOfBooleanTest2() {
|
||||
final BeanDesc desc = BeanUtil.getBeanDesc(User.class);
|
||||
final StrictBeanDesc desc = BeanUtil.getBeanDesc(User.class);
|
||||
|
||||
Assertions.assertEquals("isIsSuper", desc.getGetter("isSuper").getName());
|
||||
Assertions.assertEquals("setIsSuper", desc.getSetter("isSuper").getName());
|
||||
@ -68,7 +68,7 @@ public class BeanDescTest {
|
||||
|
||||
@Test
|
||||
public void propDescOfBooleanTest3() {
|
||||
final BeanDesc desc = BeanUtil.getBeanDesc(User.class);
|
||||
final StrictBeanDesc desc = BeanUtil.getBeanDesc(User.class);
|
||||
|
||||
Assertions.assertEquals("setLastPage", desc.getSetter("lastPage").getName());
|
||||
Assertions.assertEquals("setIsLastPage", desc.getSetter("isLastPage").getName());
|
||||
@ -76,7 +76,7 @@ public class BeanDescTest {
|
||||
|
||||
@Test
|
||||
public void getSetTest() {
|
||||
final BeanDesc desc = BeanUtil.getBeanDesc(User.class);
|
||||
final StrictBeanDesc desc = BeanUtil.getBeanDesc(User.class);
|
||||
|
||||
final User user = new User();
|
||||
desc.getProp("name").setValue(user, "张三");
|
||||
|
@ -20,7 +20,7 @@ public class BeanWithReturnThisTest {
|
||||
@Test
|
||||
public void setValueTest() {
|
||||
final BeanWithRetuenThis bean = new BeanWithRetuenThis();
|
||||
final BeanDesc beanDesc = BeanUtil.getBeanDesc(BeanWithRetuenThis.class);
|
||||
final StrictBeanDesc beanDesc = BeanUtil.getBeanDesc(BeanWithRetuenThis.class);
|
||||
final PropDesc prop = beanDesc.getProp("a");
|
||||
prop.setValue(bean, "123");
|
||||
|
||||
|
@ -19,7 +19,7 @@ public class Issue3096Test {
|
||||
|
||||
@Test
|
||||
void beanDescTest() {
|
||||
final BeanDesc desc = BeanUtil.getBeanDesc(User.class);
|
||||
final StrictBeanDesc desc = BeanUtil.getBeanDesc(User.class);
|
||||
|
||||
// https://github.com/dromara/hutool/issues/3096
|
||||
// 新修改的规则中,isLastPage字段优先匹配setIsLastPage,这个顺序固定。
|
||||
|
@ -13,6 +13,7 @@
|
||||
package org.dromara.hutool.core.util;
|
||||
|
||||
import org.dromara.hutool.core.reflect.FieldUtil;
|
||||
import org.dromara.hutool.core.reflect.ModifierType;
|
||||
import org.dromara.hutool.core.reflect.ModifierUtil;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@ -28,10 +29,10 @@ public class ModifierUtilTest {
|
||||
@Test
|
||||
public void hasModifierTest() throws NoSuchMethodException {
|
||||
final Method method = ModifierUtilTest.class.getDeclaredMethod("ddd");
|
||||
Assertions.assertTrue(ModifierUtil.hasModifier(method, ModifierUtil.ModifierType.PRIVATE));
|
||||
Assertions.assertTrue(ModifierUtil.hasModifier(method, ModifierType.PRIVATE));
|
||||
Assertions.assertTrue(ModifierUtil.hasModifier(method,
|
||||
ModifierUtil.ModifierType.PRIVATE,
|
||||
ModifierUtil.ModifierType.STATIC)
|
||||
ModifierType.PRIVATE,
|
||||
ModifierType.STATIC)
|
||||
);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user