From 264d24b54ca7fb3e14cb2e244b33c8aece27b4f5 Mon Sep 17 00:00:00 2001 From: Looly Date: Tue, 10 Sep 2024 12:13:47 +0800 Subject: [PATCH] add FieldInvoker --- .../hutool/core/reflect/FieldInvoker.java | 166 ++++++++++++++++++ .../hutool/core/reflect/FieldUtil.java | 41 ++--- 2 files changed, 177 insertions(+), 30 deletions(-) create mode 100644 hutool-core/src/main/java/org/dromara/hutool/core/reflect/FieldInvoker.java diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/FieldInvoker.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/FieldInvoker.java new file mode 100644 index 000000000..1dc054308 --- /dev/null +++ b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/FieldInvoker.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2024 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.reflect; + +import org.dromara.hutool.core.array.ArrayUtil; +import org.dromara.hutool.core.convert.Converter; +import org.dromara.hutool.core.exception.HutoolException; +import org.dromara.hutool.core.lang.Assert; + +import java.lang.reflect.Field; + +/** + * 字段调用器
+ * 通过反射读取或赋值字段
+ * 读取字段值: + *
{@code
+ *   FieldInvoker.of(Field).invoke(obj);
+ * }
+ * + * 赋值字段值: + *
{@code
+ *   FieldInvoker.of(Field).invoke(obj, value);
+ * }
+ * + * @author looly + * @since 6.0.0 + */ +public class FieldInvoker implements Invoker { + + /** + * 创建字段调用器 + * + * @param field 字段 + * @return {@code FieldInvoker} + */ + public static FieldInvoker of(final Field field) { + return new FieldInvoker(field); + } + + private final Field field; + private Converter converter; + + /** + * 构造 + * + * @param field 字段 + */ + public FieldInvoker(final Field field) { + this.field = Assert.notNull(field);; + } + + /** + * 设置字段值转换器 + * + * @param converter 转换器,{@code null}表示不转换 + * @return this + */ + public FieldInvoker setConverter(final Converter converter) { + this.converter = converter; + return this; + } + + @SuppressWarnings("unchecked") + @Override + public T invoke(final Object target, final Object... args) { + if(ArrayUtil.isEmpty(args)){ + // 默认取值 + return (T) invokeGet(target); + } else if(args.length == 1){ + invokeSet(target, args[0]); + return null; + } + + throw new HutoolException("Field [{}] cannot be set with [{}] args", field.getName(), args.length); + } + + /** + * 获取字段值 + * + * @param obj 对象,static字段则此字段为null + * @return 字段值 + * @throws HutoolException 包装IllegalAccessException异常 + */ + public Object invokeGet(Object obj) throws HutoolException { + if (null == field) { + return null; + } + if (obj instanceof Class) { + // 静态字段获取时对象为null + obj = null; + } + + ReflectUtil.setAccessible(field); + final Object result; + try { + result = field.get(obj); + } catch (final IllegalAccessException e) { + throw new HutoolException(e, "IllegalAccess for {}.{}", field.getDeclaringClass(), field.getName()); + } + return result; + } + + /** + * 设置字段值,传入的字段值必须和字段类型一致,否则抛出异常 + * + * @param obj 对象,如果是static字段,此参数为null + * @param value 值,值类型必须与字段类型匹配 + * @throws HutoolException UtilException 包装IllegalAccessException异常 + */ + public void invokeSet(final Object obj, final Object value) throws HutoolException { + ReflectUtil.setAccessible(field); + try { + field.set(obj instanceof Class ? null : obj, convertValue(value)); + } catch (final IllegalAccessException e) { + throw new HutoolException(e, "IllegalAccess for [{}.{}]", null == obj ? field.getDeclaringClass() : obj, field.getName()); + } + } + + @Override + public Class getType() { + return field.getType(); + } + + /** + * 转换值类型 + * + * @param value 值 + * @return 转换后的值 + */ + private Object convertValue(final Object value){ + if(null == converter){ + return value; + } + + // 值类型检查和转换 + final Class fieldType = field.getType(); + if (null != value) { + if (!fieldType.isAssignableFrom(value.getClass())) { + //对于类型不同的字段,尝试转换,转换失败则使用原对象类型 + final Object targetValue = converter.convert(fieldType, value); + if (null != targetValue) { + return targetValue; + } + } + } else { + // 获取null对应默认值,防止原始类型造成空指针问题 + return ClassUtil.getDefaultValue(fieldType); + } + + return value; + } +} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/FieldUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/FieldUtil.java index 9d1f55289..b35be8656 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/FieldUtil.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/FieldUtil.java @@ -18,7 +18,8 @@ package org.dromara.hutool.core.reflect; import org.dromara.hutool.core.annotation.Alias; import org.dromara.hutool.core.array.ArrayUtil; -import org.dromara.hutool.core.convert.ConvertUtil; +import org.dromara.hutool.core.convert.CompositeConverter; +import org.dromara.hutool.core.convert.Converter; import org.dromara.hutool.core.exception.HutoolException; import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.map.MapUtil; @@ -333,43 +334,23 @@ public class FieldUtil { * @param value 值,类型不匹配会自动转换对象类型 * @throws HutoolException UtilException 包装IllegalAccessException异常 */ - public static void setFieldValue(final Object obj, final Field field, Object value) throws HutoolException { - Assert.notNull(field, "Field in [{}] not exist !", obj); - - // 值类型检查和转换 - final Class fieldType = field.getType(); - if (null != value) { - if (!fieldType.isAssignableFrom(value.getClass())) { - //对于类型不同的字段,尝试转换,转换失败则使用原对象类型 - final Object targetValue = ConvertUtil.convert(fieldType, value); - if (null != targetValue) { - value = targetValue; - } - } - } else { - // 获取null对应默认值,防止原始类型造成空指针问题 - value = ClassUtil.getDefaultValue(fieldType); - } - - setFieldValueExact(obj, field, value); + public static void setFieldValue(final Object obj, final Field field, final Object value) throws HutoolException { + setFieldValue(obj, field, value, CompositeConverter.getInstance()); } /** - * 设置字段值,传入的字段值必须和字段类型一致,否则抛出异常 + * 设置字段值,如果值类型必须与字段类型匹配,会自动转换对象类型 * * @param obj 对象,如果是static字段,此参数为null * @param field 字段 - * @param value 值,值类型必须与字段类型匹配 + * @param value 值,类型不匹配会自动转换对象类型 + * @param converter 转换器,用于转换给定value为字段类型,{@code null}表示不转换 * @throws HutoolException UtilException 包装IllegalAccessException异常 */ - public static void setFieldValueExact(final Object obj, final Field field, final Object value) throws HutoolException { - ReflectUtil.setAccessible(field); - try { - field.set(obj instanceof Class ? null : obj, value); - } catch (final IllegalAccessException e) { - throw new HutoolException(e, "IllegalAccess for [{}.{}]", null == obj ? field.getDeclaringClass() : obj, field.getName()); - } - } + public static void setFieldValue(final Object obj, final Field field, final Object value, final Converter converter) throws HutoolException { + Assert.notNull(field, "Field in [{}] not exist !", obj); + FieldInvoker.of(field).setConverter(converter).invokeSet(obj, value); + } // endregion }