From 3d0e42f653a95a3f2aaf11c33128195582fd3293 Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 23 Aug 2024 19:42:34 +0800 Subject: [PATCH] fix code --- .../core/convert/CompositeConverter.java | 15 ++- .../hutool/core/convert/CustomConverter.java | 105 ------------------ .../core/convert/RegisterConverter.java | 76 ++++++++++--- .../hutool/core/convert/package-info.java | 16 ++- .../core/convert/CompositeConverterTest.java | 4 +- .../hutool/json/convert/JSONConverter.java | 27 +++-- 6 files changed, 97 insertions(+), 146 deletions(-) delete mode 100644 hutool-core/src/main/java/org/dromara/hutool/core/convert/CustomConverter.java diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/convert/CompositeConverter.java b/hutool-core/src/main/java/org/dromara/hutool/core/convert/CompositeConverter.java index 4fb56579c..f37a18ab0 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/convert/CompositeConverter.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/convert/CompositeConverter.java @@ -27,13 +27,12 @@ import java.lang.reflect.Type; import java.util.Optional; /** - * 复合转换器,融合了所有支持类型和自定义类型的转换规则 - *

- * 将各种类型Convert对象放入符合转换器,通过convert方法查找目标类型对应的转换器,将被转换对象转换之。 - *

- *

- * 在此类中,存放着默认转换器和自定义转换器,默认转换器是Hutool中预定义的一些转换器,自定义转换器存放用户自定的转换器。 - *

+ * 复合转换器,融合了所有支持类型和自定义类型的转换规则
+ * 在此类中,存放着默认转换器和自定义转换器,默认转换器是Hutool中预定义的一些转换器,自定义转换器存放用户自定的转换器。
+ * 转换过程类似于转换链,过程如下: + *
{@code
+ *     处理null、Opt、Optional --> 自定义匹配转换器 --> 自定义类型转换器 --> 预注册的标准转换器 --> Map、集合、Enum等特殊转换器 --> Bean转换器
+ * }
* * @author Looly */ @@ -143,7 +142,7 @@ public class CompositeConverter extends RegisterConverter { } // 标准转换器 - final Converter converter = getConverter(type, isCustomFirst); + final Converter converter = getConverter(type, value, isCustomFirst); if (null != converter) { return converter.convert(type, value, defaultValue); } diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/convert/CustomConverter.java b/hutool-core/src/main/java/org/dromara/hutool/core/convert/CustomConverter.java deleted file mode 100644 index 7f0bb955d..000000000 --- a/hutool-core/src/main/java/org/dromara/hutool/core/convert/CustomConverter.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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.convert; - -import org.dromara.hutool.core.collection.set.ConcurrentHashSet; -import org.dromara.hutool.core.stream.StreamUtil; - -import java.io.Serializable; -import java.lang.reflect.Type; -import java.util.Set; - -/** - * 用户自定义转换器
- * 通过自定义实现{@link MatcherConverter},可以通过{@link MatcherConverter#match(Type, Class, Object)} 检查目标类型是否匹配
- * 如果匹配,则直接转换,否则使用默认转换器转换。 - * - * @author Looly - * @since 6.0.0 - */ -public class CustomConverter implements Converter, Serializable { - private static final long serialVersionUID = 1L; - - /** - * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载 - */ - private static class SingletonHolder { - /** - * 静态初始化器,由JVM来保证线程安全 - */ - private static final CustomConverter INSTANCE = new CustomConverter(); - } - - /** - * 获得单例的 CustomConverter - * - * @return CustomConverter - */ - public static CustomConverter getInstance() { - return CustomConverter.SingletonHolder.INSTANCE; - } - - /** - * 用户自定义类型转换器 - */ - private volatile Set converterSet; - - @Override - public Object convert(final Type targetType, final Object value) throws ConvertException { - final Converter customConverter = getCustomConverter(targetType, value); - return null == customConverter ? null : customConverter.convert(targetType, value); - } - - /** - * 获得匹配类型的自定义转换器 - * - * @param type 类型 - * @param value 被转换的值 - * @return 转换器 - */ - public Converter getCustomConverter(final Type type, final Object value) { - return getConverterFromSet(this.converterSet, type, value); - } - - /** - * 登记自定义转换器 - * - * @param converter 转换器 - * @return ConverterRegistry - */ - public CustomConverter add(final MatcherConverter converter) { - if (null == this.converterSet) { - synchronized (this) { - if (null == this.converterSet) { - this.converterSet = new ConcurrentHashSet<>(); - } - } - } - this.converterSet.add(converter); - return this; - } - - /** - * 从指定集合中查找满足条件的转换器 - * - * @param type 类型 - * @return 转换器 - */ - private static Converter getConverterFromSet(final Set converterSet, final Type type, final Object value) { - return StreamUtil.of(converterSet).filter((predicate) -> predicate.match(type, value)).findFirst().orElse(null); - } -} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/convert/RegisterConverter.java b/hutool-core/src/main/java/org/dromara/hutool/core/convert/RegisterConverter.java index 4c934a3bd..96e2d2bcc 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/convert/RegisterConverter.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/convert/RegisterConverter.java @@ -16,6 +16,7 @@ package org.dromara.hutool.core.convert; +import org.dromara.hutool.core.collection.set.ConcurrentHashSet; import org.dromara.hutool.core.convert.impl.*; import org.dromara.hutool.core.lang.Opt; import org.dromara.hutool.core.lang.tuple.Pair; @@ -23,6 +24,7 @@ import org.dromara.hutool.core.lang.tuple.Triple; import org.dromara.hutool.core.lang.tuple.Tuple; import org.dromara.hutool.core.map.concurrent.SafeConcurrentHashMap; import org.dromara.hutool.core.reflect.TypeUtil; +import org.dromara.hutool.core.stream.StreamUtil; import javax.xml.datatype.XMLGregorianCalendar; import java.io.Serializable; @@ -42,10 +44,12 @@ import java.util.concurrent.atomic.AtomicLongArray; import java.util.concurrent.atomic.AtomicReference; /** - * 基于类型注册的转换器
- * 即转换的目标类型和转换器一一对应,转换器只针对目标类型,不针对源类型
- * 转换器默认提供一些固定的类型转换,用户可调用{@link #putCustom(Type, Converter)} 注册自定义转换规则
- * 注意:注册的转换器要求目标类型必须一致,不能是子类等 + * 基于类型注册的转换器,提供两种注册方式,按照优先级依次为: + *
    + *
  1. 按照匹配注册,使用{@link #register(MatcherConverter)}。 + * 注册后一旦给定的目标类型和值满足{@link MatcherConverter#match(Type, Class, Object)},即可调用对应转换器转换。
  2. + *
  3. 按照类型注册,使用{@link #register(Type, Converter)},目标类型一致,即可调用转换。
  4. + *
* * @author looly * @since 6.0.0 @@ -72,14 +76,19 @@ public class RegisterConverter implements Converter, Serializable { return RegisterConverter.SingletonHolder.INSTANCE; } + /** + * 用户自定义类型转换器,存储自定义匹配规则的一类对象的转换器 + */ + private volatile Set converterSet; + /** + * 用户自定义精确类型转换器
+ * 主要存储类型明确(无子类)的转换器 + */ + private volatile Map customConverterMap; /** * 默认类型转换器 */ private Map, Converter> defaultConverterMap; - /** - * 用户自定义类型转换器 - */ - private volatile Map customConverterMap; /** * 构造 @@ -91,7 +100,7 @@ public class RegisterConverter implements Converter, Serializable { @Override public Object convert(final Type targetType, final Object value) throws ConvertException { // 标准转换器 - final Converter converter = getConverter(targetType, true); + final Converter converter = getConverter(targetType, value, true); if (null != converter) { return converter.convert(targetType, value); } @@ -104,19 +113,26 @@ public class RegisterConverter implements Converter, Serializable { * 获得转换器
* * @param type 类型 + * @param value 转换的值 * @param isCustomFirst 是否自定义转换器优先 * @return 转换器 */ - public Converter getConverter(final Type type, final boolean isCustomFirst) { + public Converter getConverter(final Type type, final Object value, final boolean isCustomFirst) { Converter converter; if (isCustomFirst) { - converter = this.getCustomConverter(type); + converter = this.getCustomConverter(type, value); + if(null == converter){ + converter = this.getCustomConverter(type); + } if (null == converter) { converter = this.getDefaultConverter(type); } } else { converter = this.getDefaultConverter(type); if (null == converter) { + converter = this.getCustomConverter(type, value); + } + if(null == converter){ converter = this.getCustomConverter(type); } } @@ -135,7 +151,21 @@ public class RegisterConverter implements Converter, Serializable { } /** - * 获得自定义转换器 + * 获得匹配类型的自定义转换器 + * + * @param type 类型 + * @param value 被转换的值 + * @return 转换器 + */ + public Converter getCustomConverter(final Type type, final Object value) { + return StreamUtil.of(converterSet) + .filter((predicate) -> predicate.match(type, value)) + .findFirst() + .orElse(null); + } + + /** + * 获得指定类型对应的自定义转换器 * * @param type 类型 * @return 转换器 @@ -145,13 +175,13 @@ public class RegisterConverter implements Converter, Serializable { } /** - * 登记自定义转换器 + * 登记自定义转换器,登记的目标类型必须一致 * * @param type 转换的目标类型 * @param converter 转换器 * @return ConverterRegistry */ - public RegisterConverter putCustom(final Type type, final Converter converter) { + public RegisterConverter register(final Type type, final Converter converter) { if (null == customConverterMap) { synchronized (this) { if (null == customConverterMap) { @@ -163,6 +193,24 @@ public class RegisterConverter implements Converter, Serializable { return this; } + /** + * 登记自定义转换器,符合{@link MatcherConverter#match(Type, Class, Object)}则使用其转换器 + * + * @param converter 转换器 + * @return ConverterRegistry + */ + public RegisterConverter register(final MatcherConverter converter) { + if (null == this.converterSet) { + synchronized (this) { + if (null == this.converterSet) { + this.converterSet = new ConcurrentHashSet<>(); + } + } + } + this.converterSet.add(converter); + return this; + } + /** * 注册默认转换器 */ diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/convert/package-info.java b/hutool-core/src/main/java/org/dromara/hutool/core/convert/package-info.java index abd236088..20c778060 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/convert/package-info.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/convert/package-info.java @@ -15,12 +15,18 @@ */ /** - * 万能类型转换器以及各种类型转换的实现类,其中Convert为转换器入口,提供各种toXXX方法和convert方法 + * 万能类型转换器以及各种类型转换的实现类,其中Convert为转换器入口,提供各种toXXX方法和convert方法
+ * 转换器是典型的策略模式应用,可自定义转换策略。Hutool提供了常用类型的转换策略,自定义转换接口包括: + *
    + *
  • {@link org.dromara.hutool.core.convert.Converter},标准转换接口,通过类型匹配策略后调用使用。
  • + *
  • {@link org.dromara.hutool.core.convert.MatcherConverter},带有match方法的Converter,通过自身匹配判断调用转换。
  • + *
* - *

- * 转换器是典型的策略模式应用,通过实现{@link org.dromara.hutool.core.convert.Converter} 接口, - * 自定义转换策略。Hutool提供了常用类型的转换策略。 - *

+ * 公共的转换器封装有两种: + *
    + *
  • {@link org.dromara.hutool.core.convert.RegisterConverter},提供预定义的转换规则,也可以注册自定义转换规则。
  • + *
  • {@link org.dromara.hutool.core.convert.CompositeConverter},复合转换器,封装基于注册的、特别转换(泛型转换)等规则,实现万能转换。
  • + *
* * @author looly * diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/convert/CompositeConverterTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/convert/CompositeConverterTest.java index 6dd53a737..ff42d0f16 100644 --- a/hutool-core/src/test/java/org/dromara/hutool/core/convert/CompositeConverterTest.java +++ b/hutool-core/src/test/java/org/dromara/hutool/core/convert/CompositeConverterTest.java @@ -38,7 +38,7 @@ public class CompositeConverterTest { @Test public void getConverterTest() { - final Converter converter = CompositeConverter.getInstance().getConverter(CharSequence.class, false); + final Converter converter = CompositeConverter.getInstance().getConverter(CharSequence.class, null, false); assertNotNull(converter); } @@ -52,7 +52,7 @@ public class CompositeConverterTest { //此处做为示例自定义CharSequence转换,因为Hutool中已经提供CharSequence转换,请尽量不要替换 //替换可能引发关联转换异常(例如覆盖CharSequence转换会影响全局) - compositeConverter.putCustom(CharSequence.class, new CustomConverter()); + compositeConverter.register(CharSequence.class, new CustomConverter()); result = (CharSequence) compositeConverter.convert(CharSequence.class, a); assertEquals("Custom: 454553", result); } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONConverter.java b/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONConverter.java index 20a46b4be..7456b2074 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONConverter.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONConverter.java @@ -45,7 +45,7 @@ import java.util.Optional; * JSON转换器,实现Object对象转换为{@link JSON},支持的对象: *
    *
  • 任意支持的对象,转换为JSON
  • - *
  • JSOn转换为指定对象Bean
  • + *
  • JSON转换为指定对象Bean
  • *
* * @author looly @@ -61,8 +61,8 @@ public class JSONConverter implements Converter, Serializable { static { final RegisterConverter converter = RegisterConverter.getInstance(); - converter.putCustom(JSONObject.class, INSTANCE); - converter.putCustom(JSONArray.class, INSTANCE); + converter.register(JSONObject.class, INSTANCE); + converter.register(JSONArray.class, INSTANCE); } /** @@ -188,7 +188,7 @@ public class JSONConverter implements Converter, Serializable { // RFC8259,JSON字符串值、number, boolean, or null final JSONParser jsonParser = JSONParser.of(new JSONTokener(jsonStr), config); final Object value = jsonParser.nextValue(); - if(jsonParser.getTokener().nextClean() != JSONTokener.EOF){ + if (jsonParser.getTokener().nextClean() != JSONTokener.EOF) { // 对于用户提供的未转义字符串导致解析未结束,报错 throw new JSONException("JSON format error: {}", jsonStr); } @@ -197,7 +197,7 @@ public class JSONConverter implements Converter, Serializable { case '\'': return InternalJSONUtil.quote((CharSequence) value); default: - if(ObjUtil.equals(jsonStr, value)){ + if (ObjUtil.equals(jsonStr, value)) { // 对于直接的字符串,如abc,按照字符串处理 return InternalJSONUtil.quote((CharSequence) value); } @@ -208,7 +208,10 @@ public class JSONConverter implements Converter, Serializable { // ----------------------------------------------------------- Private method start /** - * JSON转Bean + * JSON转Bean,流程为: + *
{@code
+	 *     自定义反序列化 --> 尝试转Kotlin --> 基于注册的标准转换器 --> Collection、Map等含有泛型的特殊转换器 --> 普通Bean转换器
+	 * }
* * @param 目标类型 * @param targetType 目标类型, @@ -236,18 +239,18 @@ public class JSONConverter implements Converter, Serializable { return KClassUtil.newInstance(rawType, new JSONGetterValueProvider<>((JSONGetter) json)); } + // 标准转换器 + final Converter converter = RegisterConverter.getInstance().getConverter(targetType, json, true); + if (null != converter) { + return (T) converter.convert(targetType, json); + } + // 特殊类型转换,包括Collection、Map、强转、Array等 final T result = (T) SpecialConverter.getInstance().convert(targetType, rawType, json); if (null != result) { return result; } - // 标准转换器 - final Converter converter = RegisterConverter.getInstance().getConverter(targetType, true); - if (null != converter) { - return (T) converter.convert(targetType, json); - } - // 尝试转Bean if (BeanUtil.isWritableBean(rawType)) { return BeanCopier.of(json,