From c6777244a08e1540294934733f83a0f89611a11c Mon Sep 17 00:00:00 2001 From: Looly Date: Thu, 22 Aug 2024 22:29:34 +0800 Subject: [PATCH] fix code --- .../{ => set}/ConcurrentHashSet.java | 3 +- .../set/ConcurrentLinkedHashSet.java | 83 ++++++++++++++ .../core/convert/CompositeConverter.java | 43 ++++---- .../hutool/core/convert/CustomConverter.java | 104 ++++++++++++++++++ .../core/convert/PredicateConverter.java | 31 ++++++ .../core/convert/RegisterConverter.java | 9 +- .../core/io/watch/watchers/DelayWatcher.java | 2 +- .../hutool/core/stream/EntryStream.java | 2 +- .../hutool/core/data/id/SnowflakeTest.java | 2 +- .../dromara/hutool/core/data/id/UUIDTest.java | 3 +- .../dromara/hutool/core/util/IdUtilTest.java | 2 +- .../java/org/dromara/hutool/json/JSON.java | 3 +- .../hutool/json/convert/JSONConverter.java | 5 +- 13 files changed, 257 insertions(+), 35 deletions(-) rename hutool-core/src/main/java/org/dromara/hutool/core/collection/{ => set}/ConcurrentHashSet.java (96%) create mode 100644 hutool-core/src/main/java/org/dromara/hutool/core/collection/set/ConcurrentLinkedHashSet.java create mode 100644 hutool-core/src/main/java/org/dromara/hutool/core/convert/CustomConverter.java create mode 100644 hutool-core/src/main/java/org/dromara/hutool/core/convert/PredicateConverter.java diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/collection/ConcurrentHashSet.java b/hutool-core/src/main/java/org/dromara/hutool/core/collection/set/ConcurrentHashSet.java similarity index 96% rename from hutool-core/src/main/java/org/dromara/hutool/core/collection/ConcurrentHashSet.java rename to hutool-core/src/main/java/org/dromara/hutool/core/collection/set/ConcurrentHashSet.java index d0ca67e44..a9af99647 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/collection/ConcurrentHashSet.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/collection/set/ConcurrentHashSet.java @@ -14,9 +14,8 @@ * limitations under the License. */ -package org.dromara.hutool.core.collection; +package org.dromara.hutool.core.collection.set; -import org.dromara.hutool.core.collection.set.SetFromMap; import org.dromara.hutool.core.map.concurrent.SafeConcurrentHashMap; import java.util.Collection; diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/collection/set/ConcurrentLinkedHashSet.java b/hutool-core/src/main/java/org/dromara/hutool/core/collection/set/ConcurrentLinkedHashSet.java new file mode 100644 index 000000000..748f08d3a --- /dev/null +++ b/hutool-core/src/main/java/org/dromara/hutool/core/collection/set/ConcurrentLinkedHashSet.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2013-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.collection.set; + +import org.dromara.hutool.core.map.concurrent.ConcurrentLinkedHashMap; + +import java.util.Collection; + +/** + * 通过{@link ConcurrentLinkedHashMap}实现的线程安全HashSet + * + * @param 元素类型 + * @author Looly + * @since 3.1.0 + */ +public class ConcurrentLinkedHashSet extends SetFromMap { + private static final long serialVersionUID = 7997886765361607470L; + + // ----------------------------------------------------------------------------------- Constructor start + + /** + * 构造 + */ + public ConcurrentLinkedHashSet() { + super(new ConcurrentLinkedHashMap.Builder().build()); + } + + /** + * 构造
+ * 触发因子为默认的0.75 + * + * @param initialCapacity 初始大小 + */ + public ConcurrentLinkedHashSet(final int initialCapacity) { + super(new ConcurrentLinkedHashMap.Builder().initialCapacity(initialCapacity).build()); + } + + /** + * 构造 + * + * @param initialCapacity 初始大小 + * @param concurrencyLevel 线程并发度 + */ + public ConcurrentLinkedHashSet(final int initialCapacity, final int concurrencyLevel) { + super(new ConcurrentLinkedHashMap.Builder() + .initialCapacity(initialCapacity) + .concurrencyLevel(concurrencyLevel) + .build()); + } + + /** + * 从已有集合中构造 + * + * @param iter {@link Iterable} + */ + public ConcurrentLinkedHashSet(final Iterable iter) { + super(iter instanceof Collection ? + new ConcurrentLinkedHashMap.Builder().initialCapacity(((Collection) iter).size()).build() : + new ConcurrentLinkedHashMap.Builder().build()); + if (iter instanceof Collection) { + this.addAll((Collection) iter); + } else { + for (final E e : iter) { + this.add(e); + } + } + } + // ----------------------------------------------------------------------------------- Constructor end +} 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 704e0a3a3..b256f4746 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 @@ -154,23 +154,23 @@ public class CompositeConverter extends RegisterConverter { return converter.convert(type, value, defaultValue); } - Class rowType = (Class) TypeUtil.getClass(type); - if (null == rowType) { + Class rawType = (Class) TypeUtil.getClass(type); + if (null == rawType) { if (null != defaultValue) { - rowType = (Class) defaultValue.getClass(); + rawType = (Class) defaultValue.getClass(); } else { throw new ConvertException("Can not get class from type: {}", type); } } // 特殊类型转换,包括Collection、Map、强转、Array等 - final T result = convertSpecial(type, rowType, value, defaultValue); + final T result = convertSpecial(type, rawType, value, defaultValue); if (null != result) { return result; } // 尝试转Bean - if (BeanUtil.isWritableBean(rowType)) { + if (BeanUtil.isWritableBean(rawType)) { return (T) BeanConverter.INSTANCE.convert(type, value); } @@ -193,80 +193,81 @@ public class CompositeConverter extends RegisterConverter { * * @param 转换的目标类型(转换器转换到的类型) * @param type 类型 + * @param rawType 原始类型 * @param value 值 * @param defaultValue 默认值 * @return 转换后的值 */ @SuppressWarnings("unchecked") - private T convertSpecial(final Type type, final Class rowType, final Object value, final T defaultValue) { - if (null == rowType) { + private T convertSpecial(final Type type, final Class rawType, final Object value, final T defaultValue) { + if (null == rawType) { return null; } // 日期、java.sql中的日期以及自定义日期统一处理 - if (Date.class.isAssignableFrom(rowType)) { + if (Date.class.isAssignableFrom(rawType)) { return DateConverter.INSTANCE.convert(type, value, defaultValue); } // 集合转换(含有泛型参数,不可以默认强转) - if (Collection.class.isAssignableFrom(rowType)) { + if (Collection.class.isAssignableFrom(rawType)) { return (T) CollectionConverter.INSTANCE.convert(type, value, (Collection) defaultValue); } // Map类型(含有泛型参数,不可以默认强转) - if (Map.class.isAssignableFrom(rowType)) { + if (Map.class.isAssignableFrom(rawType)) { return (T) MapConverter.INSTANCE.convert(type, value, (Map) defaultValue); } // issue#I6SZYB Entry类(含有泛型参数,不可以默认强转) - if (Map.Entry.class.isAssignableFrom(rowType)) { + if (Map.Entry.class.isAssignableFrom(rawType)) { return (T) EntryConverter.INSTANCE.convert(type, value); } // 默认强转 - if (rowType.isInstance(value)) { + if (rawType.isInstance(value)) { return (T) value; } // 原始类型转换 - if (rowType.isPrimitive()) { + if (rawType.isPrimitive()) { return PrimitiveConverter.INSTANCE.convert(type, value, defaultValue); } // 数字类型转换 - if (Number.class.isAssignableFrom(rowType)) { + if (Number.class.isAssignableFrom(rawType)) { return NumberConverter.INSTANCE.convert(type, value, defaultValue); } // 枚举转换 - if (rowType.isEnum()) { + if (rawType.isEnum()) { return EnumConverter.INSTANCE.convert(type, value, defaultValue); } // 数组转换 - if (rowType.isArray()) { + if (rawType.isArray()) { return ArrayConverter.INSTANCE.convert(type, value, defaultValue); } // Record - if (RecordUtil.isRecord(rowType)) { + if (RecordUtil.isRecord(rawType)) { return (T) RecordConverter.INSTANCE.convert(type, value); } // Kotlin Bean - if (KClassUtil.isKotlinClass(rowType)) { + if (KClassUtil.isKotlinClass(rawType)) { return (T) KBeanConverter.INSTANCE.convert(type, value); } // issue#I7FQ29 Class - if ("java.lang.Class".equals(rowType.getName())) { + if ("java.lang.Class".equals(rawType.getName())) { return (T) ClassConverter.INSTANCE.convert(type, value); } // 空值转空Bean - if(ObjUtil.isEmpty(value)){ + if (ObjUtil.isEmpty(value)) { // issue#3649 空值转空对象,则直接实例化 - return ConstructorUtil.newInstanceIfPossible(rowType); + return ConstructorUtil.newInstanceIfPossible(rawType); } // 表示非需要特殊转换的对象 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 new file mode 100644 index 000000000..66cd7a52b --- /dev/null +++ b/hutool-core/src/main/java/org/dromara/hutool/core/convert/CustomConverter.java @@ -0,0 +1,104 @@ +/* + * 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 PredicateConverter},可以通过{@link PredicateConverter#test(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 RegisterConverter INSTANCE = new RegisterConverter(); + } + + /** + * 获得单例的 RegisterConverter + * + * @return RegisterConverter + */ + public static RegisterConverter 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); + return null == customConverter ? null : customConverter.convert(targetType, value); + } + + /** + * 获得匹配类型的自定义转换器 + * + * @param type 类型 + * @return 转换器 + */ + public Converter getCustomConverter(final Type type) { + return getConverterFromSet(this.converterSet, type); + } + + /** + * 登记自定义转换器 + * + * @param converter 转换器 + * @return ConverterRegistry + */ + public CustomConverter add(final PredicateConverter 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) { + return StreamUtil.of(converterSet).filter((predicate) -> predicate.test(type)).findFirst().orElse(null); + } +} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/convert/PredicateConverter.java b/hutool-core/src/main/java/org/dromara/hutool/core/convert/PredicateConverter.java new file mode 100644 index 000000000..e9705e10e --- /dev/null +++ b/hutool-core/src/main/java/org/dromara/hutool/core/convert/PredicateConverter.java @@ -0,0 +1,31 @@ +/* + * 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 java.lang.reflect.Type; +import java.util.function.Predicate; + +/** + * 断言转换器
+ * 判断目标对象是否满足断言,满足则转换,否则跳过
+ * 实现此接口同样可以不判断断言而直接转换 + * + * @author Looly + * @since 6.0.0 + */ +public interface PredicateConverter extends Converter, Predicate { +} 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 fadcc5495..84bdec46d 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 @@ -42,7 +42,10 @@ import java.util.concurrent.atomic.AtomicLongArray; import java.util.concurrent.atomic.AtomicReference; /** - * 基于类型注册的转换器,转换器默认提供一些固定的类型转换,用户可调用{@link #putCustom(Type, Converter)} 注册自定义转换规则 + * 基于类型注册的转换器
+ * 即转换的目标类型和转换器一一对应,转换器只针对目标类型,不针对源类型
+ * 转换器默认提供一些固定的类型转换,用户可调用{@link #putCustom(Type, Converter)} 注册自定义转换规则
+ * 注意:注册的转换器要求目标类型必须一致,不能是子类等 * * @author looly * @since 6.0.0 @@ -164,7 +167,7 @@ public class RegisterConverter implements Converter, Serializable { * 注册默认转换器 */ private void registerDefault() { - defaultConverterMap = new SafeConcurrentHashMap<>(64); + final Map, Converter> defaultConverterMap = new SafeConcurrentHashMap<>(64); // 包装类转换器 defaultConverterMap.put(Character.class, new CharacterConverter()); @@ -220,5 +223,7 @@ public class RegisterConverter implements Converter, Serializable { defaultConverterMap.put(Pair.class, PairConverter.INSTANCE);// since 6.0.0 defaultConverterMap.put(Triple.class, TripleConverter.INSTANCE);// since 6.0.0 defaultConverterMap.put(Tuple.class, TupleConverter.INSTANCE);// since 6.0.0 + + this.defaultConverterMap = defaultConverterMap; } } diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/io/watch/watchers/DelayWatcher.java b/hutool-core/src/main/java/org/dromara/hutool/core/io/watch/watchers/DelayWatcher.java index fe3c9e3b6..0443c65d9 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/io/watch/watchers/DelayWatcher.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/io/watch/watchers/DelayWatcher.java @@ -16,7 +16,7 @@ package org.dromara.hutool.core.io.watch.watchers; -import org.dromara.hutool.core.collection.ConcurrentHashSet; +import org.dromara.hutool.core.collection.set.ConcurrentHashSet; import org.dromara.hutool.core.io.watch.Watcher; import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.thread.ThreadUtil; diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/stream/EntryStream.java b/hutool-core/src/main/java/org/dromara/hutool/core/stream/EntryStream.java index 24352ff15..8ca6add64 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/stream/EntryStream.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/stream/EntryStream.java @@ -16,7 +16,7 @@ package org.dromara.hutool.core.stream; -import org.dromara.hutool.core.collection.ConcurrentHashSet; +import org.dromara.hutool.core.collection.set.ConcurrentHashSet; import org.dromara.hutool.core.collection.iter.IterUtil; import org.dromara.hutool.core.map.multi.RowKeyTable; import org.dromara.hutool.core.map.multi.Table; diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/data/id/SnowflakeTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/data/id/SnowflakeTest.java index b4da63e94..fab859c5c 100644 --- a/hutool-core/src/test/java/org/dromara/hutool/core/data/id/SnowflakeTest.java +++ b/hutool-core/src/test/java/org/dromara/hutool/core/data/id/SnowflakeTest.java @@ -12,7 +12,7 @@ package org.dromara.hutool.core.data.id; -import org.dromara.hutool.core.collection.ConcurrentHashSet; +import org.dromara.hutool.core.collection.set.ConcurrentHashSet; import org.dromara.hutool.core.exception.HutoolException; import org.dromara.hutool.core.lang.Console; import org.dromara.hutool.core.lang.tuple.Pair; diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/data/id/UUIDTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/data/id/UUIDTest.java index 8ca0895ca..65b65f1ba 100644 --- a/hutool-core/src/test/java/org/dromara/hutool/core/data/id/UUIDTest.java +++ b/hutool-core/src/test/java/org/dromara/hutool/core/data/id/UUIDTest.java @@ -12,8 +12,7 @@ package org.dromara.hutool.core.data.id; -import org.dromara.hutool.core.collection.ConcurrentHashSet; -import org.dromara.hutool.core.lang.Console; +import org.dromara.hutool.core.collection.set.ConcurrentHashSet; import org.dromara.hutool.core.thread.ThreadUtil; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/util/IdUtilTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/util/IdUtilTest.java index e70151494..9bec5c54c 100644 --- a/hutool-core/src/test/java/org/dromara/hutool/core/util/IdUtilTest.java +++ b/hutool-core/src/test/java/org/dromara/hutool/core/util/IdUtilTest.java @@ -12,7 +12,7 @@ package org.dromara.hutool.core.util; -import org.dromara.hutool.core.collection.ConcurrentHashSet; +import org.dromara.hutool.core.collection.set.ConcurrentHashSet; import org.dromara.hutool.core.date.DateUtil; import org.dromara.hutool.core.date.StopWatch; import org.dromara.hutool.core.exception.HutoolException; diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/JSON.java b/hutool-json/src/main/java/org/dromara/hutool/json/JSON.java index 1255c93e0..652ff2dd6 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/JSON.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/JSON.java @@ -20,7 +20,6 @@ import org.dromara.hutool.core.bean.path.BeanPath; import org.dromara.hutool.core.convert.ConvertException; import org.dromara.hutool.core.convert.Converter; import org.dromara.hutool.core.lang.mutable.MutableEntry; -import org.dromara.hutool.json.convert.JSONConverter; import java.io.Serializable; import java.io.StringWriter; @@ -193,6 +192,6 @@ public interface JSON extends Converter, Cloneable, Serializable { @Override default Object convert(final Type targetType, final Object value) throws ConvertException { - return JSONConverter.of(config()).convert(targetType, value); + return config().getConverter().convert(targetType, value); } } 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 7dcfd7dd4..6228f0088 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 @@ -61,8 +61,9 @@ public class JSONConverter implements Converter, Serializable { public static final JSONConverter INSTANCE = new JSONConverter(null); static { - RegisterConverter.getInstance().putCustom(JSONObject.class, INSTANCE); - RegisterConverter.getInstance().putCustom(JSONArray.class, INSTANCE); + final RegisterConverter converter = RegisterConverter.getInstance(); + converter.putCustom(JSONObject.class, INSTANCE); + converter.putCustom(JSONArray.class, INSTANCE); } /**