From 8ac1faf3009d17d15a6a7e4138e1c14f5505454e Mon Sep 17 00:00:00 2001 From: Carm Date: Sun, 2 Feb 2025 23:11:16 +0800 Subject: [PATCH] feat!(value): Finished the standard configured values --- .../configuration/adapter/ValueAdapter.java | 8 +- .../adapter/ValueAdapterRegistry.java | 10 +- .../configuration/adapter/ValueParser.java | 2 +- .../adapter/strandard/PrimitiveAdapters.java | 2 +- .../builder/value/ConfigValueBuilder.java | 34 +-- .../builder/value/SectionValueBuilder.java | 16 +- .../builder/value/SourceValueBuilder.java | 2 +- .../value/impl/CachedConfigValue.java | 23 ++ .../value/standard/ConfiguredList.java | 46 ++-- .../value/standard/ConfiguredMap.java | 196 ++++++++++++++++++ .../value/standard/ConfiguredValue.java | 34 +-- 11 files changed, 291 insertions(+), 82 deletions(-) create mode 100644 core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredMap.java diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueAdapter.java b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueAdapter.java index 6fe33a3..99ef7ef 100644 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueAdapter.java +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueAdapter.java @@ -38,7 +38,7 @@ public class ValueAdapter return serializer; } - public @Nullable ValueParser deserializer() { + public @Nullable ValueParser parser() { return deserializer; } @@ -46,7 +46,7 @@ public class ValueAdapter this.serializer = serializer; } - public void deserializer(@Nullable ValueParser deserializer) { + public void parser(@Nullable ValueParser deserializer) { this.deserializer = deserializer; } @@ -57,9 +57,9 @@ public class ValueAdapter } @Override - public TYPE deserialize(@NotNull ConfigurationProvider provider, @NotNull ValueType type, @NotNull Object value) throws Exception { + public TYPE parse(@NotNull ConfigurationProvider provider, @NotNull ValueType type, @NotNull Object value) throws Exception { if (deserializer == null) throw new UnsupportedOperationException("Deserializer is not supported"); - return deserializer.deserialize(provider, type, value); + return deserializer.parse(provider, type, value); } @Override 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 3bb7e67..2864261 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 @@ -27,7 +27,7 @@ public class ValueAdapterRegistry { if (fromAdapter == null) throw new IllegalArgumentException("No adapter for type " + from); register(to, serializer == null ? null : (provider, type, value) -> fromAdapter.serialize(provider, from, serializer.handle(value)), - parser == null ? null : (provider, type, data) -> parser.handle(fromAdapter.deserialize(provider, from, data)) + parser == null ? null : (provider, type, data) -> parser.handle(fromAdapter.parse(provider, from, data)) ); } @@ -55,7 +55,7 @@ public class ValueAdapterRegistry { public void register(@NotNull ValueType type, @NotNull ValueParser deserializer) { ValueAdapter existing = adapterOf(type); if (existing != null) { - existing.deserializer(deserializer); + existing.parser(deserializer); } else { register(new ValueAdapter<>(type, null, deserializer)); } @@ -66,7 +66,7 @@ public class ValueAdapterRegistry { ValueAdapter existing = adapterOf(type); if (existing != null) { if (serializer != null) existing.serializer(serializer); - if (deserializer != null) existing.deserializer(deserializer); + if (deserializer != null) existing.parser(deserializer); } else { register(new ValueAdapter<>(type, serializer, deserializer)); } @@ -81,7 +81,7 @@ public class ValueAdapterRegistry { } @SuppressWarnings("unchecked") - public ValueAdapter adapterOf(@NotNull ValueType type) { + 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; @@ -110,7 +110,7 @@ public class ValueAdapterRegistry { if (type.isInstance(source)) return type.cast(source); // Not required to deserialize ValueAdapter adapter = adapterOf(type); if (adapter == null) throw new RuntimeException("No adapter for type " + type); - return adapter.deserialize(provider, type, source); + return adapter.parse(provider, type, source); } @Contract("_,null -> null") diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueParser.java b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueParser.java index b35b089..d375456 100644 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueParser.java +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueParser.java @@ -11,7 +11,7 @@ import org.jetbrains.annotations.NotNull; @FunctionalInterface public interface ValueParser { - TYPE deserialize( + TYPE parse( @NotNull ConfigurationProvider provider, @NotNull ValueType type, @NotNull Object data ) throws Exception; diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.java b/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.java index f522bed..1017820 100644 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.java +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.java @@ -18,7 +18,7 @@ public class PrimitiveAdapters extends ValueAdapter { public static ValueAdapter> ofEnum() { ValueAdapter> adapter = new ValueAdapter<>(new ValueType>() { }); - adapter.deserializer((provider, type, data) -> Enum.valueOf((Class) type.getRawType(), data.toString())); + adapter.parser((provider, type, data) -> Enum.valueOf((Class) type.getRawType(), data.toString())); adapter.serializer((provider, type, value) -> value.name()); return adapter; } diff --git a/core/src/main/java/cc/carm/lib/configuration/builder/value/ConfigValueBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/value/ConfigValueBuilder.java index 113fabf..5a41e9a 100644 --- a/core/src/main/java/cc/carm/lib/configuration/builder/value/ConfigValueBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/builder/value/ConfigValueBuilder.java @@ -34,44 +34,12 @@ public class ConfigValueBuilder { return from(String.class); } - public @NotNull SourceValueBuilder fromInteger() { - return from(Integer.class); - } - - public @NotNull SourceValueBuilder fromLong() { - return from(Long.class); - } - - public @NotNull SourceValueBuilder fromDouble() { - return from(Double.class); - } - - public @NotNull SourceValueBuilder fromFloat() { - return from(Float.class); - } - - public @NotNull SourceValueBuilder fromBoolean() { - return from(Boolean.class); - } - - public @NotNull SourceValueBuilder fromCharacter() { - return from(Character.class); - } - - public @NotNull SourceValueBuilder fromByte() { - return from(Byte.class); - } - - public @NotNull SourceValueBuilder fromShort() { - return from(Short.class); - } - public @NotNull SectionValueBuilder fromSection() { return new SectionValueBuilder<>(this.type); } public @NotNull SectionValueBuilder fromSection(@NotNull ConfigValueHandler valueParser, - @NotNull ConfigValueHandler> valueSerializer) { + @NotNull ConfigValueHandler> valueSerializer) { return new SectionValueBuilder<>(this.type, valueParser, valueSerializer); } diff --git a/core/src/main/java/cc/carm/lib/configuration/builder/value/SectionValueBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/value/SectionValueBuilder.java index a4a4dae..1dc7f5b 100644 --- a/core/src/main/java/cc/carm/lib/configuration/builder/value/SectionValueBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/builder/value/SectionValueBuilder.java @@ -17,7 +17,7 @@ public class SectionValueBuilder extends CommonConfigBuilder valueType; protected @NotNull ConfigValueHandler parser; - protected @NotNull ConfigValueHandler> serializer; + protected @NotNull ConfigValueHandler> serializer; public SectionValueBuilder(@NotNull ValueType valueType) { this(valueType, ConfigValueHandler.required(), ConfigValueHandler.required()); @@ -25,7 +25,7 @@ public class SectionValueBuilder extends CommonConfigBuilder valueType, @NotNull ConfigValueHandler parser, - @NotNull ConfigValueHandler> serializer) { + @NotNull ConfigValueHandler> serializer) { this.valueType = valueType; this.parser = parser; this.serializer = serializer; @@ -45,18 +45,18 @@ public class SectionValueBuilder extends CommonConfigBuilder serialize(ConfigDataFunction> serializer) { + public @NotNull SectionValueBuilder serialize(ConfigDataFunction> serializer) { return serialize((p, value) -> serializer.handle(value)); } - public @NotNull SectionValueBuilder serialize(ConfigValueHandler> serializer) { + public @NotNull SectionValueBuilder serialize(ConfigValueHandler> serializer) { this.serializer = serializer; return this; } - public @NotNull SectionValueBuilder serialize(Consumer> serializer) { + public @NotNull SectionValueBuilder serialize(Consumer> serializer) { return serialize((p, value) -> { - Map map = new LinkedHashMap<>(); + Map map = new LinkedHashMap<>(); serializer.accept(map); return map; }); @@ -64,7 +64,7 @@ public class SectionValueBuilder extends CommonConfigBuilder build() { - return new ConfiguredValue<>( + return ConfiguredValue.of( buildManifest(), (p, type, data) -> { ConfigurationSection section = p.deserialize(ConfigurationSection.class, data); @@ -72,7 +72,7 @@ public class SectionValueBuilder extends CommonConfigBuilder { - Map map = this.serializer.handle(p, data); + Map map = this.serializer.handle(p, data); return map == null || map.isEmpty() ? null : map; // Map is a type of original data } ); diff --git a/core/src/main/java/cc/carm/lib/configuration/builder/value/SourceValueBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/value/SourceValueBuilder.java index fd8bc29..aa8dd88 100644 --- a/core/src/main/java/cc/carm/lib/configuration/builder/value/SourceValueBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/builder/value/SourceValueBuilder.java @@ -52,7 +52,7 @@ public class SourceValueBuilder extends CommonConfigBuilder build() { - return new ConfiguredValue<>( + return ConfiguredValue.of( buildManifest(), (p, type, data) -> { S source = p.deserialize(this.sourceType, data); diff --git a/core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java b/core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java index 13b852d..7f52e43 100644 --- a/core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java @@ -1,5 +1,8 @@ package cc.carm.lib.configuration.value.impl; +import cc.carm.lib.configuration.adapter.ValueAdapter; +import cc.carm.lib.configuration.adapter.ValueParser; +import cc.carm.lib.configuration.adapter.ValueSerializer; import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.value.ValueManifest; import org.jetbrains.annotations.Contract; @@ -55,4 +58,24 @@ public abstract class CachedConfigValue extends ConfigValue { else return emptyValue; } + /** + * @return Value's parser, parse base object to value. + */ + protected @Nullable ValueParser parserFor(@NotNull ValueAdapter adapter) { + if (adapter.parser() != null) return adapter.parser(); + ValueAdapter registered = provider().adapters().adapterOf(adapter.type()); + if (registered == null) return null; + return registered.parser(); + } + + /** + * @return Value's serializer, parse value to base object. + */ + protected @Nullable ValueSerializer serializerFor(@NotNull ValueAdapter adapter) { + if (adapter.serializer() != null) return adapter.serializer(); + ValueAdapter registered = provider().adapters().adapterOf(adapter.type()); + if (registered == null) return null; + return registered.serializer(); + } + } diff --git a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java index e5907ff..e76718d 100644 --- a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java @@ -1,5 +1,6 @@ package cc.carm.lib.configuration.value.standard; +import cc.carm.lib.configuration.adapter.ValueAdapter; import cc.carm.lib.configuration.adapter.ValueParser; import cc.carm.lib.configuration.adapter.ValueSerializer; import cc.carm.lib.configuration.adapter.ValueType; @@ -11,54 +12,65 @@ import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Supplier; public class ConfiguredList extends CachedConfigValue> implements List { - protected final @NotNull ValueType valueType; - protected final @Nullable ValueParser parser; - protected final @Nullable ValueSerializer serializer; + protected final @NotNull Supplier> constructor; + protected final @NotNull ValueAdapter paramAdapter; - private ConfiguredList(@NotNull ValueManifest> manifest, @NotNull ValueType valueType, - @Nullable ValueParser parser, @Nullable ValueSerializer serializer) { + private ConfiguredList(@NotNull ValueManifest> manifest, + @NotNull Supplier> constructor, + @NotNull ValueAdapter paramAdapter) { super(manifest); - this.valueType = valueType; - this.parser = parser; - this.serializer = serializer; + this.constructor = constructor; + this.paramAdapter = paramAdapter; + } + + /** + * @return Adapter of this value. + */ + public @NotNull ValueAdapter adapter() { + return this.paramAdapter; + } + + public @NotNull ValueType paramType() { + return adapter().type(); } /** * @return Value's parser, parse base object to value. */ public @Nullable ValueParser parser() { - return parser; + return parserFor(adapter()); } /** * @return Value's serializer, parse value to base object. */ public @Nullable ValueSerializer serializer() { - return serializer; + return serializerFor(adapter()); } - public @NotNull ValueType valueType() { - return valueType; + private @NotNull List createList() { + return constructor.get(); } @Override public @NotNull List get() { - if (!isExpired()) return getCachedOrDefault(new ArrayList<>()); + if (!isExpired()) return getCachedOrDefault(createList()); // Data that is outdated and needs to be parsed again. - List list = new ArrayList<>(); + List list = createList(); List data = config().contains(path()) ? config().getList(path()) : null; if (data == null) return getDefaultFirst(list); - ValueParser parser = this.parser; + ValueParser parser = parser(); if (parser == null) return getDefaultFirst(list); for (Object dataVal : data) { if (dataVal == null) continue; try { - list.add(parser.deserialize(provider(), valueType(), dataVal)); + list.add(parser.parse(provider(), paramType(), dataVal)); } catch (Exception e) { e.printStackTrace(); } @@ -80,7 +92,7 @@ public class ConfiguredList extends CachedConfigValue> implements Lis for (V val : value) { if (val == null) continue; try { - data.add(serializer.serialize(provider(), valueType, val)); + data.add(serializer.serialize(provider(), paramType(), val)); } catch (Exception ex) { ex.printStackTrace(); } diff --git a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredMap.java b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredMap.java new file mode 100644 index 0000000..4eb4a1d --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredMap.java @@ -0,0 +1,196 @@ +package cc.carm.lib.configuration.value.standard; + +import cc.carm.lib.configuration.adapter.ValueAdapter; +import cc.carm.lib.configuration.adapter.ValueParser; +import cc.carm.lib.configuration.adapter.ValueSerializer; +import cc.carm.lib.configuration.adapter.ValueType; +import cc.carm.lib.configuration.source.section.ConfigurationSection; +import cc.carm.lib.configuration.value.ValueManifest; +import cc.carm.lib.configuration.value.impl.CachedConfigValue; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Unmodifiable; + +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +public class ConfiguredMap extends CachedConfigValue> implements Map { + + protected final @NotNull Supplier> constructor; + + protected final @NotNull ValueAdapter keyAdapter; + protected final @NotNull ValueAdapter valueAdapter; + + protected ConfiguredMap(@NotNull ValueManifest> manifest, + @NotNull Supplier> constructor, + @NotNull ValueAdapter keyAdapter, @NotNull ValueAdapter valueAdapter) { + super(manifest); + this.constructor = constructor; + this.keyAdapter = keyAdapter; + this.valueAdapter = valueAdapter; + } + + public @NotNull ValueAdapter keyAdapter() { + return keyAdapter; + } + + public @NotNull ValueType keyType() { + return keyAdapter().type(); + } + + public @NotNull ValueAdapter valueAdapter() { + return valueAdapter; + } + + public @NotNull ValueType valueType() { + return valueAdapter().type(); + } + + private Map createMap() { + return this.constructor.get(); + } + + @Override + public @NotNull Map get() { + if (!isExpired()) return getCachedOrDefault(createMap()); + // If the value is expired, we need to update it + Map map = createMap(); + + ConfigurationSection section = config().getSection(path()); + if (section == null) return getDefaultFirst(map); + + Set keys = section.getKeys(false); + if (keys.isEmpty()) return getDefaultFirst(map); + + ValueParser keyParser = parserFor(keyAdapter); + ValueParser valueParser = parserFor(valueAdapter); + if (keyParser == null || valueParser == null) return getDefaultFirst(map); + + for (String dataKey : keys) { + Object dataVal = section.get(dataKey); + if (dataVal == null) continue; + try { + K key = keyParser.parse(provider(), keyType(), dataKey); + V value = valueParser.parse(provider(), valueType(), dataVal); + map.put(key, value); + } catch (Exception e) { + e.printStackTrace(); + } + } + + return updateCache(map); + } + + @Override + public V get(Object key) { + return get().get(key); + } + + public V getNotNull(Object key) { + return Objects.requireNonNull(get(key)); + } + + @Override + public void set(@Nullable Map value) { + updateCache(value); + if (value == null) { + setData(null); + return; + } + + ValueSerializer keySerializer = serializerFor(keyAdapter); + ValueSerializer valueSerializer = serializerFor(valueAdapter); + if (keySerializer == null || valueSerializer == null) return; + + Map data = new LinkedHashMap<>(); + + for (Map.Entry entry : value.entrySet()) { + try { + data.put( + keySerializer.serialize(provider(), keyType(), entry.getKey()), + valueSerializer.serialize(provider(), valueType(), entry.getValue()) + ); + } catch (Exception e) { + e.printStackTrace(); + } + } + setData(data); + } + + public @NotNull T handle(Function, T> function) { + Map m = get(); + T result = function.apply(m); + set(m); + return result; + } + + public @NotNull ConfiguredMap modify(Consumer> consumer) { + Map m = get(); + consumer.accept(m); + set(m); + return this; + } + + @Override + public int size() { + return get().size(); + } + + @Override + public boolean isEmpty() { + return get().isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return get().containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return get().containsValue(value); + } + + @Nullable + @Override + public V put(K key, V value) { + return handle(m -> m.put(key, value)); + } + + @Override + public V remove(Object key) { + return handle(m -> m.remove(key)); + } + + @Override + public void putAll(@NotNull Map m) { + modify(map -> map.putAll(m)); + } + + @Override + public void clear() { + modify(Map::clear); + } + + @NotNull + @Override + public Set keySet() { + return get().keySet(); + } + + @NotNull + @Override + public Collection values() { + return get().values(); + } + + @NotNull + @Override + @Unmodifiable + public Set> entrySet() { + return get().entrySet(); + } + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredValue.java b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredValue.java index d444034..8df3683 100644 --- a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredValue.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredValue.java @@ -1,10 +1,10 @@ package cc.carm.lib.configuration.value.standard; +import cc.carm.lib.configuration.adapter.ValueAdapter; import cc.carm.lib.configuration.adapter.ValueParser; import cc.carm.lib.configuration.adapter.ValueSerializer; import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.builder.value.ConfigValueBuilder; -import cc.carm.lib.configuration.source.ConfigurationProvider; import cc.carm.lib.configuration.value.ValueManifest; import cc.carm.lib.configuration.value.impl.CachedConfigValue; import org.jetbrains.annotations.NotNull; @@ -49,32 +49,42 @@ public class ConfiguredValue extends CachedConfigValue { public static ConfiguredValue of(@NotNull ValueManifest manifest, @Nullable ValueParser parser, @Nullable ValueSerializer serializer) { - return new ConfiguredValue<>(manifest, parser, serializer); + ValueAdapter adapter = new ValueAdapter<>(manifest.type()); + adapter.parser(parser); + adapter.serializer(serializer); + return of(manifest, adapter); } - protected final @Nullable ValueParser parser; - protected final @Nullable ValueSerializer serializer; + public static ConfiguredValue of(@NotNull ValueManifest manifest, @NotNull ValueAdapter adapter) { + return new ConfiguredValue<>(manifest, adapter); + } - public ConfiguredValue(@NotNull ValueManifest manifest, - @Nullable ValueParser parser, - @Nullable ValueSerializer serializer) { + protected final @NotNull ValueAdapter adapter; + + public ConfiguredValue(@NotNull ValueManifest manifest, @NotNull ValueAdapter adapter) { super(manifest); - this.parser = parser; - this.serializer = serializer; + this.adapter = adapter; + } + + /** + * @return Adapter of this value. + */ + public @NotNull ValueAdapter adapter() { + return adapter; } /** * @return Value's parser, parse base object to value. */ public @Nullable ValueParser parser() { - return parser; + return parserFor(adapter()); } /** * @return Value's serializer, parse value to base object. */ public @Nullable ValueSerializer serializer() { - return serializer; + return serializerFor(adapter()); } @Override @@ -90,7 +100,7 @@ public class ConfiguredValue extends CachedConfigValue { try { // If there are no errors, update the cache and return. - return updateCache(parser.deserialize(provider(), type(), data)); + return updateCache(parser.parse(provider(), type(), data)); } catch (Exception e) { // There was a parsing error, prompted and returned the default value. e.printStackTrace();