This commit is contained in:
Looly
2024-09-10 20:19:36 +08:00
parent 264d24b54c
commit eec27cdc40
30 changed files with 618 additions and 222 deletions

View File

@@ -16,8 +16,9 @@
package org.dromara.hutool.core.bean;
import org.dromara.hutool.core.reflect.Invoker;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;
@@ -62,7 +63,7 @@ public interface BeanDesc extends Serializable {
* @param fieldName 字段名
* @return Getter方法
*/
default Method getGetter(final String fieldName) {
default Invoker getGetter(final String fieldName) {
final PropDesc desc = getProp(fieldName);
return null == desc ? null : desc.getGetter();
}
@@ -73,7 +74,7 @@ public interface BeanDesc extends Serializable {
* @param fieldName 字段名
* @return Setter方法
*/
default Method getSetter(final String fieldName) {
default Invoker getSetter(final String fieldName) {
final PropDesc desc = getProp(fieldName);
return null == desc ? null : desc.getSetter();
}

View File

@@ -20,7 +20,7 @@ import org.dromara.hutool.core.annotation.AnnotationUtil;
import org.dromara.hutool.core.annotation.PropIgnore;
import org.dromara.hutool.core.convert.ConvertUtil;
import org.dromara.hutool.core.reflect.*;
import org.dromara.hutool.core.reflect.method.MethodUtil;
import org.dromara.hutool.core.reflect.method.MethodInvoker;
import java.beans.Transient;
import java.lang.reflect.Field;
@@ -37,7 +37,7 @@ public class PropDesc {
/**
* 字段
*/
private Field field;
private Invoker fieldInvoker;
/**
* 字段名
*/
@@ -45,11 +45,11 @@ public class PropDesc {
/**
* Getter方法
*/
protected Method getter;
protected Invoker getter;
/**
* Setter方法
*/
protected Method setter;
protected Invoker setter;
/**
* 构造<br>
@@ -61,21 +61,21 @@ public class PropDesc {
*/
public PropDesc(final Field field, final Method getter, final Method setter) {
this(FieldUtil.getFieldName(field), getter, setter);
this.field = field;
this.fieldInvoker = null == field ? null : FieldInvoker.of(field);
}
/**
* 构造<br>
* Getter和Setter方法设置为默认可访问
*
* @param fieldName 字段名
* @param getter get方法
* @param setter set方法
* @param fieldName 字段名
* @param getterMethod get方法
* @param setterMethod set方法
*/
public PropDesc(final String fieldName, final Method getter, final Method setter) {
public PropDesc(final String fieldName, final Method getterMethod, final Method setterMethod) {
this.fieldName = fieldName;
this.getter = ReflectUtil.setAccessible(getter);
this.setter = ReflectUtil.setAccessible(setter);
this.getter = null == getterMethod ? null : MethodInvoker.of(getterMethod);
this.setter = null == setterMethod ? null : MethodInvoker.of(setterMethod);
}
/**
@@ -94,7 +94,11 @@ public class PropDesc {
* @since 5.1.6
*/
public String getRawFieldName() {
return null == this.field ? null : this.field.getName();
if (null == this.fieldInvoker) {
return this.fieldName;
}
return this.fieldInvoker.getName();
}
/**
@@ -103,7 +107,10 @@ public class PropDesc {
* @return 字段
*/
public Field getField() {
return this.field;
if (null != this.fieldInvoker && this.fieldInvoker instanceof FieldInvoker) {
return ((FieldInvoker) this.fieldInvoker).getField();
}
return null;
}
/**
@@ -113,8 +120,8 @@ public class PropDesc {
* @return 字段类型
*/
public Type getFieldType() {
if (null != this.field) {
return TypeUtil.getType(this.field);
if (null != this.fieldInvoker) {
return this.fieldInvoker.getType();
}
return findPropType(getter, setter);
}
@@ -126,27 +133,27 @@ public class PropDesc {
* @return 字段类型
*/
public Class<?> getFieldClass() {
if (null != this.field) {
return TypeUtil.getClass(this.field);
if (null != this.fieldInvoker) {
return this.fieldInvoker.getTypeClass();
}
return findPropClass(getter, setter);
}
/**
* 获取Getter方法可能为{@code null}
* 获取Getter方法Invoker,可能为{@code null}
*
* @return Getter方法
* @return Getter方法Invoker
*/
public Method getGetter() {
public Invoker getGetter() {
return this.getter;
}
/**
* 获取Setter方法可能为{@code null}
* 获取Setter方法Invoker,可能为{@code null}
*
* @return {@link Method}Setter 方法对象
* @return {@link Method}Setter 方法Invoker
*/
public Method getSetter() {
public Invoker getSetter() {
return this.setter;
}
@@ -158,18 +165,27 @@ public class PropDesc {
* @since 5.4.2
*/
public boolean isReadable(final boolean checkTransient) {
// 检查是否有getter方法或是否为public修饰
if (null == this.getter && !ModifierUtil.isPublic(this.field)) {
return false;
Field field = null;
if (this.fieldInvoker instanceof FieldInvoker) {
field = ((FieldInvoker) this.fieldInvoker).getField();
}
Method getterMethod = null;
if (this.getter instanceof MethodInvoker) {
getterMethod = ((MethodInvoker) this.getter).getMethod();
}
// 检查transient关键字和@Transient注解
if (checkTransient && isTransientForGet()) {
if (checkTransient && isTransientForGet(field, getterMethod)) {
return false;
}
// 检查@PropIgnore注解
return !isIgnoreGet();
if (isIgnoreGet(field, getterMethod)) {
return false;
}
// 检查是否有getter方法或是否为public修饰
return null != getterMethod || ModifierUtil.isPublic(field);
}
/**
@@ -183,11 +199,9 @@ public class PropDesc {
*/
public Object getValue(final Object bean) {
if (null != this.getter) {
// issue#3671 JDK15+ 修改了lambda的策略动态生成后在metaspace不会释放导致资源占用高
//return LambdaUtil.buildGetter(this.getter).apply(bean);
return MethodUtil.invoke(bean, this.getter);
} else if (ModifierUtil.isPublic(this.field)) {
return FieldUtil.getFieldValue(bean, this.field);
return this.getter.invoke(bean);
} else if (null != this.fieldInvoker) {
return fieldInvoker.invoke(bean);
}
return null;
@@ -230,18 +244,27 @@ public class PropDesc {
* @since 5.4.2
*/
public boolean isWritable(final boolean checkTransient) {
// 检查是否有getter方法或是否为public修饰
if (null == this.setter && !ModifierUtil.isPublic(this.field)) {
return false;
Field field = null;
if (this.fieldInvoker instanceof FieldInvoker) {
field = ((FieldInvoker) this.fieldInvoker).getField();
}
Method setterMethod = null;
if (this.setter instanceof MethodInvoker) {
setterMethod = ((MethodInvoker) this.setter).getMethod();
}
// 检查transient关键字和@Transient注解
if (checkTransient && isTransientForSet()) {
if (checkTransient && isTransientForSet(field, setterMethod)) {
return false;
}
// 检查@PropIgnore注解
return !isIgnoreSet();
if(isIgnoreSet(field, setterMethod)){
return false;
}
// 检查是否有setter方法或是否为public修饰
return null != setterMethod || ModifierUtil.isPublic(field);
}
/**
@@ -256,9 +279,9 @@ public class PropDesc {
*/
public PropDesc setValue(final Object bean, final Object value) {
if (null != this.setter) {
MethodUtil.invoke(bean, this.setter, value);
} else if (ModifierUtil.isPublic(this.field)) {
FieldUtil.setFieldValue(bean, this.field, value);
this.setter.invoke(bean, value);
} else if (null != this.fieldInvoker) {
fieldInvoker.invoke(bean, value);
}
return this;
}
@@ -325,29 +348,29 @@ public class PropDesc {
@Override
public String toString() {
return "PropDesc{" +
"field=" + field +
"field=" + fieldInvoker +
", fieldName=" + fieldName +
", getter=" + getter +
", setter=" + setter +
'}';
}
//------------------------------------------------------------------------------------ Private method start
// region ----- private methods
/**
* 通过Getter和Setter方法中找到属性类型
*
* @param getter Getter方法
* @param setter Setter方法
* @param getterInvoker Getter方法Invoker
* @param setterInvoker Setter方法Invoker
* @return {@link Type}
*/
private Type findPropType(final Method getter, final Method setter) {
private Type findPropType(final Invoker getterInvoker, final Invoker setterInvoker) {
Type type = null;
if (null != getter) {
type = TypeUtil.getReturnType(getter);
if (null != getterInvoker) {
type = getterInvoker.getType();
}
if (null == type && null != setter) {
type = TypeUtil.getParamType(setter, 0);
if (null == type && null != setterInvoker) {
type = setterInvoker.getType();
}
return type;
}
@@ -355,36 +378,21 @@ public class PropDesc {
/**
* 通过Getter和Setter方法中找到属性类型
*
* @param getter Getter方法
* @param setter Setter方法
* @param getterInvoker Getter方法Invoker
* @param setterInvoker Setter方法Invoker
* @return {@link Type}
*/
private Class<?> findPropClass(final Method getter, final Method setter) {
private Class<?> findPropClass(final Invoker getterInvoker, final Invoker setterInvoker) {
Class<?> type = null;
if (null != getter) {
type = TypeUtil.getReturnClass(getter);
if (null != getterInvoker) {
type = getterInvoker.getTypeClass();
}
if (null == type && null != setter) {
type = TypeUtil.getFirstParamClass(setter);
if (null == type && null != setterInvoker) {
type = setterInvoker.getTypeClass();
}
return type;
}
/**
* 检查字段是否被忽略写,通过{@link PropIgnore} 注解完成,规则为:
* <pre>
* 1. 在字段上有{@link PropIgnore} 注解
* 2. 在setXXX方法上有{@link PropIgnore} 注解
* </pre>
*
* @return 是否忽略写
* @since 5.4.2
*/
private boolean isIgnoreSet() {
return AnnotationUtil.hasAnnotation(this.field, PropIgnore.class)
|| AnnotationUtil.hasAnnotation(this.setter, PropIgnore.class);
}
/**
* 检查字段是否被忽略读,通过{@link PropIgnore} 注解完成,规则为:
* <pre>
@@ -392,30 +400,48 @@ public class PropDesc {
* 2. 在getXXX方法上有{@link PropIgnore} 注解
* </pre>
*
* @param field 字段,可为{@code null}
* @param getterMethod 读取方法,可为{@code null}
* @return 是否忽略读
* @since 5.4.2
*/
private boolean isIgnoreGet() {
return AnnotationUtil.hasAnnotation(this.field, PropIgnore.class)
|| AnnotationUtil.hasAnnotation(this.getter, PropIgnore.class);
private static boolean isIgnoreGet(final Field field, final Method getterMethod) {
return AnnotationUtil.hasAnnotation(field, PropIgnore.class)
|| AnnotationUtil.hasAnnotation(getterMethod, PropIgnore.class);
}
/**
* 检查字段是否被忽略写,通过{@link PropIgnore} 注解完成,规则为:
* <pre>
* 1. 在字段上有{@link PropIgnore} 注解
* 2. 在setXXX方法上有{@link PropIgnore} 注解
* </pre>
*
* @param field 字段,可为{@code null}
* @param setterMethod 写方法,可为{@code null}
* @return 是否忽略写
*/
private static boolean isIgnoreSet(final Field field, final Method setterMethod) {
return AnnotationUtil.hasAnnotation(field, PropIgnore.class)
|| AnnotationUtil.hasAnnotation(setterMethod, PropIgnore.class);
}
/**
* 字段和Getter方法是否为Transient关键字修饰的
*
* @param field 字段,可为{@code null}
* @param getterMethod 读取方法,可为{@code null}
* @return 是否为Transient关键字修饰的
* @since 5.3.11
*/
private boolean isTransientForGet() {
boolean isTransient = ModifierUtil.hasModifier(this.field, ModifierType.TRANSIENT);
private static boolean isTransientForGet(final Field field, final Method getterMethod) {
boolean isTransient = ModifierUtil.hasModifier(field, ModifierType.TRANSIENT);
// 检查Getter方法
if (!isTransient && null != this.getter) {
isTransient = ModifierUtil.hasModifier(this.getter, ModifierType.TRANSIENT);
if (!isTransient && null != getterMethod) {
isTransient = ModifierUtil.hasModifier(getterMethod, ModifierType.TRANSIENT);
// 检查注解
if (!isTransient) {
isTransient = AnnotationUtil.hasAnnotation(this.getter, Transient.class);
isTransient = AnnotationUtil.hasAnnotation(getterMethod, Transient.class);
}
}
@@ -425,23 +451,24 @@ public class PropDesc {
/**
* 字段和Getter方法是否为Transient关键字修饰的
*
* @param field 字段,可为{@code null}
* @param setterMethod 写方法,可为{@code null}
* @return 是否为Transient关键字修饰的
* @since 5.3.11
*/
private boolean isTransientForSet() {
boolean isTransient = ModifierUtil.hasModifier(this.field, ModifierType.TRANSIENT);
private static boolean isTransientForSet(final Field field, final Method setterMethod) {
boolean isTransient = ModifierUtil.hasModifier(field, ModifierType.TRANSIENT);
// 检查Getter方法
if (!isTransient && null != this.setter) {
isTransient = ModifierUtil.hasModifier(this.setter, ModifierType.TRANSIENT);
if (!isTransient && null != setterMethod) {
isTransient = ModifierUtil.hasModifier(setterMethod, ModifierType.TRANSIENT);
// 检查注解
if (!isTransient) {
isTransient = AnnotationUtil.hasAnnotation(this.setter, Transient.class);
isTransient = AnnotationUtil.hasAnnotation(setterMethod, Transient.class);
}
}
return isTransient;
}
//------------------------------------------------------------------------------------ Private method end
// endregion
}

View File

@@ -17,6 +17,8 @@
package org.dromara.hutool.core.bean;
import org.dromara.hutool.core.bean.path.AbstractBeanDesc;
import org.dromara.hutool.core.reflect.TypeUtil;
import org.dromara.hutool.core.reflect.method.MethodInvoker;
import org.dromara.hutool.core.reflect.method.MethodNameUtil;
import org.dromara.hutool.core.reflect.method.MethodUtil;
import org.dromara.hutool.core.util.BooleanUtil;
@@ -86,17 +88,17 @@ public class SimpleBeanDesc extends AbstractBeanDesc {
} else{
if(isSetter){
if(null == propDesc.setter ||
propDesc.setter.getParameterTypes()[0].isAssignableFrom(method.getParameterTypes()[0])){
propDesc.setter.getTypeClass().isAssignableFrom(method.getParameterTypes()[0])){
// 如果存在多个重载的setter方法选择参数类型最匹配的
propDesc.setter = method;
propDesc.setter = MethodInvoker.of(method);
}
}else{
if(null == propDesc.getter ||
(BooleanUtil.isBoolean(propDesc.getter.getReturnType()) &&
(BooleanUtil.isBoolean(propDesc.getter.getTypeClass()) &&
BooleanUtil.isBoolean(method.getReturnType()) &&
methodName.startsWith(MethodNameUtil.IS_PREFIX))){
// 如果返回值为Boolean或booleanisXXX优先于getXXX
propDesc.getter = method;
propDesc.getter = MethodInvoker.of(method);
}
}
}

View File

@@ -259,8 +259,6 @@ public class RegisterConverter implements Converter, Serializable {
defaultConverterMap.put(AtomicLongArray.class, new AtomicLongArrayConverter());
// 其它类型
defaultConverterMap.put(TimeZone.class, new TimeZoneConverter());
defaultConverterMap.put(ZoneId.class, new ZoneIdConverter());
defaultConverterMap.put(Locale.class, new LocaleConverter());
defaultConverterMap.put(Charset.class, new CharsetConverter());
defaultConverterMap.put(Path.class, new PathConverter());

View File

@@ -94,6 +94,10 @@ public class SpecialConverter implements Converter, Serializable {
// // 空值转空Bean
converterSet.add(EmptyBeanConverter.INSTANCE);
// 日期相关
converterSet.add(TimeZoneConverter.INSTANCE);
converterSet.add(ZoneIdConverter.INSTANCE);
this.converterSet = converterSet;
}

View File

@@ -17,8 +17,10 @@
package org.dromara.hutool.core.convert.impl;
import org.dromara.hutool.core.convert.AbstractConverter;
import org.dromara.hutool.core.convert.MatcherConverter;
import org.dromara.hutool.core.date.ZoneUtil;
import java.lang.reflect.Type;
import java.time.ZoneId;
import java.util.TimeZone;
@@ -27,9 +29,19 @@ import java.util.TimeZone;
* @author Looly
*
*/
public class TimeZoneConverter extends AbstractConverter{
public class TimeZoneConverter extends AbstractConverter implements MatcherConverter {
private static final long serialVersionUID = 1L;
/**
* 单例
*/
public static final TimeZoneConverter INSTANCE = new TimeZoneConverter();
@Override
public boolean match(final Type targetType, final Class<?> rawType, final Object value) {
return TimeZone.class.isAssignableFrom(rawType);
}
@Override
protected TimeZone convertInternal(final Class<?> targetClass, final Object value) {
if(value instanceof ZoneId){
@@ -37,5 +49,4 @@ public class TimeZoneConverter extends AbstractConverter{
}
return TimeZone.getTimeZone(convertToStr(value));
}
}

View File

@@ -17,8 +17,10 @@
package org.dromara.hutool.core.convert.impl;
import org.dromara.hutool.core.convert.AbstractConverter;
import org.dromara.hutool.core.convert.MatcherConverter;
import org.dromara.hutool.core.date.ZoneUtil;
import java.lang.reflect.Type;
import java.time.ZoneId;
import java.util.TimeZone;
@@ -27,9 +29,19 @@ import java.util.TimeZone;
*
* @author Looly
*/
public class ZoneIdConverter extends AbstractConverter {
public class ZoneIdConverter extends AbstractConverter implements MatcherConverter {
private static final long serialVersionUID = 1L;
/**
* 单例
*/
public static final ZoneIdConverter INSTANCE = new ZoneIdConverter();
@Override
public boolean match(final Type targetType, final Class<?> rawType, final Object value) {
return ZoneId.class.isAssignableFrom(rawType);
}
@Override
protected ZoneId convertInternal(final Class<?> targetClass, final Object value) {
if (value instanceof TimeZone) {
@@ -37,5 +49,4 @@ public class ZoneIdConverter extends AbstractConverter {
}
return ZoneId.of(convertToStr(value));
}
}

View File

@@ -80,7 +80,7 @@ public class DateTime extends Date {
/**
* 时区
*/
private TimeZone timeZone;
private transient TimeZone timeZone;
/**
* 第一周最少天数

View File

@@ -24,6 +24,7 @@ import org.dromara.hutool.core.lang.Opt;
import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
import org.dromara.hutool.core.reflect.ClassDescUtil;
import org.dromara.hutool.core.reflect.ModifierUtil;
import org.dromara.hutool.core.reflect.method.MethodInvoker;
import org.dromara.hutool.core.reflect.method.MethodUtil;
import java.io.Serializable;
@@ -171,9 +172,9 @@ public class LambdaUtil {
* @param <R> getter方法返回值类型
* @return Obj::getXxx
*/
@SuppressWarnings("unchecked")
public static <T, R> Function<T, R> buildGetter(final Class<T> clazz, final String fieldName) {
return LambdaFactory.build(Function.class, BeanUtil.getBeanDesc(clazz).getGetter(fieldName));
final MethodInvoker getter = (MethodInvoker) BeanUtil.getBeanDesc(clazz).getGetter(fieldName);
return buildGetter(getter.getMethod());
}
/**
@@ -205,9 +206,9 @@ public class LambdaUtil {
* @param <P> setter方法返回的值类型
* @return Obj::setXxx
*/
@SuppressWarnings("unchecked")
public static <T, P> BiConsumer<T, P> buildSetter(final Class<T> clazz, final String fieldName) {
return LambdaFactory.build(BiConsumer.class, BeanUtil.getBeanDesc(clazz).getSetter(fieldName));
final MethodInvoker setter = (MethodInvoker) BeanUtil.getBeanDesc(clazz).getSetter(fieldName);
return buildSetter(setter.getMethod());
}
/**

View File

@@ -163,6 +163,19 @@ public class Opt<T> {
return this.value;
}
/**
* 返回包裹里的元素,取不到则抛出异常
*
* @return 包裹里的元素
* @throws NoSuchElementException 如果元素为空,则抛出此异常
*/
public T getOrThrow() throws NoSuchElementException {
if (this.value == null) {
throw new NoSuchElementException("No value present");
}
return this.value;
}
/**
* 判断包裹里元素的值是否不存在,不存在为 {@code true},否则为{@code false}
*

View File

@@ -22,6 +22,7 @@ import org.dromara.hutool.core.exception.HutoolException;
import org.dromara.hutool.core.lang.Assert;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
/**
* 字段调用器<br>
@@ -30,7 +31,7 @@ import java.lang.reflect.Field;
* <pre>{@code
* FieldInvoker.of(Field).invoke(obj);
* }</pre>
*
* <p>
* 赋值字段值:
* <pre>{@code
* FieldInvoker.of(Field).invoke(obj, value);
@@ -60,7 +61,32 @@ public class FieldInvoker implements Invoker {
* @param field 字段
*/
public FieldInvoker(final Field field) {
this.field = Assert.notNull(field);;
this.field = Assert.notNull(field);
;
}
/**
* 获取字段
*
* @return 字段
*/
public Field getField() {
return this.field;
}
@Override
public String getName() {
return this.field.getName();
}
@Override
public Type getType() {
return field.getGenericType();
}
@Override
public Class<?> getTypeClass() {
return field.getType();
}
/**
@@ -77,10 +103,10 @@ public class FieldInvoker implements Invoker {
@SuppressWarnings("unchecked")
@Override
public <T> T invoke(final Object target, final Object... args) {
if(ArrayUtil.isEmpty(args)){
if (ArrayUtil.isEmpty(args)) {
// 默认取值
return (T) invokeGet(target);
} else if(args.length == 1){
} else if (args.length == 1) {
invokeSet(target, args[0]);
return null;
}
@@ -91,7 +117,7 @@ public class FieldInvoker implements Invoker {
/**
* 获取字段值
*
* @param obj 对象static字段则此字段为null
* @param obj 对象static字段则此字段为null
* @return 字段值
* @throws HutoolException 包装IllegalAccessException异常
*/
@@ -130,19 +156,14 @@ public class FieldInvoker implements Invoker {
}
}
@Override
public Class<?> getType() {
return field.getType();
}
/**
* 转换值类型
*
* @param value 值
* @return 转换后的值
*/
private Object convertValue(final Object value){
if(null == converter){
private Object convertValue(final Object value) {
if (null == converter) {
return value;
}

View File

@@ -16,6 +16,8 @@
package org.dromara.hutool.core.reflect;
import java.lang.reflect.Type;
/**
* Invoker接口定义了调用目标对象的方法的规范。<br>
* 它允许动态地调用方法,增强了代码的灵活性和扩展性。<br>
@@ -36,10 +38,24 @@ public interface Invoker {
<T> T invoke(Object target, Object... args);
/**
* 获取调用方法的返回类型或参数类型
* 获取调用方法的名称
*
* @return 调用方法的名称,作为字符串返回。
*/
String getName();
/**
* 获取调用方法的返回类型或参数类型或字段类型。
*
* @return 调用方法的返回类型作为Class对象返回。
*/
Class<?> getType();
Type getType();
/**
* 获取调用方法的返回类型或参数类型或字段类型。
*
* @return 调用方法的返回类型作为Class对象返回。
*/
Class<?> getTypeClass();
}

View File

@@ -20,12 +20,7 @@ import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.util.ObjUtil;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.lang.reflect.*;
import java.util.List;
import java.util.Map;
@@ -66,6 +61,8 @@ public class TypeUtil {
if (upperBounds.length == 1) {
return getClass(upperBounds[0]);
}
} else if(type instanceof GenericArrayType){
return Array.newInstance(getClass(((GenericArrayType)type).getGenericComponentType()), 0).getClass();
}
}
return null;

View File

@@ -18,12 +18,11 @@ package org.dromara.hutool.core.reflect.method;
import org.dromara.hutool.core.exception.HutoolException;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.reflect.ClassUtil;
import org.dromara.hutool.core.reflect.Invoker;
import org.dromara.hutool.core.reflect.ModifierUtil;
import org.dromara.hutool.core.reflect.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
/**
* 方法调用器,通过反射调用方法。
@@ -43,8 +42,10 @@ public class MethodInvoker implements Invoker {
}
private final Method method;
private final Class<?>[] paramTypes;
private final Class<?> type;
private final Type[] paramTypes;
private final Class<?>[] paramTypeClasses;
private final Type type;
private final Class<?> typeClass;
private boolean checkArgs;
/**
@@ -53,17 +54,53 @@ public class MethodInvoker implements Invoker {
* @param method 方法
*/
public MethodInvoker(final Method method) {
this.method = method;
this.method = ReflectUtil.setAccessible(Assert.notNull(method));
this.paramTypes = method.getParameterTypes();
this.paramTypes = TypeUtil.getParamTypes(method);
this.paramTypeClasses = method.getParameterTypes();
if (paramTypes.length == 1) {
// setter方法读取参数类型
type = paramTypes[0];
typeClass = paramTypeClasses[0];
} else {
type = method.getReturnType();
typeClass = method.getReturnType();
}
}
/**
* 获取方法
*
* @return 方法
*/
public Method getMethod() {
return this.method;
}
/**
* 获取方法参数类型
*
* @return 方法参数类型
*/
public Type[] getParamTypes() {
return this.paramTypes;
}
@Override
public String getName() {
return this.method.getName();
}
@Override
public Type getType() {
return this.type;
}
@Override
public Class<?> getTypeClass() {
return this.typeClass;
}
/**
* 设置是否检查参数<br>
* <pre>
@@ -81,19 +118,21 @@ public class MethodInvoker implements Invoker {
@SuppressWarnings("unchecked")
@Override
public <T> T invoke(Object target, final Object... args) throws HutoolException{
if(this.checkArgs){
public <T> T invoke(Object target, final Object... args) throws HutoolException {
if (this.checkArgs) {
checkArgs(args);
}
final Method method = this.method;
// static方法调用则target为null
if(ModifierUtil.isStatic(method)){
if (ModifierUtil.isStatic(method)) {
target = null;
}
// 根据方法定义的参数类型,将用户传入的参数规整和转换
final Object[] actualArgs = MethodUtil.actualArgs(method, args);
try {
// issue#3671 JDK15+ 修改了lambda的策略动态生成后在metaspace不会释放导致资源占用高
//return (T) LambdaUtil.buildGetter(method).apply(target);
return MethodHandleUtil.invokeExact(target, method, actualArgs);
} catch (final Exception e) {
// 传统反射方式执行方法
@@ -108,8 +147,8 @@ public class MethodInvoker implements Invoker {
/**
* 执行静态方法
*
* @param <T> 对象类型
* @param args 参数对象
* @param <T> 对象类型
* @param args 参数对象
* @return 结果
* @throws HutoolException 多种异常包装
*/
@@ -117,11 +156,6 @@ public class MethodInvoker implements Invoker {
return invoke(null, args);
}
@Override
public Class<?> getType() {
return this.type;
}
/**
* 检查传入参数的有效性。
*
@@ -129,12 +163,12 @@ public class MethodInvoker implements Invoker {
* @throws IllegalArgumentException 如果参数数组为空或长度为0则抛出此异常。
*/
private void checkArgs(final Object[] args) {
final Class<?>[] paramTypes = this.paramTypes;
final Class<?>[] paramTypeClasses = this.paramTypeClasses;
if (null != args) {
Assert.isTrue(args.length == paramTypes.length, "Params length [{}] is not fit for param length [{}] of method !", args.length, paramTypes.length);
Assert.isTrue(args.length == paramTypeClasses.length, "Params length [{}] is not fit for param length [{}] of method !", args.length, paramTypeClasses.length);
Class<?> type;
for (int i = 0; i < args.length; i++) {
type = paramTypes[i];
type = paramTypeClasses[i];
if (type.isPrimitive() && null == args[i]) {
// 参数是原始类型而传入参数为null时赋予默认值
args[i] = ClassUtil.getDefaultValue(type);

View File

@@ -20,6 +20,7 @@ import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.collection.set.SetUtil;
import org.dromara.hutool.core.text.StrUtil;
import java.lang.reflect.Type;
import java.util.Set;
/**
@@ -532,11 +533,11 @@ public class BooleanUtil {
/**
* 给定类是否为Boolean或者boolean
*
* @param clazz
* @param type
* @return 是否为Boolean或者boolean
* @since 4.5.2
*/
public static boolean isBoolean(final Class<?> clazz) {
return (clazz == Boolean.class || clazz == boolean.class);
public static boolean isBoolean(final Type type) {
return (type == Boolean.class || type == boolean.class);
}
}

View File

@@ -17,9 +17,12 @@
package org.dromara.hutool.core.bean;
import org.dromara.hutool.core.bean.path.AbstractBeanDesc;
import org.dromara.hutool.core.reflect.method.MethodInvoker;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Method;
/**
* {@link StrictBeanDesc} 单元测试类
*
@@ -38,8 +41,10 @@ public class BeanDescTest {
Assertions.assertEquals("age", desc.getProp("age").getFieldName());
Assertions.assertEquals("getAge", desc.getGetter("age").getName());
Assertions.assertEquals("setAge", desc.getSetter("age").getName());
Assertions.assertEquals(1, desc.getSetter("age").getParameterTypes().length);
Assertions.assertSame(int.class, desc.getSetter("age").getParameterTypes()[0]);
final MethodInvoker setter = (MethodInvoker) desc.getSetter("age");
Assertions.assertEquals(1, setter.getMethod().getParameterTypes().length);
Assertions.assertSame(int.class, setter.getMethod().getParameterTypes()[0]);
}
@@ -51,8 +56,11 @@ public class BeanDescTest {
Assertions.assertEquals("name", prop.getFieldName());
Assertions.assertEquals("getName", prop.getGetter().getName());
Assertions.assertEquals("setName", prop.getSetter().getName());
Assertions.assertEquals(1, prop.getSetter().getParameterTypes().length);
Assertions.assertSame(String.class, prop.getSetter().getParameterTypes()[0]);
final MethodInvoker setter = (MethodInvoker) desc.getSetter("name");
final Method setterMethod = setter.getMethod();
Assertions.assertEquals(1, setterMethod.getParameterTypes().length);
Assertions.assertSame(String.class, setterMethod.getParameterTypes()[0]);
}
@Test