diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/bean/BeanDescFactory.java b/hutool-core/src/main/java/org/dromara/hutool/core/bean/BeanDescFactory.java
index ec0a7992f..7cbdb96d5 100644
--- a/hutool-core/src/main/java/org/dromara/hutool/core/bean/BeanDescFactory.java
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/bean/BeanDescFactory.java
@@ -52,7 +52,7 @@ public class BeanDescFactory {
public static BeanDesc getBeanDescWithoutCache(final Class> clazz) {
if (RecordUtil.isRecord(clazz)) {
return new RecordBeanDesc(clazz);
- }else if(Proxy.isProxyClass(clazz) || ArrayUtil.isEmpty(FieldUtil.getFields(clazz))){
+ } else if (isProxyClass(clazz) || ArrayUtil.isEmpty(FieldUtil.getFields(clazz))) {
// 代理类和空字段的Bean不支持属性获取,直接使用方法方式
return new SimpleBeanDesc(clazz);
} else {
@@ -68,4 +68,11 @@ public class BeanDescFactory {
public static void clearCache() {
bdCache.clear();
}
+
+ private static boolean isProxyClass(final Class> clazz) {
+ // JDK代理类
+ return Proxy.isProxyClass(clazz) ||
+ // cglib代理类
+ clazz.getName().contains("$$");
+ }
}
diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/bean/SimpleBeanDesc.java b/hutool-core/src/main/java/org/dromara/hutool/core/bean/SimpleBeanDesc.java
index 92093e4bd..7eee77284 100644
--- a/hutool-core/src/main/java/org/dromara/hutool/core/bean/SimpleBeanDesc.java
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/bean/SimpleBeanDesc.java
@@ -15,12 +15,18 @@ package org.dromara.hutool.core.bean;
import org.dromara.hutool.core.bean.path.AbstractBeanDesc;
import org.dromara.hutool.core.reflect.method.MethodNameUtil;
import org.dromara.hutool.core.reflect.method.MethodUtil;
+import org.dromara.hutool.core.util.BooleanUtil;
import java.lang.reflect.Method;
import java.util.Map;
/**
- * 简单的Bean描述,只查找getter和setter方法
+ * 简单的Bean描述,只查找getter和setter方法,规则如下:
+ *
+ * - 不匹配字段,只查找getXXX、isXXX、setXXX方法。
+ * - 如果同时存在getXXX和isXXX,返回值为Boolean或boolean,isXXX优先。
+ * - 如果同时存在setXXX的多个重载方法,最小子类优先,如setXXX(List)优先于setXXX(Collection)
+ *
*
* @author Looly
* @since 6.0.0
@@ -75,9 +81,19 @@ public class SimpleBeanDesc extends AbstractBeanDesc {
propMap.put(fieldName, propDesc);
} else{
if(isSetter){
- propDesc.setter = method;
+ if(null == propDesc.setter ||
+ propDesc.setter.getParameterTypes()[0].isAssignableFrom(method.getParameterTypes()[0])){
+ // 如果存在多个重载的setter方法,选择参数类型最匹配的
+ propDesc.setter = method;
+ }
}else{
- propDesc.getter = method;
+ if(null == propDesc.getter ||
+ (BooleanUtil.isBoolean(propDesc.getter.getReturnType()) &&
+ BooleanUtil.isBoolean(method.getReturnType()) &&
+ methodName.startsWith(MethodNameUtil.IS_PREFIX))){
+ // 如果返回值为Boolean或boolean,isXXX优先于getXXX
+ propDesc.getter = method;
+ }
}
}
}
diff --git a/hutool-extra/src/test/java/org/dromara/hutool/extra/aop/ProxyBeanTest.java b/hutool-extra/src/test/java/org/dromara/hutool/extra/aop/ProxyBeanTest.java
new file mode 100644
index 000000000..e9f2ece25
--- /dev/null
+++ b/hutool-extra/src/test/java/org/dromara/hutool/extra/aop/ProxyBeanTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.extra.aop;
+
+import org.dromara.hutool.core.bean.BeanUtil;
+import org.dromara.hutool.core.exception.HutoolException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Map;
+
+public class ProxyBeanTest {
+
+ @Test
+ void proxyTest() {
+ final IBean bean = ProxyUtil.newProxyInstance((proxy, method, args) -> {
+ final String name = method.getName();
+ switch (name){
+ case "getName":
+ return "hutool";
+ case "setName":
+ case "setAge":
+ return null;
+ case "getAge":
+ return 1;
+ }
+ throw new HutoolException("No method name: " + name);
+ }, IBean.class);
+
+ // 测试代理类的Bean拷贝
+ final Map map = BeanUtil.beanToMap(bean);
+ Assertions.assertEquals(2, map.size());
+ Assertions.assertEquals("hutool", map.get("name"));
+ Assertions.assertEquals(1, map.get("age"));
+ }
+
+ interface IBean{
+ String getName();
+ IBean setName(String name);
+
+ int getAge();
+ IBean setAge(int age);
+ }
+}