mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-05 17:37:59 +08:00
add public field support
This commit is contained in:
parent
bddb97704e
commit
dc94761c43
@ -8,6 +8,7 @@
|
||||
### 新特性
|
||||
* 【core 】 新增WatchServer(issue#440@Github)
|
||||
* 【core 】 ReflectUtil.getFieldValue支持static(issue#662@Github)
|
||||
* 【core 】 改进Bean判断和注入逻辑:支持public字段注入(issue#I1689L@Gitee)
|
||||
|
||||
|
||||
### Bug修复
|
||||
|
@ -20,12 +20,14 @@ import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import cn.hutool.core.bean.copier.ValueProvider;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.lang.Console;
|
||||
import cn.hutool.core.lang.Editor;
|
||||
import cn.hutool.core.lang.Filter;
|
||||
import cn.hutool.core.map.CaseInsensitiveMap;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ClassUtil;
|
||||
import cn.hutool.core.util.ModifierUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
@ -42,15 +44,19 @@ import cn.hutool.core.util.StrUtil;
|
||||
public class BeanUtil {
|
||||
|
||||
/**
|
||||
* 判断是否为Bean对象<br>
|
||||
* 判定方法是是否存在只有一个参数的setXXX方法
|
||||
* 判断是否为Bean对象,判定方法是:
|
||||
*
|
||||
* <pre>
|
||||
* 1、是否存在只有一个参数的setXXX方法
|
||||
* 2、是否存在public类型的字段
|
||||
* </pre>
|
||||
*
|
||||
* @param clazz 待测试类
|
||||
* @return 是否为Bean对象
|
||||
* @see #hasSetter(Class)
|
||||
*/
|
||||
public static boolean isBean(Class<?> clazz) {
|
||||
return hasSetter(clazz);
|
||||
return hasSetter(clazz) || hasPublicField(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -84,8 +90,7 @@ public class BeanUtil {
|
||||
*/
|
||||
public static boolean hasGetter(Class<?> clazz) {
|
||||
if (ClassUtil.isNormalClass(clazz)) {
|
||||
final Method[] methods = clazz.getMethods();
|
||||
for (Method method : methods) {
|
||||
for (Method method : clazz.getMethods()) {
|
||||
if (method.getParameterTypes().length == 0) {
|
||||
if (method.getName().startsWith("get") || method.getName().startsWith("is")) {
|
||||
return true;
|
||||
@ -96,6 +101,25 @@ public class BeanUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定类中是否有public类型字段(static字段除外)
|
||||
*
|
||||
* @param clazz 待测试类
|
||||
* @return 是否有public类型字段
|
||||
* @since 5.1.0
|
||||
*/
|
||||
public static boolean hasPublicField(Class<?> clazz) {
|
||||
if (ClassUtil.isNormalClass(clazz)) {
|
||||
for (Field field : clazz.getFields()) {
|
||||
if (ModifierUtil.isPublic(field) && false == ModifierUtil.isStatic(field)) {
|
||||
//非static的public字段
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建动态Bean
|
||||
*
|
||||
|
@ -1,14 +1,5 @@
|
||||
package cn.hutool.core.bean.copier;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
import cn.hutool.core.bean.BeanDesc.PropDesc;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.bean.copier.provider.BeanValueProvider;
|
||||
@ -20,10 +11,22 @@ import cn.hutool.core.lang.ParameterizedTypeImpl;
|
||||
import cn.hutool.core.lang.copier.Copier;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ModifierUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.TypeUtil;
|
||||
|
||||
import java.io.Serializable;
|
||||
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.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Bean拷贝
|
||||
*
|
||||
@ -214,12 +217,14 @@ public class BeanCopier<T> implements Copier<T>, Serializable {
|
||||
final Map<String, String> fieldReverseMapping = copyOptions.getReversedMapping();
|
||||
|
||||
final Collection<PropDesc> props = BeanUtil.getBeanDesc(actualEditable).getProps();
|
||||
Field field;
|
||||
String fieldName;
|
||||
Object value;
|
||||
Method setterMethod;
|
||||
Class<?> propClass;
|
||||
for (PropDesc prop : props) {
|
||||
// 获取值
|
||||
field = prop.getField();
|
||||
fieldName = prop.getFieldName();
|
||||
if (CollUtil.contains(ignoreSet, fieldName)) {
|
||||
// 目标属性值被忽略或值提供者无此key时跳过
|
||||
@ -231,30 +236,31 @@ public class BeanCopier<T> implements Copier<T>, Serializable {
|
||||
continue;
|
||||
}
|
||||
setterMethod = prop.getSetter();
|
||||
if (null == setterMethod) {
|
||||
// Setter方法不存在跳过
|
||||
if (null == setterMethod && false == ModifierUtil.isPublic(field)) {
|
||||
// Setter方法不存在或者字段为非public跳过
|
||||
//5.1.0新增支持public字段注入支持
|
||||
continue;
|
||||
}
|
||||
|
||||
Type firstParamType = TypeUtil.getFirstParamType(setterMethod);
|
||||
if (firstParamType instanceof ParameterizedType) {
|
||||
Type valueType = (null == setterMethod) ? TypeUtil.getType(field) : TypeUtil.getFirstParamType(setterMethod);
|
||||
if (valueType instanceof ParameterizedType) {
|
||||
// 参数为泛型参数类型,解析对应泛型类型为真实类型
|
||||
ParameterizedType tmp = (ParameterizedType) firstParamType;
|
||||
ParameterizedType tmp = (ParameterizedType) valueType;
|
||||
Type[] actualTypeArguments = tmp.getActualTypeArguments();
|
||||
if (TypeUtil.hasTypeVeriable(actualTypeArguments)) {
|
||||
// 泛型对象中含有未被转换的泛型变量
|
||||
actualTypeArguments = TypeUtil.getActualTypes(this.destType, setterMethod.getDeclaringClass(), tmp.getActualTypeArguments());
|
||||
actualTypeArguments = TypeUtil.getActualTypes(this.destType, field.getDeclaringClass(), tmp.getActualTypeArguments());
|
||||
if (ArrayUtil.isNotEmpty(actualTypeArguments)) {
|
||||
// 替换泛型变量为实际类型
|
||||
firstParamType = new ParameterizedTypeImpl(actualTypeArguments, tmp.getOwnerType(), tmp.getRawType());
|
||||
valueType = new ParameterizedTypeImpl(actualTypeArguments, tmp.getOwnerType(), tmp.getRawType());
|
||||
}
|
||||
}
|
||||
} else if (firstParamType instanceof TypeVariable) {
|
||||
} else if (valueType instanceof TypeVariable) {
|
||||
// 参数为泛型,查找其真实类型(适用于泛型方法定义于泛型父类)
|
||||
firstParamType = TypeUtil.getActualType(this.destType, setterMethod.getDeclaringClass(), firstParamType);
|
||||
valueType = TypeUtil.getActualType(this.destType, field.getDeclaringClass(), valueType);
|
||||
}
|
||||
|
||||
value = valueProvider.value(providerKey, firstParamType);
|
||||
value = valueProvider.value(providerKey, valueType);
|
||||
if (null == value && copyOptions.ignoreNullValue) {
|
||||
continue;// 当允许跳过空时,跳过
|
||||
}
|
||||
@ -272,8 +278,13 @@ public class BeanCopier<T> implements Copier<T>, Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
// 执行set方法注入值
|
||||
setterMethod.invoke(bean, value);
|
||||
if(null == setterMethod){
|
||||
// 直接注入值
|
||||
ReflectUtil.setFieldValue(bean, field, value);
|
||||
} else{
|
||||
// 执行set方法注入值
|
||||
setterMethod.invoke(bean, value);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (false ==copyOptions.ignoreError) {
|
||||
throw new UtilException(e, "Inject [{}] error!", prop.getFieldName());
|
||||
|
@ -1,13 +1,13 @@
|
||||
package cn.hutool.core.bean.copier.provider;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
import cn.hutool.core.bean.copier.ValueProvider;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.map.CaseInsensitiveMap;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Map值提供者
|
||||
*
|
||||
@ -41,7 +41,7 @@ public class MapValueProvider implements ValueProvider<String> {
|
||||
//检查下划线模式
|
||||
value = map.get(StrUtil.toUnderlineCase(key));
|
||||
}
|
||||
|
||||
|
||||
return Convert.convert(valueType, value);
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,5 @@
|
||||
package cn.hutool.core.convert.impl;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.bean.copier.BeanCopier;
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
@ -12,6 +9,9 @@ import cn.hutool.core.map.MapProxy;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.core.util.TypeUtil;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Bean转换器,支持:
|
||||
* <pre>
|
||||
@ -69,7 +69,7 @@ public class BeanConverter<T> extends AbstractConverter<T> {
|
||||
// 将Map动态代理为Bean
|
||||
return MapProxy.create((Map<?, ?>)value).toProxyBean(this.beanClass);
|
||||
}
|
||||
|
||||
|
||||
//限定被转换对象类型
|
||||
return BeanCopier.create(value, ReflectUtil.newInstanceIfPossible(this.beanClass), this.beanType, this.copyOptions).copy();
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package cn.hutool.core.bean;
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import cn.hutool.core.bean.copier.ValueProvider;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Console;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@ -101,6 +100,20 @@ public class BeanUtilTest {
|
||||
Assert.assertEquals(12, person.getAge());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试public类型的字段注入是否成功
|
||||
*/
|
||||
@Test
|
||||
public void mapToBeanTest2() {
|
||||
HashMap<String, Object> map = CollUtil.newHashMap();
|
||||
map.put("name", "Joe");
|
||||
map.put("age", 12);
|
||||
|
||||
Person2 person = BeanUtil.mapToBean(map, Person2.class, CopyOptions.create());
|
||||
Assert.assertEquals("Joe", person.name);
|
||||
Assert.assertEquals(12, person.age);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanToMapTest() {
|
||||
SubPerson person = new SubPerson();
|
||||
@ -264,4 +277,10 @@ public class BeanUtilTest {
|
||||
private int age;
|
||||
private String openid;
|
||||
}
|
||||
|
||||
public static class Person2 {
|
||||
public String name;
|
||||
public int age;
|
||||
public String openid;
|
||||
}
|
||||
}
|
||||
|
@ -80,4 +80,11 @@ public class ConvertToBeanTest {
|
||||
Assert.assertEquals("测试A11", subPerson.getName());
|
||||
Assert.assertEquals("11213232", subPerson.getOpenid());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullStrToBeanTest(){
|
||||
String nullStr = "null";
|
||||
final SubPerson subPerson = Convert.convert(SubPerson.class, nullStr);
|
||||
Assert.assertNull(subPerson);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user