1
mirror of https://github.com/CarmJos/EasyConfiguration.git synced 2026-06-04 18:48:20 +08:00

refactor deserialize, add set collection dsl

This commit is contained in:
huanmeng-qwq
2025-09-27 02:49:57 +08:00
committed by Carm
parent fc4a11bc3e
commit 4a0e6b0676
5 changed files with 171 additions and 45 deletions
@@ -6,6 +6,7 @@ import cc.carm.lib.configuration.source.section.ConfigureSection;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Array;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.*; import java.util.*;
@@ -13,6 +14,7 @@ import java.util.*;
public class ValueAdapterRegistry { public class ValueAdapterRegistry {
protected final Set<ValueAdapter<?>> adapters = new HashSet<>(); protected final Set<ValueAdapter<?>> adapters = new HashSet<>();
protected final Map<ValueType<?>, ValueAdapter<?>> adapterCache = new HashMap<>();
public <FROM, TO> void register(@NotNull Class<FROM> from, @NotNull Class<TO> to, public <FROM, TO> void register(@NotNull Class<FROM> from, @NotNull Class<TO> to,
@Nullable DataFunction<FROM, TO> parser, @Nullable DataFunction<FROM, TO> parser,
@@ -33,6 +35,7 @@ public class ValueAdapterRegistry {
public void register(@NotNull ValueAdapter<?>... adapter) { public void register(@NotNull ValueAdapter<?>... adapter) {
adapters.addAll(Arrays.asList(adapter)); adapters.addAll(Arrays.asList(adapter));
adapterCache.clear();
} }
public <T> void register(@NotNull Class<T> type, @NotNull ValueSerializer<T> serializer) { public <T> void register(@NotNull Class<T> type, @NotNull ValueSerializer<T> serializer) {
@@ -80,19 +83,30 @@ public class ValueAdapterRegistry {
public void unregister(@NotNull ValueType<?> type) { public void unregister(@NotNull ValueType<?> type) {
adapters.removeIf(adapter -> adapter.type().equals(type)); adapters.removeIf(adapter -> adapter.type().equals(type));
adapterCache.clear();
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> @Nullable ValueAdapter<T> adapterOf(@NotNull ValueType<T> type) { public <T> @Nullable ValueAdapter<T> adapterOf(@NotNull ValueType<T> type) {
ValueAdapter<?> matched = adapters.stream() ValueAdapter<?> cached = adapterCache.get(type);
.filter(adapter -> adapter.type().equals(type)) if (cached != null) return (ValueAdapter<T>) cached;
.findFirst().orElse(null);
if (matched != null) return (ValueAdapter<T>) matched;
// If no adapter found, try to find the adapter for the super type for (ValueAdapter<?> adapter : adapters) {
return (ValueAdapter<T>) adapters.stream() if (adapter.type().equals(type)) {
.filter(adapter -> adapter.type().isSubtypeOf(type)) adapterCache.put(type, adapter);
.findFirst().orElse(null); return (ValueAdapter<T>) adapter;
}
}
for (ValueAdapter<?> adapter : adapters) {
if (adapter.type().isSubtypeOf(type)) {
adapterCache.put(type, adapter);
return (ValueAdapter<T>) adapter;
}
}
adapterCache.put(type, null);
return null;
} }
public <T> ValueAdapter<T> adapterOf(@NotNull T value) { public <T> ValueAdapter<T> adapterOf(@NotNull T value) {
@@ -108,50 +122,126 @@ public class ValueAdapterRegistry {
} }
public <T> T deserialize(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<T> type, @Nullable Object source) throws Exception { public <T> T deserialize(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<T> type, @Nullable Object source) throws Exception {
if (source == null) return null; // Null check if (source == null) return null;
if (!(type.getType() instanceof ParameterizedType) && type.isInstance(source)) {
return type.cast(source); // Not required to deserialize Type typeInstance = type.getType();
if (!(typeInstance instanceof ParameterizedType) && type.isInstance(source)) {
return type.cast(source);
} }
ValueAdapter<T> adapter = adapterOf(type); // Try to find an existed adapter for the type ValueAdapter<T> adapter = adapterOf(type);
if (adapter != null) { if (adapter != null) {
return adapter.parse(holder, type, source); return adapter.parse(holder, type, source);
} // If no adapter found, we will try to handle the type manually }
if (type.getRawType().isArray()) { // For arrays. return deserializeWithoutAdapter(holder, type, source, typeInstance);
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++) { private <T> T deserializeWithoutAdapter(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<T> type,
array[i] = deserialize(holder, type.getRawType().getComponentType(), list.get(i)); @NotNull Object source, @NotNull Type typeInstance) throws Exception {
} Class<?> rawType = type.getRawType();
return type.cast(array);
} else if (type.getType() instanceof ParameterizedType) { if (rawType.isArray()) {
ParameterizedType pt = (ParameterizedType) type.getType(); return deserializeArray(holder, type, source, rawType);
Type rawType = pt.getRawType(); }
Type[] typeArgs = pt.getActualTypeArguments();
if (rawType == List.class || rawType == Collection.class || rawType == ArrayList.class) { if (typeInstance instanceof ParameterizedType) {
return type.cast(new ArrayList<>(deserializeList(holder, ValueType.of(typeArgs[0]), source))); return deserializeParameterized(holder, type, source, (ParameterizedType) typeInstance);
} 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) { throw new RuntimeException("No adapter for type " + type);
Map<?, ?> map; }
if (source instanceof Map<?, ?>) {
map = (Map<?, ?>) source; private <T> T deserializeArray(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<T> type,
} else if (source instanceof ConfigureSection) { @NotNull Object source, @NotNull Class<?> rawType) throws Exception {
map = ((ConfigureSection) source).asMap(); if (!(source instanceof List<?>)) {
} else { source = deserializeList(holder, type, source);
throw new IllegalArgumentException("Cannot deserialize to Map from " + source.getClass()); }
}
Map<Object, Object> resultMap = new LinkedHashMap<>(map.size()); List<?> list = (List<?>) source;
for (Map.Entry<?, ?> entry : map.entrySet()) { int size = list.size();
Object key = deserialize(holder, ValueType.of(typeArgs[0]), entry.getKey()); if (size == 0) {
Object value = deserialize(holder, ValueType.of(typeArgs[1]), entry.getValue()); return type.cast(Array.newInstance(rawType.getComponentType(), 0));
resultMap.put(key, value); }
}
return type.cast(resultMap); 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> T deserializeParameterized(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<T> 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<Collection<Object>> collectionFactory) throws Exception {
ValueType<?> elementValueType = ValueType.of(elementType);
List<?> sourceList = deserializeList(holder, elementValueType, source);
if (sourceList.isEmpty()) {
return collectionFactory.get();
}
Collection<Object> result = collectionFactory.get();
if (result instanceof ArrayList) {
((ArrayList<Object>) 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<Object, Object> 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<Object, Object> 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 @Nullable
@@ -96,6 +96,7 @@ public class ConfigurationTest {
System.out.println("> Test Kotlin value after:"); System.out.println("> Test Kotlin value after:");
System.out.println(KotlinConfiguration.INSTANCE.getLINKED_MAP().get()); 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) { public static void save(ConfigurationHolder<?> provider) {
@@ -16,6 +16,10 @@ object KotlinConfiguration : Configuration {
defaults("Carm Jos") defaults("Carm Jos")
} }
val BLACK_LIST = setFrom(String::class) {
defaults("404", "404", "123")
}
val NICKNAME = mapFrom(String::class, ::mutableMapOf) { val NICKNAME = mapFrom(String::class, ::mutableMapOf) {
defaultMap(mapOf("Carm Jos" to "Carm")) defaultMap(mapOf("Carm Jos" to "Carm"))
parse { v -> v } parse { v -> v }
+5
View File
@@ -30,6 +30,11 @@
<artifactId>configured-core</artifactId> <artifactId>configured-core</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>configured-feature-collections</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.jetbrains.kotlin</groupId> <groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId> <artifactId>kotlin-stdlib-jdk8</artifactId>
@@ -2,6 +2,8 @@ package cc.carm.lib.configuration.kotlin.value
import cc.carm.lib.configuration.adapter.ValueType import cc.carm.lib.configuration.adapter.ValueType
import cc.carm.lib.configuration.builder.collection.SimpleCollectionCreator 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 cc.carm.lib.configuration.value.standard.ConfiguredList
import kotlin.reflect.KClass import kotlin.reflect.KClass
@@ -28,3 +30,27 @@ inline fun <S : Any, reified V> listFrom(
} else configBuilder.from(valueType) } else configBuilder.from(valueType)
return sourceValueBuilder.also(block).build() return sourceValueBuilder.also(block).build()
} }
inline fun <S : Any, reified V> setFrom(
clazz: KClass<S>, block: (ConfigSetBuilder.SourceBuilder<S, V>.() -> Unit)
): ConfiguredSet<V> {
return setFrom(clazz.java, block)
}
inline fun <S : Any, reified V> setFrom(
clazz: Class<S>, block: (ConfigSetBuilder.SourceBuilder<S, V>.() -> Unit)
): ConfiguredSet<V> {
return setFrom(ValueType.of(clazz), block)
}
inline fun <S : Any, reified V> setFrom(
valueType: ValueType<S>, block: (ConfigSetBuilder.SourceBuilder<S, V>.() -> Unit)
): ConfiguredSet<V> {
val configBuilder = ConfiguredSet.builderOf(V::class.java)
val sourceValueBuilder: ConfigSetBuilder.SourceBuilder<S, V> =
if (valueType.rawType == String::class.java) {
@Suppress("UNCHECKED_CAST")
configBuilder.fromString() as ConfigSetBuilder.SourceBuilder<S, V>
} else configBuilder.from(valueType)
return sourceValueBuilder.also(block).build()
}