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:
@@ -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();
|
||||||
|
|
||||||
|
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> T deserializeArray(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<T> 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);
|
return type.cast(array);
|
||||||
} else if (type.getType() instanceof ParameterizedType) {
|
}
|
||||||
ParameterizedType pt = (ParameterizedType) type.getType();
|
|
||||||
|
@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 rawType = pt.getRawType();
|
||||||
Type[] typeArgs = pt.getActualTypeArguments();
|
Type[] typeArgs = pt.getActualTypeArguments();
|
||||||
|
|
||||||
if (rawType == List.class || rawType == Collection.class || rawType == ArrayList.class) {
|
if (rawType == List.class || rawType == Collection.class || rawType == ArrayList.class) {
|
||||||
return type.cast(new ArrayList<>(deserializeList(holder, ValueType.of(typeArgs[0]), source)));
|
return (T) deserializeCollection(holder, source, typeArgs[0], ArrayList::new);
|
||||||
} 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) {
|
if (rawType == Set.class || rawType == HashSet.class) {
|
||||||
Map<?, ?> map;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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<?, ?>) {
|
if (source instanceof Map<?, ?>) {
|
||||||
map = (Map<?, ?>) source;
|
sourceMap = (Map<?, ?>) source;
|
||||||
} else if (source instanceof ConfigureSection) {
|
} else if (source instanceof ConfigureSection) {
|
||||||
map = ((ConfigureSection) source).asMap();
|
sourceMap = ((ConfigureSection) source).asMap();
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Cannot deserialize to Map from " + source.getClass());
|
throw new IllegalArgumentException("Cannot deserialize to Map from " + source.getClass());
|
||||||
}
|
}
|
||||||
Map<Object, Object> resultMap = new LinkedHashMap<>(map.size());
|
|
||||||
for (Map.Entry<?, ?> entry : map.entrySet()) {
|
int mapSize = sourceMap.size();
|
||||||
Object key = deserialize(holder, ValueType.of(typeArgs[0]), entry.getKey());
|
if (mapSize == 0) {
|
||||||
Object value = deserialize(holder, ValueType.of(typeArgs[1]), entry.getValue());
|
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);
|
resultMap.put(key, value);
|
||||||
}
|
}
|
||||||
return type.cast(resultMap);
|
return resultMap;
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new RuntimeException("No adapter for type " + type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@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 }
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
+26
@@ -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()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user