From 4a0e6b06765622b3410a3388d86045054d4e397d Mon Sep 17 00:00:00 2001 From: huanmeng-qwq <1871735932@qq.com> Date: Sat, 27 Sep 2025 02:49:57 +0800 Subject: [PATCH] refactor deserialize, add set collection dsl --- .../adapter/ValueAdapterRegistry.java | 180 +++++++++++++----- .../demo/tests/ConfigurationTest.java | 1 + .../demo/tests/conf/KotlinConfiguration.kt | 4 + features/kotlin/pom.xml | 5 + .../kotlin/value/{Lists.kt => Collections.kt} | 26 +++ 5 files changed, 171 insertions(+), 45 deletions(-) rename features/kotlin/src/main/kotlin/cc/carm/lib/configuration/kotlin/value/{Lists.kt => Collections.kt} (56%) diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueAdapterRegistry.java b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueAdapterRegistry.java index 674fa90..c277552 100644 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueAdapterRegistry.java +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueAdapterRegistry.java @@ -6,6 +6,7 @@ import cc.carm.lib.configuration.source.section.ConfigureSection; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.lang.reflect.Array; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.*; @@ -13,6 +14,7 @@ import java.util.*; public class ValueAdapterRegistry { protected final Set> adapters = new HashSet<>(); + protected final Map, ValueAdapter> adapterCache = new HashMap<>(); public void register(@NotNull Class from, @NotNull Class to, @Nullable DataFunction parser, @@ -33,6 +35,7 @@ public class ValueAdapterRegistry { public void register(@NotNull ValueAdapter... adapter) { adapters.addAll(Arrays.asList(adapter)); + adapterCache.clear(); } public void register(@NotNull Class type, @NotNull ValueSerializer serializer) { @@ -80,19 +83,30 @@ public class ValueAdapterRegistry { public void unregister(@NotNull ValueType type) { adapters.removeIf(adapter -> adapter.type().equals(type)); + adapterCache.clear(); } @SuppressWarnings("unchecked") public @Nullable ValueAdapter adapterOf(@NotNull ValueType type) { - ValueAdapter matched = adapters.stream() - .filter(adapter -> adapter.type().equals(type)) - .findFirst().orElse(null); - if (matched != null) return (ValueAdapter) matched; + ValueAdapter cached = adapterCache.get(type); + if (cached != null) return (ValueAdapter) cached; - // If no adapter found, try to find the adapter for the super type - return (ValueAdapter) adapters.stream() - .filter(adapter -> adapter.type().isSubtypeOf(type)) - .findFirst().orElse(null); + for (ValueAdapter adapter : adapters) { + if (adapter.type().equals(type)) { + adapterCache.put(type, adapter); + return (ValueAdapter) adapter; + } + } + + for (ValueAdapter adapter : adapters) { + if (adapter.type().isSubtypeOf(type)) { + adapterCache.put(type, adapter); + return (ValueAdapter) adapter; + } + } + + adapterCache.put(type, null); + return null; } public ValueAdapter adapterOf(@NotNull T value) { @@ -108,50 +122,126 @@ public class ValueAdapterRegistry { } public T deserialize(@NotNull ConfigurationHolder holder, @NotNull ValueType type, @Nullable Object source) throws Exception { - if (source == null) return null; // Null check - if (!(type.getType() instanceof ParameterizedType) && type.isInstance(source)) { - return type.cast(source); // Not required to deserialize + if (source == null) return null; + + Type typeInstance = type.getType(); + if (!(typeInstance instanceof ParameterizedType) && type.isInstance(source)) { + return type.cast(source); } - ValueAdapter adapter = adapterOf(type); // Try to find an existed adapter for the type + ValueAdapter adapter = adapterOf(type); if (adapter != null) { return adapter.parse(holder, type, source); - } // If no adapter found, we will try to handle the type manually + } - if (type.getRawType().isArray()) { // For arrays. - List list = deserializeList(holder, type, source); - Object[] array = (Object[]) java.lang.reflect.Array.newInstance(type.getRawType().getComponentType(), list.size()); - for (int i = 0; i < list.size(); i++) { - array[i] = deserialize(holder, type.getRawType().getComponentType(), list.get(i)); - } - return type.cast(array); - } else if (type.getType() instanceof ParameterizedType) { - ParameterizedType pt = (ParameterizedType) type.getType(); - Type rawType = pt.getRawType(); - Type[] typeArgs = pt.getActualTypeArguments(); - if (rawType == List.class || rawType == Collection.class || rawType == ArrayList.class) { - return type.cast(new ArrayList<>(deserializeList(holder, ValueType.of(typeArgs[0]), source))); - } else if (rawType == Set.class || rawType == HashSet.class) { - return type.cast(new HashSet<>(deserializeList(holder, ValueType.of(typeArgs[0]), source))); - } else if (rawType == Map.class || rawType == LinkedHashMap.class) { - Map map; - if (source instanceof Map) { - map = (Map) source; - } else if (source instanceof ConfigureSection) { - map = ((ConfigureSection) source).asMap(); - } else { - throw new IllegalArgumentException("Cannot deserialize to Map from " + source.getClass()); - } - Map resultMap = new LinkedHashMap<>(map.size()); - for (Map.Entry entry : map.entrySet()) { - Object key = deserialize(holder, ValueType.of(typeArgs[0]), entry.getKey()); - Object value = deserialize(holder, ValueType.of(typeArgs[1]), entry.getValue()); - resultMap.put(key, value); - } - return type.cast(resultMap); + return deserializeWithoutAdapter(holder, type, source, typeInstance); + } + + private T deserializeWithoutAdapter(@NotNull ConfigurationHolder holder, @NotNull ValueType type, + @NotNull Object source, @NotNull Type typeInstance) throws Exception { + Class rawType = type.getRawType(); + + if (rawType.isArray()) { + return deserializeArray(holder, type, source, rawType); + } + + if (typeInstance instanceof ParameterizedType) { + return deserializeParameterized(holder, type, source, (ParameterizedType) typeInstance); + } + + throw new RuntimeException("No adapter for type " + type); + } + + private T deserializeArray(@NotNull ConfigurationHolder holder, @NotNull ValueType type, + @NotNull Object source, @NotNull Class rawType) throws Exception { + if (!(source instanceof List)) { + source = deserializeList(holder, type, source); + } + + List list = (List) source; + int size = list.size(); + if (size == 0) { + return type.cast(Array.newInstance(rawType.getComponentType(), 0)); + } + + Class componentType = rawType.getComponentType(); + Object[] array = (Object[]) Array.newInstance(componentType, size); + for (int i = 0; i < size; i++) { + array[i] = deserialize(holder, componentType, list.get(i)); + } + return type.cast(array); + } + + @SuppressWarnings("unchecked") + private T deserializeParameterized(@NotNull ConfigurationHolder holder, @NotNull ValueType type, + @NotNull Object source, @NotNull ParameterizedType pt) throws Exception { + Type rawType = pt.getRawType(); + Type[] typeArgs = pt.getActualTypeArguments(); + + if (rawType == List.class || rawType == Collection.class || rawType == ArrayList.class) { + return (T) deserializeCollection(holder, source, typeArgs[0], ArrayList::new); + } + + if (rawType == Set.class || rawType == HashSet.class) { + return (T) deserializeCollection(holder, source, typeArgs[0], HashSet::new); + } + + if (rawType == Map.class || rawType == LinkedHashMap.class) { + return (T) deserializeMap(holder, source, typeArgs[0], typeArgs[1]); + } + + throw new RuntimeException("No adapter for parameterized type " + type); + } + + private Collection deserializeCollection(@NotNull ConfigurationHolder holder, @NotNull Object source, + @NotNull Type elementType, @NotNull java.util.function.Supplier> collectionFactory) throws Exception { + ValueType elementValueType = ValueType.of(elementType); + List sourceList = deserializeList(holder, elementValueType, source); + + if (sourceList.isEmpty()) { + return collectionFactory.get(); + } + + Collection result = collectionFactory.get(); + if (result instanceof ArrayList) { + ((ArrayList) result).ensureCapacity(sourceList.size()); + } + + for (Object item : sourceList) { + Object deserializedItem = deserialize(holder, elementValueType, item); + if (deserializedItem != null) { + result.add(deserializedItem); } } - throw new RuntimeException("No adapter for type " + type); + return result; + } + + private Map deserializeMap(@NotNull ConfigurationHolder holder, @NotNull Object source, + @NotNull Type keyType, @NotNull Type valueType) throws Exception { + Map sourceMap; + if (source instanceof Map) { + sourceMap = (Map) source; + } else if (source instanceof ConfigureSection) { + sourceMap = ((ConfigureSection) source).asMap(); + } else { + throw new IllegalArgumentException("Cannot deserialize to Map from " + source.getClass()); + } + + int mapSize = sourceMap.size(); + if (mapSize == 0) { + return new LinkedHashMap<>(); + } + + ValueType keyValueType = ValueType.of(keyType); + ValueType valueValueType = ValueType.of(valueType); + Map resultMap = new LinkedHashMap<>(mapSize); + + for (Map.Entry entry : sourceMap.entrySet()) { + Object key = deserialize(holder, keyValueType, entry.getKey()); + Object value = deserialize(holder, valueValueType, entry.getValue()); + resultMap.put(key, value); + } + return resultMap; } @Nullable diff --git a/demo/src/main/java/cc/carm/lib/configuration/demo/tests/ConfigurationTest.java b/demo/src/main/java/cc/carm/lib/configuration/demo/tests/ConfigurationTest.java index d5cf665..30ec6a4 100644 --- a/demo/src/main/java/cc/carm/lib/configuration/demo/tests/ConfigurationTest.java +++ b/demo/src/main/java/cc/carm/lib/configuration/demo/tests/ConfigurationTest.java @@ -96,6 +96,7 @@ public class ConfigurationTest { System.out.println("> Test Kotlin value after:"); System.out.println(KotlinConfiguration.INSTANCE.getLINKED_MAP().get()); + System.out.println("> Test Set value -> " + KotlinConfiguration.INSTANCE.getBLACK_LIST().get()); } public static void save(ConfigurationHolder provider) { diff --git a/demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/KotlinConfiguration.kt b/demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/KotlinConfiguration.kt index c71f88c..82195ac 100644 --- a/demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/KotlinConfiguration.kt +++ b/demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/KotlinConfiguration.kt @@ -16,6 +16,10 @@ object KotlinConfiguration : Configuration { defaults("Carm Jos") } + val BLACK_LIST = setFrom(String::class) { + defaults("404", "404", "123") + } + val NICKNAME = mapFrom(String::class, ::mutableMapOf) { defaultMap(mapOf("Carm Jos" to "Carm")) parse { v -> v } diff --git a/features/kotlin/pom.xml b/features/kotlin/pom.xml index 1821e17..12b3dfb 100644 --- a/features/kotlin/pom.xml +++ b/features/kotlin/pom.xml @@ -30,6 +30,11 @@ configured-core ${project.version} + + ${project.groupId} + configured-feature-collections + ${project.version} + org.jetbrains.kotlin kotlin-stdlib-jdk8 diff --git a/features/kotlin/src/main/kotlin/cc/carm/lib/configuration/kotlin/value/Lists.kt b/features/kotlin/src/main/kotlin/cc/carm/lib/configuration/kotlin/value/Collections.kt similarity index 56% rename from features/kotlin/src/main/kotlin/cc/carm/lib/configuration/kotlin/value/Lists.kt rename to features/kotlin/src/main/kotlin/cc/carm/lib/configuration/kotlin/value/Collections.kt index 73fd6ef..aaa8ba8 100644 --- a/features/kotlin/src/main/kotlin/cc/carm/lib/configuration/kotlin/value/Lists.kt +++ b/features/kotlin/src/main/kotlin/cc/carm/lib/configuration/kotlin/value/Collections.kt @@ -2,6 +2,8 @@ package cc.carm.lib.configuration.kotlin.value import cc.carm.lib.configuration.adapter.ValueType import cc.carm.lib.configuration.builder.collection.SimpleCollectionCreator +import cc.carm.lib.configuration.builder.set.ConfigSetBuilder +import cc.carm.lib.configuration.value.collections.ConfiguredSet import cc.carm.lib.configuration.value.standard.ConfiguredList import kotlin.reflect.KClass @@ -28,3 +30,27 @@ inline fun listFrom( } else configBuilder.from(valueType) return sourceValueBuilder.also(block).build() } + +inline fun setFrom( + clazz: KClass, block: (ConfigSetBuilder.SourceBuilder.() -> Unit) +): ConfiguredSet { + return setFrom(clazz.java, block) +} + +inline fun setFrom( + clazz: Class, block: (ConfigSetBuilder.SourceBuilder.() -> Unit) +): ConfiguredSet { + return setFrom(ValueType.of(clazz), block) +} + +inline fun setFrom( + valueType: ValueType, block: (ConfigSetBuilder.SourceBuilder.() -> Unit) +): ConfiguredSet { + val configBuilder = ConfiguredSet.builderOf(V::class.java) + val sourceValueBuilder: ConfigSetBuilder.SourceBuilder = + if (valueType.rawType == String::class.java) { + @Suppress("UNCHECKED_CAST") + configBuilder.fromString() as ConfigSetBuilder.SourceBuilder + } else configBuilder.from(valueType) + return sourceValueBuilder.also(block).build() +}