From da7d6b9d814e19f0bb6f195161032dcb2ed25113 Mon Sep 17 00:00:00 2001 From: Looly Date: Wed, 2 Jul 2025 10:41:21 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0`MapValueProvider`=E5=92=8C`R?= =?UTF-8?q?ecordConverter`=E5=B9=B6=E6=94=AF=E6=8C=81Record=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2=EF=BC=88issue#3985@Github=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + .../copier/provider/MapValueProvider.java | 38 +++++++++++++++ .../core/convert/AbstractConverter.java | 10 ++-- .../core/convert/ConverterRegistry.java | 7 +++ .../core/convert/impl/RecordConverter.java | 48 +++++++++++++++++++ 5 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 hutool-core/src/main/java/cn/hutool/core/bean/copier/provider/MapValueProvider.java create mode 100644 hutool-core/src/main/java/cn/hutool/core/convert/impl/RecordConverter.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a0234283..42f667f30 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ### 🐣新特性 * 【captcha】 `MathGenerator`四则运算方式支持不生成负数结果(pr#1363@Gitee) +* 【core 】 增加`MapValueProvider`和`RecordConverter`并支持Record转换(issue#3985@Github) ### 🐞Bug修复 ------------------------------------------------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/copier/provider/MapValueProvider.java b/hutool-core/src/main/java/cn/hutool/core/bean/copier/provider/MapValueProvider.java new file mode 100644 index 000000000..b37fb8f81 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/bean/copier/provider/MapValueProvider.java @@ -0,0 +1,38 @@ +package cn.hutool.core.bean.copier.provider; + +import cn.hutool.core.bean.copier.ValueProvider; +import cn.hutool.core.convert.Convert; + +import java.lang.reflect.Type; +import java.util.Map; + +/** + * Map值提供者 + * + * @author Looly + * @since 5.8.40 + */ +@SuppressWarnings("rawtypes") +public class MapValueProvider implements ValueProvider { + + private final Map map; + + /** + * 构造 + * + * @param map map + */ + public MapValueProvider(final Map map) { + this.map = map; + } + + @Override + public Object value(String key, Type valueType) { + return Convert.convert(valueType, map.get(key)); + } + + @Override + public boolean containsKey(String key) { + return map.containsKey(key); + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/AbstractConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/AbstractConverter.java index 401291411..abeb0e9f4 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/AbstractConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/AbstractConverter.java @@ -12,8 +12,8 @@ import java.util.Map; * 抽象转换器,提供通用的转换逻辑,同时通过convertInternal实现对应类型的专属逻辑
* 转换器不会抛出转换异常,转换失败时会返回{@code null} * + * @param 转换的目标类型 * @author Looly - * */ public abstract class AbstractConverter implements Converter, Serializable { private static final long serialVersionUID = 1L; @@ -22,7 +22,7 @@ public abstract class AbstractConverter implements Converter, Serializable * 不抛异常转换
* 当转换失败时返回默认值 * - * @param value 被转换的值 + * @param value 被转换的值 * @param defaultValue 默认值 * @return 转换后的值 * @since 4.5.7 @@ -59,7 +59,7 @@ public abstract class AbstractConverter implements Converter, Serializable return ((null == result) ? defaultValue : result); } else { throw new IllegalArgumentException( - StrUtil.format("Default value [{}]({}) is not the instance of [{}]", defaultValue, defaultValue.getClass(), targetType)); + StrUtil.format("Default value [{}]({}) is not the instance of [{}]", defaultValue, defaultValue.getClass(), targetType)); } } @@ -98,9 +98,9 @@ public abstract class AbstractConverter implements Converter, Serializable return value.toString(); } else if (ArrayUtil.isArray(value)) { return ArrayUtil.toString(value); - } else if(CharUtil.isChar(value)) { + } else if (CharUtil.isChar(value)) { //对于ASCII字符使用缓存加速转换,减少空间创建 - return CharUtil.toString((char)value); + return CharUtil.toString((char) value); } return value.toString(); } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java b/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java index c34aa79b6..2e427e53a 100755 --- a/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java @@ -1,6 +1,7 @@ package cn.hutool.core.convert; import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.bean.RecordUtil; import cn.hutool.core.convert.impl.*; import cn.hutool.core.date.DateTime; import cn.hutool.core.lang.Opt; @@ -346,6 +347,12 @@ public class ConverterRegistry implements Serializable { return ReflectUtil.newInstanceIfPossible(rowType); } + // record + // issue#3985@Github since 5.8.40 + if(RecordUtil.isRecord(rowType)){ + return (T) new RecordConverter(rowType).convert(value, defaultValue); + } + // 表示非需要特殊转换的对象 return null; } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/RecordConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/RecordConverter.java new file mode 100644 index 000000000..8ddbb706b --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/RecordConverter.java @@ -0,0 +1,48 @@ +package cn.hutool.core.convert.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.bean.RecordUtil; +import cn.hutool.core.bean.copier.ValueProvider; +import cn.hutool.core.bean.copier.provider.BeanValueProvider; +import cn.hutool.core.bean.copier.provider.MapValueProvider; +import cn.hutool.core.convert.ConvertException; +import cn.hutool.core.convert.Converter; + +import java.util.Map; + +/** + * Record转换器 + * + * @author looly + */ +public class RecordConverter implements Converter { + + private final Class recordClass; + + /** + * 构造 + * @param recordClass Record类 + */ + public RecordConverter(Class recordClass) { + this.recordClass = recordClass; + } + + @SuppressWarnings("unchecked") + @Override + public Object convert(Object value, Object defaultValue) throws IllegalArgumentException { + ValueProvider valueProvider = null; + if (value instanceof ValueProvider) { + valueProvider = (ValueProvider) value; + } else if (value instanceof Map) { + valueProvider = new MapValueProvider((Map) value); + } else if (BeanUtil.isReadableBean(value.getClass())) { + valueProvider = new BeanValueProvider(value, false, false); + } + + if (null != valueProvider) { + return RecordUtil.newInstance(recordClass, valueProvider); + } + + throw new ConvertException("Unsupported source type: [{}] to [{}]", value.getClass(), recordClass); + } +}