diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/bean/StrictBeanDesc.java b/hutool-core/src/main/java/org/dromara/hutool/core/bean/StrictBeanDesc.java index f1b7b1085..caa5d7055 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/bean/StrictBeanDesc.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/bean/StrictBeanDesc.java @@ -17,6 +17,7 @@ package org.dromara.hutool.core.bean; import org.dromara.hutool.core.bean.path.AbstractBeanDesc; +import org.dromara.hutool.core.reflect.ClassUtil; import org.dromara.hutool.core.reflect.FieldUtil; import org.dromara.hutool.core.reflect.ModifierUtil; import org.dromara.hutool.core.reflect.method.MethodNameUtil; @@ -45,13 +46,37 @@ import java.util.Map; public class StrictBeanDesc extends AbstractBeanDesc { private static final long serialVersionUID = 1L; + /** + * 方法和字段匹配是否忽略大小写 + */ + private final boolean ignoreCase; + /** + * 方法和字段匹配是否匹配原始类型,即setter参数和字段包装类型和原始类型匹配
+ * 如果字段为int类型,则setter可以是:setXXX(int value)、setXXX(Integer value)
+ * 如果字段为Integer类型,则setter可以是:setXXX(Integer value)、setXXX(int value) + */ + private final boolean isMatchPrimitive; + /** * 构造 * * @param beanClass Bean类 */ public StrictBeanDesc(final Class beanClass) { + this(beanClass, true, false); + } + + /** + * 构造 + * + * @param beanClass Bean类 + * @param ignoreCase 方法和字段匹配是否忽略大小写 + * @param isMatchPrimitive 方法和字段匹配是否匹配原始类型,即setter参数和字段包装类型和原始类型匹配 + */ + public StrictBeanDesc(final Class beanClass, final boolean ignoreCase, final boolean isMatchPrimitive) { super(beanClass); + this.ignoreCase = ignoreCase; + this.isMatchPrimitive = isMatchPrimitive; init(); } @@ -94,8 +119,9 @@ public class StrictBeanDesc extends AbstractBeanDesc { */ private PropDesc createProp(final Field field, final Method[] methods) { final PropDesc prop = findProp(field, methods, false); + // 忽略大小写重新匹配一次 - if (null == prop.getter || null == prop.setter) { + if (ignoreCase && (null == prop.getter || null == prop.setter)) { final PropDesc propIgnoreCase = findProp(field, methods, true); if (null == prop.getter) { prop.getter = propIgnoreCase.getter; @@ -163,15 +189,21 @@ public class StrictBeanDesc extends AbstractBeanDesc { methodName = method.getName(); if (0 == method.getParameterCount()) { // 无参数,可能为Getter方法 - if (StrUtil.equals(methodName, MethodNameUtil.genGetter(fieldName), ignoreCase) && - method.getReturnType().isAssignableFrom(fieldType)) { - // getter的返回类型必须为字段类型或字段的父类 - getter = method; + if (StrUtil.equals(methodName, MethodNameUtil.genGetter(fieldName), ignoreCase)) { + final Class returnType = method.getReturnType(); + if(returnType.isAssignableFrom(fieldType) || + (isMatchPrimitive && ClassUtil.isBasicTypeMatch(returnType, fieldType))){ + // getter的返回类型必须为字段类型或字段的父类 + getter = method; + } + } + } else if (StrUtil.equals(methodName, MethodNameUtil.genSetter(fieldName), ignoreCase)) { + final Class parameterType = method.getParameterTypes()[0]; + if(fieldType.isAssignableFrom(parameterType) || + (isMatchPrimitive && ClassUtil.isBasicTypeMatch(fieldType, parameterType))){ + // setter方法的参数必须为字段类型或字段的子类 + setter = method; } - } else if (StrUtil.equals(methodName, MethodNameUtil.genSetter(fieldName), ignoreCase) && - fieldType.isAssignableFrom(method.getParameterTypes()[0])) { - // setter方法的参数必须为字段类型或字段的子类 - setter = method; } if (null != getter && null != setter) { // 如果Getter和Setter方法都找到了,不再继续寻找 diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/ClassUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/ClassUtil.java index 811fe79a9..c5bae6c1f 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/ClassUtil.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/ClassUtil.java @@ -402,6 +402,36 @@ public class ClassUtil { return (clazz.isPrimitive() || isPrimitiveWrapper(clazz)); } + /** + * 是否为基本类型的包装类匹配或反之,如: + *
+	 *     null    匹配 null
+	 *     int     匹配 Integer
+	 *     long    匹配 Long
+	 *     short   匹配 Short
+	 *     char    匹配 Character
+	 *     float   匹配 Float
+	 *     double  匹配 Double
+	 *     boolean 匹配 Boolean
+	 * 
+ * + * @param class1 类1 + * @param class2 类2 + * @return 是否为基本类型的包装类 + */ + public static boolean isBasicTypeMatch(final Class class1, final Class class2) { + if (class1 == class2) { + return true; + } + if (null == class1 || null == class2) { + return false; + } + if (class1.isPrimitive() && BasicType.wrap(class1) == class2) { + return true; + } + return class2.isPrimitive() && BasicType.wrap(class2) == class1; + } + /** * 是否为 简单值类型 或 简单值类型的数组
* diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/bean/PrimitiveMatchTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/bean/PrimitiveMatchTest.java new file mode 100644 index 000000000..a84970614 --- /dev/null +++ b/hutool-core/src/test/java/org/dromara/hutool/core/bean/PrimitiveMatchTest.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 Hutool Team and hutool.cn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.dromara.hutool.core.bean; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class PrimitiveMatchTest { + + @Test + void setMatchPrimitiveTest(){ + final TestUser testUser = new TestUser(); + StrictBeanDesc strictBeanDesc = new StrictBeanDesc(TestUser.class, false, true); + strictBeanDesc.getSetter("id").invoke(testUser, 12); + Assertions.assertEquals(12, testUser.getId()); + + // 不匹配原始类型 + strictBeanDesc = new StrictBeanDesc(TestUser.class, false, false); + Assertions.assertNull(strictBeanDesc.getSetter("id")); + } + + static class TestUser{ + private int id; + + public Integer getId() { + return id; + } + + public void setId(final Integer id) { + this.id = id; + } + } +}