mirror of
https://github.com/CarmJos/EasyConfiguration.git
synced 2026-06-04 10:38:19 +08:00
feat!(value): Redesigned the Configuration api
This commit is contained in:
@@ -18,14 +18,6 @@
|
||||
<artifactId>easyconfiguration-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyoptions</artifactId>
|
||||
<version>1.1.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
||||
@@ -2,8 +2,6 @@ package cc.carm.lib.configuration;
|
||||
|
||||
/**
|
||||
* The root interface of the configuration file interfaces,
|
||||
* which is used to label and record the configuration information.
|
||||
* which is used to label a class as a configuration.
|
||||
*/
|
||||
public interface Configuration {
|
||||
|
||||
}
|
||||
public interface Configuration { }
|
||||
@@ -1,52 +1,77 @@
|
||||
package cc.carm.lib.configuration.adapter;
|
||||
|
||||
import cc.carm.lib.configuration.source.ConfigurationProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Value adapter, used to convert the value of the configuration file into the objects.
|
||||
*
|
||||
* @param <B> The type of the base data
|
||||
* @param <V> The type of the target value
|
||||
* @param <TYPE> The type of the target value
|
||||
*/
|
||||
public abstract class ValueAdapter<B, V> implements ValueSerializer<B, V>, ValueDeserializer<B, V> {
|
||||
public class ValueAdapter<TYPE>
|
||||
implements ValueSerializer<TYPE>, ValueParser<TYPE> {
|
||||
|
||||
protected final Class<? super B> baseType;
|
||||
protected final Class<? super V> valueType;
|
||||
protected final @NotNull ValueType<TYPE> type;
|
||||
protected @Nullable ValueSerializer<TYPE> serializer;
|
||||
protected @Nullable ValueParser<TYPE> deserializer;
|
||||
|
||||
protected ValueAdapter(Class<? super B> baseType, Class<? super V> valueType) {
|
||||
this.baseType = baseType;
|
||||
this.valueType = valueType;
|
||||
public ValueAdapter(@NotNull ValueType<TYPE> type) {
|
||||
this(type, null, null);
|
||||
}
|
||||
|
||||
public Class<? super B> getBaseClass() {
|
||||
return baseType;
|
||||
public ValueAdapter(@NotNull ValueType<TYPE> type,
|
||||
@Nullable ValueSerializer<TYPE> serializer,
|
||||
@Nullable ValueParser<TYPE> deserializer) {
|
||||
this.type = type;
|
||||
this.serializer = serializer;
|
||||
this.deserializer = deserializer;
|
||||
}
|
||||
|
||||
public Class<? super V> getValueClass() {
|
||||
return valueType;
|
||||
public @NotNull ValueType<TYPE> type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public boolean isAdaptedFrom(Class<?> clazz) {
|
||||
return clazz.isAssignableFrom(valueType);
|
||||
public @Nullable ValueSerializer<TYPE> serializer() {
|
||||
return serializer;
|
||||
}
|
||||
|
||||
public boolean isAdaptedFrom(Object object) {
|
||||
return isAdaptedFrom(object.getClass());
|
||||
public @Nullable ValueParser<TYPE> deserializer() {
|
||||
return deserializer;
|
||||
}
|
||||
|
||||
public boolean isAdaptedTo(Class<?> clazz) {
|
||||
return clazz == valueType;
|
||||
public void serializer(@Nullable ValueSerializer<TYPE> serializer) {
|
||||
this.serializer = serializer;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected final V deserializeObject(ConfigurationProvider<?> provider, Class<?> valueClass, Object data) throws Exception {
|
||||
return deserialize(provider, (Class<? extends V>) valueClass, (B) data);
|
||||
public void deserializer(@Nullable ValueParser<TYPE> deserializer) {
|
||||
this.deserializer = deserializer;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected final B serializeObject(ConfigurationProvider<?> provider, Object value) throws Exception {
|
||||
return serialize(provider, (V) value);
|
||||
@Override
|
||||
public Object serialize(@NotNull ConfigurationProvider<?> provider, @NotNull ValueType<? super TYPE> type, @NotNull TYPE value) throws Exception {
|
||||
if (serializer == null) throw new UnsupportedOperationException("Serializer is not supported");
|
||||
return serializer.serialize(provider, type, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE deserialize(@NotNull ConfigurationProvider<?> provider, @NotNull ValueType<? super TYPE> type, @NotNull Object value) throws Exception {
|
||||
if (deserializer == null) throw new UnsupportedOperationException("Deserializer is not supported");
|
||||
return deserializer.deserialize(provider, type, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof ValueAdapter)) return false;
|
||||
ValueAdapter<?> that = (ValueAdapter<?>) o;
|
||||
return Objects.equals(type, that.type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,91 +1,125 @@
|
||||
package cc.carm.lib.configuration.adapter;
|
||||
|
||||
import cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapters;
|
||||
import cc.carm.lib.configuration.function.ConfigDataFunction;
|
||||
import cc.carm.lib.configuration.source.ConfigurationProvider;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class ValueAdapterRegistry {
|
||||
|
||||
protected final Map<Class<?>, ValueAdapter<?, ?>> adapters = new HashMap<>();
|
||||
protected final Set<ValueAdapter<?>> adapters = new HashSet<>();
|
||||
|
||||
public void register(@NotNull ValueAdapter<?, ?> adapter) {
|
||||
adapters.put(adapter.getValueClass(), adapter);
|
||||
public <FROM, TO> void register(@NotNull Class<FROM> from, @NotNull Class<TO> to,
|
||||
@Nullable ConfigDataFunction<FROM, TO> parser,
|
||||
@Nullable ConfigDataFunction<TO, FROM> serializer) {
|
||||
register(ValueType.of(from), ValueType.of(to), parser, serializer);
|
||||
}
|
||||
|
||||
public <T> void register(Class<T> clazz, @NotNull ValueAdapter<?, T> adapter) {
|
||||
adapters.put(clazz, adapter);
|
||||
public <FROM, TO> void register(@NotNull ValueType<FROM> from, @NotNull ValueType<TO> to,
|
||||
@Nullable ConfigDataFunction<FROM, TO> parser,
|
||||
@Nullable ConfigDataFunction<TO, FROM> serializer) {
|
||||
ValueAdapter<FROM> fromAdapter = adapterOf(from);
|
||||
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))
|
||||
);
|
||||
}
|
||||
|
||||
public <B, V> void register(Class<B> baseClass, Class<V> valueClass,
|
||||
ConfigDataFunction<B, V> parser,
|
||||
ConfigDataFunction<V, B> serializer) {
|
||||
register(new ValueAdapter<B, V>(baseClass, valueClass) {
|
||||
@Override
|
||||
public B serialize(@NotNull ConfigurationProvider<?> provider, @NotNull V value) throws Exception {
|
||||
return serializer.parse(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V deserialize(@NotNull ConfigurationProvider<?> provider, @NotNull Class<? extends V> clazz, @NotNull B data) throws Exception {
|
||||
return parser.parse(data);
|
||||
}
|
||||
});
|
||||
public void register(@NotNull ValueAdapter<?>... adapter) {
|
||||
adapters.addAll(Arrays.asList(adapter));
|
||||
}
|
||||
|
||||
public void unregister(@NotNull Class<?> typeClass) {
|
||||
adapters.remove(typeClass);
|
||||
public <T> void register(@NotNull Class<T> type, @NotNull ValueSerializer<T> serializer) {
|
||||
register(ValueType.of(type), serializer);
|
||||
}
|
||||
|
||||
public <T> void register(@NotNull ValueType<T> type, @NotNull ValueSerializer<T> serializer) {
|
||||
ValueAdapter<T> existing = adapterOf(type);
|
||||
if (existing != null) {
|
||||
existing.serializer(serializer);
|
||||
} else {
|
||||
register(new ValueAdapter<>(type, serializer, null));
|
||||
}
|
||||
}
|
||||
|
||||
public <T> void register(@NotNull Class<T> type, @NotNull ValueParser<T> deserializer) {
|
||||
register(ValueType.of(type), deserializer);
|
||||
}
|
||||
|
||||
public <T> void register(@NotNull ValueType<T> type, @NotNull ValueParser<T> deserializer) {
|
||||
ValueAdapter<T> existing = adapterOf(type);
|
||||
if (existing != null) {
|
||||
existing.deserializer(deserializer);
|
||||
} else {
|
||||
register(new ValueAdapter<>(type, null, deserializer));
|
||||
}
|
||||
}
|
||||
|
||||
public <T> void register(@NotNull ValueType<T> type, @Nullable ValueSerializer<T> serializer, @Nullable ValueParser<T> deserializer) {
|
||||
if (serializer == null && deserializer == null) return;
|
||||
ValueAdapter<T> existing = adapterOf(type);
|
||||
if (existing != null) {
|
||||
if (serializer != null) existing.serializer(serializer);
|
||||
if (deserializer != null) existing.deserializer(deserializer);
|
||||
} else {
|
||||
register(new ValueAdapter<>(type, serializer, deserializer));
|
||||
}
|
||||
}
|
||||
|
||||
public void unregister(@NotNull Class<?> type) {
|
||||
unregister(ValueType.of(type));
|
||||
}
|
||||
|
||||
public void unregister(@NotNull ValueType<?> type) {
|
||||
adapters.removeIf(adapter -> adapter.type().equals(type));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> ValueAdapter<T> adapterOf(@NotNull ValueType<T> type) {
|
||||
ValueAdapter<?> matched = adapters.stream().filter(adapter -> adapter.type().equals(type)).findFirst().orElse(null);
|
||||
if (matched != null) return (ValueAdapter<T>) matched;
|
||||
|
||||
// If no adapter found, try to find the adapter for the super type
|
||||
return (ValueAdapter<T>) adapters.stream()
|
||||
.filter(adapter -> adapter.type().isSubtypeOf(type))
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public <T> ValueAdapter<T> adapterOf(@NotNull T value) {
|
||||
return adapterOf(ValueType.of(value));
|
||||
}
|
||||
|
||||
public <T> ValueAdapter<T> adapterOf(@NotNull Class<T> type) {
|
||||
return adapterOf(ValueType.of(type));
|
||||
}
|
||||
|
||||
@Contract("_,_,null -> null")
|
||||
public <T> T deserialize(@NotNull ConfigurationProvider<?> provider, @NotNull Class<T> type, @Nullable Object source) throws Exception {
|
||||
return deserialize(provider, ValueType.of(type), source);
|
||||
}
|
||||
|
||||
@Contract("_,_,null -> null")
|
||||
public <T> T deserialize(@NotNull ConfigurationProvider<?> provider, @NotNull ValueType<T> type, @Nullable Object source) throws Exception {
|
||||
if (source == null) return null; // Null check
|
||||
if (type.isInstance(source)) return type.cast(source); // Not required to deserialize
|
||||
|
||||
ValueAdapter<?, ?> adapter = getAdapter(type);
|
||||
if (adapter == null) throw new RuntimeException("No adapter for type " + type.getName());
|
||||
|
||||
// Check if value is adapted from given value's type
|
||||
if (adapter.isAdaptedFrom(source)) {
|
||||
return (T) adapter.deserializeObject(provider, type, source);
|
||||
}
|
||||
|
||||
// Otherwise, we need to deserialize one by one.
|
||||
Object baseValue = deserialize(provider, adapter.getBaseClass(), source);
|
||||
if (baseValue == null) return null; // Null check
|
||||
|
||||
return (T) adapter.deserializeObject(provider, type, baseValue);
|
||||
ValueAdapter<T> adapter = adapterOf(type);
|
||||
if (adapter == null) throw new RuntimeException("No adapter for type " + type);
|
||||
return adapter.deserialize(provider, type, source);
|
||||
}
|
||||
|
||||
@Contract("_,null -> null")
|
||||
public <T> Object serialize(@NotNull ConfigurationProvider<?> provider, @Nullable T value) throws Exception {
|
||||
if (value == null) return null; // Null check
|
||||
|
||||
ValueAdapter<?, ?> adapter = getAdapter(value.getClass());
|
||||
ValueType<T> type = ValueType.of(value);
|
||||
ValueAdapter<T> adapter = adapterOf(type);
|
||||
if (adapter == null) return value; // No adapters, try to return the original value
|
||||
|
||||
if (adapter instanceof PrimitiveAdapters) {
|
||||
// If the value is adapted from a primitive type,
|
||||
// we should serialize it into object, then return.
|
||||
return adapter.serializeObject(provider, value);
|
||||
}
|
||||
|
||||
// Otherwise, we need to serialize one by one.
|
||||
return serialize(provider, adapter.serializeObject(provider, value));
|
||||
}
|
||||
|
||||
public ValueAdapter<?, ?> getAdapter(Class<?> clazz) {
|
||||
return adapters.getOrDefault(clazz, findAdapter(clazz));
|
||||
}
|
||||
|
||||
public ValueAdapter<?, ?> findAdapter(Class<?> clazz) {
|
||||
return adapters.values().stream().filter(adapter -> adapter.isAdaptedTo(clazz)).findFirst().orElse(null);
|
||||
return adapter.serialize(provider, type, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
package cc.carm.lib.configuration.adapter;
|
||||
|
||||
import cc.carm.lib.configuration.source.ConfigurationProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Value deserializer, convert base data to target value.
|
||||
*
|
||||
* @param <B> The type of base data
|
||||
* @param <V> The type of target value
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ValueDeserializer<B, V> {
|
||||
|
||||
V deserialize(@NotNull ConfigurationProvider<?> provider, @NotNull Class<? extends V> clazz, @NotNull B data) throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package cc.carm.lib.configuration.adapter;
|
||||
|
||||
import cc.carm.lib.configuration.source.ConfigurationProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Value deserializer, convert base data to target value.
|
||||
*
|
||||
* @param <TYPE> The type of target value
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ValueParser<TYPE> {
|
||||
|
||||
TYPE deserialize(
|
||||
@NotNull ConfigurationProvider<?> provider,
|
||||
@NotNull ValueType<? super TYPE> type, @NotNull Object data
|
||||
) throws Exception;
|
||||
|
||||
}
|
||||
@@ -6,12 +6,14 @@ import org.jetbrains.annotations.NotNull;
|
||||
/**
|
||||
* Value serializer, convert target value to base data.
|
||||
*
|
||||
* @param <B> The type of base data
|
||||
* @param <V> The type of value
|
||||
* @param <TYPE> The type of value
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ValueSerializer<B, V> {
|
||||
public interface ValueSerializer<TYPE> {
|
||||
|
||||
B serialize(@NotNull ConfigurationProvider<?> provider, @NotNull V value) throws Exception;
|
||||
Object serialize(
|
||||
@NotNull ConfigurationProvider<?> provider,
|
||||
@NotNull ValueType<? super TYPE> type, @NotNull TYPE value
|
||||
) throws Exception;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
package cc.carm.lib.configuration.adapter;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Used to get the generic type.
|
||||
*/
|
||||
public abstract class ValueType<T> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> ValueType<T> of(@NotNull T value) {
|
||||
return of((Class<T>) value.getClass());
|
||||
}
|
||||
|
||||
public static <T> ValueType<T> of(final Type type) {
|
||||
return new ValueType<T>(type) {
|
||||
};
|
||||
}
|
||||
|
||||
public static <T> ValueType<T> of(final Class<T> clazz) {
|
||||
return of((Type) clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the generic type of the complex type.
|
||||
*
|
||||
* @param rawType The raw type
|
||||
* @param types The type arguments
|
||||
* @param <T> The type
|
||||
* @return The {@link ValueType}
|
||||
*/
|
||||
public static <T> ValueType<T> of(final Class<?> rawType, final Type... types) {
|
||||
ParameterizedType parameterizedType = new ParameterizedType() {
|
||||
@Override
|
||||
public @NotNull Type @NotNull [] getActualTypeArguments() {
|
||||
return types;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Type getRawType() {
|
||||
return rawType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getOwnerType() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
return of(parameterizedType);
|
||||
}
|
||||
|
||||
private final Type type;
|
||||
|
||||
protected ValueType() {
|
||||
this.type = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
|
||||
}
|
||||
|
||||
private ValueType(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public boolean isSubtypeOf(Class<?> target) {
|
||||
Class<?> rawType = getRawType();
|
||||
return target.isAssignableFrom(rawType);
|
||||
}
|
||||
|
||||
public boolean isSubtypeOf(ValueType<?> target) {
|
||||
return target.isSubtypeOf(getRawType());
|
||||
}
|
||||
|
||||
public boolean isInstance(Object obj) {
|
||||
return obj != null && getRawType().isInstance(obj);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 提取当前 ValueType 的原始类型(Class 对象)。
|
||||
*
|
||||
* @return 对应的 Class 对象
|
||||
* @throws IllegalStateException 如果无法提取出原始类型
|
||||
*/
|
||||
public Class<?> getRawType() {
|
||||
if (type instanceof Class<?>) {
|
||||
return (Class<?>) type;
|
||||
}
|
||||
if (type instanceof ParameterizedType) {
|
||||
ParameterizedType pt = (ParameterizedType) type;
|
||||
Type raw = pt.getRawType();
|
||||
if (raw instanceof Class<?>) {
|
||||
return (Class<?>) raw;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Unsupported type: " + type);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public T cast(Object obj) {
|
||||
if (!isInstance(obj)) {
|
||||
throw new ClassCastException("Cannot cast object " + obj + " to type " + this);
|
||||
}
|
||||
return (T) obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (type instanceof Class<?>) {
|
||||
return ((Class<?>) type).getName();
|
||||
}
|
||||
if (type instanceof ParameterizedType) {
|
||||
ParameterizedType pt = (ParameterizedType) type;
|
||||
Type raw = pt.getRawType();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(raw.getTypeName());
|
||||
sb.append('<');
|
||||
Type[] args = pt.getActualTypeArguments();
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append(args[i].getTypeName());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
return type.getTypeName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (obj instanceof ValueType) {
|
||||
return Objects.equals(type, ((ValueType<?>) obj).type);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(type);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package cc.carm.lib.configuration.adapter.strandard;
|
||||
|
||||
import cc.carm.lib.configuration.adapter.ValueAdapter;
|
||||
import cc.carm.lib.configuration.source.ConfigurationProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public class EnumAdapter extends ValueAdapter<String, Enum> {
|
||||
|
||||
public EnumAdapter() {
|
||||
super(String.class, Enum.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serialize(@NotNull ConfigurationProvider<?> provider, @NotNull Enum value) throws Exception {
|
||||
return value.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enum deserialize(@NotNull ConfigurationProvider<?> provider, @NotNull Class<? extends Enum> clazz, @NotNull String data) throws Exception {
|
||||
return Enum.valueOf(clazz, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAdaptedTo(Class<?> clazz) {
|
||||
return clazz.isEnum();
|
||||
}
|
||||
|
||||
}
|
||||
+55
-16
@@ -1,11 +1,27 @@
|
||||
package cc.carm.lib.configuration.adapter.strandard;
|
||||
|
||||
import cc.carm.lib.configuration.adapter.ValueAdapter;
|
||||
import cc.carm.lib.configuration.adapter.ValueParser;
|
||||
import cc.carm.lib.configuration.adapter.ValueType;
|
||||
import cc.carm.lib.configuration.function.ConfigDataFunction;
|
||||
import cc.carm.lib.configuration.source.ConfigurationProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public abstract class PrimitiveAdapters<T> extends ValueAdapter<Object, T> {
|
||||
public class PrimitiveAdapters<T> extends ValueAdapter<T> {
|
||||
|
||||
public static final PrimitiveAdapters<?>[] ADAPTERS = new PrimitiveAdapters[]{
|
||||
ofString(), ofBoolean(), ofBooleanType(), ofCharacter(), ofCharacterType(),
|
||||
ofInteger(), ofIntegerType(), ofLong(), ofLongType(), ofDouble(), ofDoubleType(),
|
||||
ofFloat(), ofFloatType(), ofShort(), ofShortType(), ofByte(), ofByteType()
|
||||
};
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public static ValueAdapter<Enum<?>> ofEnum() {
|
||||
ValueAdapter<Enum<?>> adapter = new ValueAdapter<>(new ValueType<Enum<?>>() {
|
||||
});
|
||||
adapter.deserializer((provider, type, data) -> Enum.valueOf((Class<Enum>) type.getRawType(), data.toString()));
|
||||
adapter.serializer((provider, type, value) -> value.name());
|
||||
return adapter;
|
||||
}
|
||||
|
||||
public static PrimitiveAdapters<String> ofString() {
|
||||
return of(String.class, o -> o instanceof String ? (String) o : o.toString());
|
||||
@@ -15,56 +31,79 @@ public abstract class PrimitiveAdapters<T> extends ValueAdapter<Object, T> {
|
||||
return of(Boolean.class, o -> o instanceof Boolean ? (Boolean) o : Boolean.parseBoolean(o.toString()));
|
||||
}
|
||||
|
||||
public static PrimitiveAdapters<Boolean> ofBooleanType() {
|
||||
return of(boolean.class, o -> o instanceof Boolean ? (Boolean) o : Boolean.parseBoolean(o.toString()));
|
||||
}
|
||||
|
||||
public static PrimitiveAdapters<Character> ofCharacter() {
|
||||
return of(Character.class, o -> o instanceof Character ? (Character) o : o.toString().charAt(0));
|
||||
}
|
||||
|
||||
public static PrimitiveAdapters<Character> ofCharacterType() {
|
||||
return of(char.class, o -> o instanceof Character ? (Character) o : o.toString().charAt(0));
|
||||
}
|
||||
|
||||
public static PrimitiveAdapters<Integer> ofInteger() {
|
||||
return ofNumber(Integer.class, Number::intValue, Integer::parseInt);
|
||||
}
|
||||
|
||||
public static PrimitiveAdapters<Integer> ofIntegerType() {
|
||||
return ofNumber(int.class, Number::intValue, Integer::parseInt);
|
||||
}
|
||||
|
||||
public static PrimitiveAdapters<Long> ofLong() {
|
||||
return ofNumber(Long.class, Number::longValue, Long::parseLong);
|
||||
}
|
||||
|
||||
public static PrimitiveAdapters<Long> ofLongType() {
|
||||
return ofNumber(long.class, Number::longValue, Long::parseLong);
|
||||
}
|
||||
|
||||
public static PrimitiveAdapters<Double> ofDouble() {
|
||||
return ofNumber(Double.class, Number::doubleValue, Double::parseDouble);
|
||||
}
|
||||
|
||||
public static PrimitiveAdapters<Double> ofDoubleType() {
|
||||
return ofNumber(double.class, Number::doubleValue, Double::parseDouble);
|
||||
}
|
||||
|
||||
public static PrimitiveAdapters<Float> ofFloat() {
|
||||
return ofNumber(Float.class, Number::floatValue, Float::parseFloat);
|
||||
}
|
||||
|
||||
public static PrimitiveAdapters<Float> ofFloatType() {
|
||||
return ofNumber(float.class, Number::floatValue, Float::parseFloat);
|
||||
}
|
||||
|
||||
public static PrimitiveAdapters<Short> ofShort() {
|
||||
return ofNumber(Short.class, Number::shortValue, Short::parseShort);
|
||||
}
|
||||
|
||||
public static PrimitiveAdapters<Short> ofShortType() {
|
||||
return ofNumber(short.class, Number::shortValue, Short::parseShort);
|
||||
}
|
||||
|
||||
public static PrimitiveAdapters<Byte> ofByte() {
|
||||
return ofNumber(Byte.class, Number::byteValue, Byte::parseByte);
|
||||
}
|
||||
|
||||
protected PrimitiveAdapters(Class<T> valueType) {
|
||||
super(Object.class, valueType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object serialize(@NotNull ConfigurationProvider<?> provider, @NotNull T value) throws Exception {
|
||||
return value;
|
||||
public static PrimitiveAdapters<Byte> ofByteType() {
|
||||
return ofNumber(byte.class, Number::byteValue, Byte::parseByte);
|
||||
}
|
||||
|
||||
public static <T> PrimitiveAdapters<T> of(@NotNull Class<T> clazz,
|
||||
@NotNull ConfigDataFunction<Object, T> function) {
|
||||
return new PrimitiveAdapters<T>(clazz) {
|
||||
@Override
|
||||
public T deserialize(@NotNull ConfigurationProvider<?> provider, @NotNull Class<? extends T> clazz, @NotNull Object data) throws Exception {
|
||||
return function.parse(data);
|
||||
}
|
||||
};
|
||||
return new PrimitiveAdapters<>(clazz, (p, type, data) -> function.handle(data));
|
||||
}
|
||||
|
||||
public static <T extends Number> PrimitiveAdapters<T> ofNumber(@NotNull Class<T> numberClass,
|
||||
@NotNull ConfigDataFunction<Number, T> castFunction,
|
||||
@NotNull ConfigDataFunction<String, T> parseFunction) {
|
||||
return of(numberClass, o -> o instanceof Number ? castFunction.parse((Number) o) : parseFunction.parse(o.toString()));
|
||||
return of(numberClass, o -> o instanceof Number ? castFunction.handle((Number) o) : parseFunction.handle(o.toString()));
|
||||
}
|
||||
|
||||
protected PrimitiveAdapters(@NotNull Class<T> valueType, @NotNull ValueParser<T> deserializer) {
|
||||
super(ValueType.of(valueType), (provider, type, value) -> value, deserializer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package cc.carm.lib.configuration.adapter.strandard;
|
||||
|
||||
import cc.carm.lib.configuration.adapter.ValueAdapter;
|
||||
import cc.carm.lib.configuration.adapter.ValueType;
|
||||
import cc.carm.lib.configuration.source.section.ConfigurationSection;
|
||||
|
||||
public interface StandardAdapters {
|
||||
|
||||
ValueAdapter<ConfigurationSection> SECTION_ADAPTER = new ValueAdapter<>(
|
||||
ValueType.of(ConfigurationSection.class),
|
||||
(provider, type, value) -> value,
|
||||
(provider, type, value) -> {
|
||||
if (value instanceof ConfigurationSection) {
|
||||
return (ConfigurationSection) value;
|
||||
} else throw new IllegalArgumentException("Value is not a ConfigurationSection");
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package cc.carm.lib.configuration.annotation;
|
||||
|
||||
import cc.carm.lib.configuration.loader.PathGenerator;
|
||||
import cc.carm.lib.configuration.source.loader.PathGenerator;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package cc.carm.lib.configuration.builder;
|
||||
|
||||
import cc.carm.lib.configuration.source.ConfigurationProvider;
|
||||
import cc.carm.lib.configuration.value.ConfigValue;
|
||||
import cc.carm.lib.configuration.value.ValueManifest;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public abstract class AbstractConfigBuilder<T, B extends AbstractConfigBuilder<T, B, P>, P extends ConfigurationProvider<?>> {
|
||||
|
||||
protected final Class<? super P> providerClass;
|
||||
|
||||
protected @Nullable P provider;
|
||||
protected @Nullable String path;
|
||||
|
||||
protected @NotNull Supplier<T> defaultValueSupplier = () -> null;
|
||||
|
||||
protected AbstractConfigBuilder(Class<? super P> providerClass) {
|
||||
this.providerClass = providerClass;
|
||||
}
|
||||
|
||||
protected abstract @NotNull B self();
|
||||
|
||||
public abstract @NotNull ConfigValue<?> build();
|
||||
|
||||
public @NotNull B from(@Nullable P provider) {
|
||||
this.provider = provider;
|
||||
return self();
|
||||
}
|
||||
|
||||
public @NotNull B path(@Nullable String path) {
|
||||
this.path = path;
|
||||
return self();
|
||||
}
|
||||
|
||||
public @NotNull B defaults(@Nullable T defaultValue) {
|
||||
return defaults(() -> defaultValue);
|
||||
}
|
||||
|
||||
public @NotNull B defaults(@NotNull Supplier<@Nullable T> supplier) {
|
||||
this.defaultValueSupplier = supplier;
|
||||
return self();
|
||||
}
|
||||
|
||||
protected @NotNull ValueManifest<T> buildManifest() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package cc.carm.lib.configuration.builder;
|
||||
|
||||
import cc.carm.lib.configuration.source.ConfigurationProvider;
|
||||
|
||||
public abstract class CommonConfigBuilder<T, B extends CommonConfigBuilder<T, B>>
|
||||
extends AbstractConfigBuilder<T, B, ConfigurationProvider<?>> {
|
||||
|
||||
protected CommonConfigBuilder() {
|
||||
super(ConfigurationProvider.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package cc.carm.lib.configuration.builder.value;
|
||||
|
||||
import cc.carm.lib.configuration.adapter.ValueType;
|
||||
import cc.carm.lib.configuration.function.ConfigDataFunction;
|
||||
import cc.carm.lib.configuration.function.ConfigValueHandler;
|
||||
import cc.carm.lib.configuration.source.section.ConfigurationSection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ConfigValueBuilder<V> {
|
||||
|
||||
protected final @NotNull ValueType<V> type;
|
||||
|
||||
public ConfigValueBuilder(@NotNull ValueType<V> type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public @NotNull <S> SourceValueBuilder<S, V> from(@NotNull Class<S> clazz) {
|
||||
return new SourceValueBuilder<>(ValueType.of(clazz), this.type);
|
||||
}
|
||||
|
||||
public @NotNull <S> SourceValueBuilder<S, V> from(@NotNull ValueType<S> sourceType) {
|
||||
return new SourceValueBuilder<>(sourceType, this.type);
|
||||
}
|
||||
|
||||
public @NotNull <S> SourceValueBuilder<S, V> from(@NotNull ValueType<S> sourceType,
|
||||
@NotNull ConfigValueHandler<S, V> valueParser,
|
||||
@NotNull ConfigValueHandler<V, S> valueSerializer) {
|
||||
return new SourceValueBuilder<>(sourceType, this.type, valueParser, valueSerializer);
|
||||
}
|
||||
|
||||
public @NotNull SourceValueBuilder<String, V> fromString() {
|
||||
return from(String.class);
|
||||
}
|
||||
|
||||
public @NotNull SourceValueBuilder<Integer, V> fromInteger() {
|
||||
return from(Integer.class);
|
||||
}
|
||||
|
||||
public @NotNull SourceValueBuilder<Long, V> fromLong() {
|
||||
return from(Long.class);
|
||||
}
|
||||
|
||||
public @NotNull SourceValueBuilder<Double, V> fromDouble() {
|
||||
return from(Double.class);
|
||||
}
|
||||
|
||||
public @NotNull SourceValueBuilder<Float, V> fromFloat() {
|
||||
return from(Float.class);
|
||||
}
|
||||
|
||||
public @NotNull SourceValueBuilder<Boolean, V> fromBoolean() {
|
||||
return from(Boolean.class);
|
||||
}
|
||||
|
||||
public @NotNull SourceValueBuilder<Character, V> fromCharacter() {
|
||||
return from(Character.class);
|
||||
}
|
||||
|
||||
public @NotNull SourceValueBuilder<Byte, V> fromByte() {
|
||||
return from(Byte.class);
|
||||
}
|
||||
|
||||
public @NotNull SourceValueBuilder<Short, V> fromShort() {
|
||||
return from(Short.class);
|
||||
}
|
||||
|
||||
public @NotNull SectionValueBuilder<V> fromSection() {
|
||||
return new SectionValueBuilder<>(this.type);
|
||||
}
|
||||
|
||||
public @NotNull SectionValueBuilder<V> fromSection(@NotNull ConfigValueHandler<ConfigurationSection, V> valueParser,
|
||||
@NotNull ConfigValueHandler<V, ? extends Map<String, Object>> valueSerializer) {
|
||||
return new SectionValueBuilder<>(this.type, valueParser, valueSerializer);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package cc.carm.lib.configuration.builder.value;
|
||||
|
||||
import cc.carm.lib.configuration.adapter.ValueType;
|
||||
import cc.carm.lib.configuration.builder.CommonConfigBuilder;
|
||||
import cc.carm.lib.configuration.function.ConfigDataFunction;
|
||||
import cc.carm.lib.configuration.function.ConfigValueHandler;
|
||||
import cc.carm.lib.configuration.source.section.ConfigurationSection;
|
||||
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class SectionValueBuilder<V> extends CommonConfigBuilder<V, SectionValueBuilder<V>> {
|
||||
|
||||
protected final @NotNull ValueType<V> valueType;
|
||||
|
||||
protected @NotNull ConfigValueHandler<ConfigurationSection, V> parser;
|
||||
protected @NotNull ConfigValueHandler<V, ? extends Map<String, Object>> serializer;
|
||||
|
||||
public SectionValueBuilder(@NotNull ValueType<V> valueType) {
|
||||
this(valueType, ConfigValueHandler.required(), ConfigValueHandler.required());
|
||||
}
|
||||
|
||||
public SectionValueBuilder(@NotNull ValueType<V> valueType,
|
||||
@NotNull ConfigValueHandler<ConfigurationSection, V> parser,
|
||||
@NotNull ConfigValueHandler<V, ? extends Map<String, Object>> serializer) {
|
||||
this.valueType = valueType;
|
||||
this.parser = parser;
|
||||
this.serializer = serializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull SectionValueBuilder<V> self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull SectionValueBuilder<V> parse(ConfigDataFunction<ConfigurationSection, V> valueParser) {
|
||||
return parse((p, section) -> valueParser.handle(section));
|
||||
}
|
||||
|
||||
public @NotNull SectionValueBuilder<V> parse(ConfigValueHandler<ConfigurationSection, V> valueParser) {
|
||||
this.parser = valueParser;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull SectionValueBuilder<V> serialize(ConfigDataFunction<V, ? extends Map<String, Object>> serializer) {
|
||||
return serialize((p, value) -> serializer.handle(value));
|
||||
}
|
||||
|
||||
public @NotNull SectionValueBuilder<V> serialize(ConfigValueHandler<V, ? extends Map<String, Object>> serializer) {
|
||||
this.serializer = serializer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull SectionValueBuilder<V> serialize(Consumer<Map<String, Object>> serializer) {
|
||||
return serialize((p, value) -> {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
serializer.accept(map);
|
||||
return map;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ConfiguredValue<V> build() {
|
||||
return new ConfiguredValue<>(
|
||||
buildManifest(),
|
||||
(p, type, data) -> {
|
||||
ConfigurationSection section = p.deserialize(ConfigurationSection.class, data);
|
||||
if (section == null) return null;
|
||||
return this.parser.handle(p, section);
|
||||
},
|
||||
(p, type, data) -> {
|
||||
Map<String, Object> map = this.serializer.handle(p, data);
|
||||
return map == null || map.isEmpty() ? null : map; // Map is a type of original data
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package cc.carm.lib.configuration.builder.value;
|
||||
|
||||
import cc.carm.lib.configuration.adapter.ValueType;
|
||||
import cc.carm.lib.configuration.builder.CommonConfigBuilder;
|
||||
import cc.carm.lib.configuration.function.ConfigDataFunction;
|
||||
import cc.carm.lib.configuration.function.ConfigValueHandler;
|
||||
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class SourceValueBuilder<S, V> extends CommonConfigBuilder<V, SourceValueBuilder<S, V>> {
|
||||
|
||||
protected final @NotNull ValueType<S> sourceType;
|
||||
protected final @NotNull ValueType<V> valueType;
|
||||
protected @NotNull ConfigValueHandler<S, V> valueParser;
|
||||
protected @NotNull ConfigValueHandler<V, S> valueSerializer;
|
||||
|
||||
public SourceValueBuilder(@NotNull ValueType<S> sourceType, @NotNull ValueType<V> valueType) {
|
||||
this(sourceType, valueType, ConfigValueHandler.required(), ConfigValueHandler.required());
|
||||
}
|
||||
|
||||
public SourceValueBuilder(@NotNull ValueType<S> sourceType, @NotNull ValueType<V> valueType,
|
||||
@NotNull ConfigValueHandler<S, V> valueParser,
|
||||
@NotNull ConfigValueHandler<V, S> valueSerializer) {
|
||||
this.sourceType = sourceType;
|
||||
this.valueType = valueType;
|
||||
this.valueParser = valueParser;
|
||||
this.valueSerializer = valueSerializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull SourceValueBuilder<S, V> self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull SourceValueBuilder<S, V> parse(ConfigDataFunction<S, V> parser) {
|
||||
return parse((p, source) -> parser.handle(source));
|
||||
}
|
||||
|
||||
public @NotNull SourceValueBuilder<S, V> parse(@NotNull ConfigValueHandler<S, V> parser) {
|
||||
this.valueParser = parser;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull SourceValueBuilder<S, V> serialize(@NotNull ConfigValueHandler<V, S> serializer) {
|
||||
this.valueSerializer = serializer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull SourceValueBuilder<S, V> serialize(@NotNull ConfigDataFunction<V, S> serializer) {
|
||||
return serialize((p, value) -> serializer.handle(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ConfiguredValue<V> build() {
|
||||
return new ConfiguredValue<>(
|
||||
buildManifest(),
|
||||
(p, type, data) -> {
|
||||
S source = p.deserialize(this.sourceType, data);
|
||||
return this.valueParser.handle(p, source);
|
||||
},
|
||||
(p, type, value) -> {
|
||||
S source = this.valueSerializer.handle(p, value);
|
||||
return p.serialize(source);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,11 +9,11 @@ import java.util.Objects;
|
||||
@FunctionalInterface
|
||||
public interface ConfigDataFunction<T, R> {
|
||||
|
||||
@NotNull R parse(@NotNull T data) throws Exception;
|
||||
@NotNull R handle(@NotNull T data) throws Exception;
|
||||
|
||||
default <V> @NotNull ConfigDataFunction<T, V> andThen(@NotNull ConfigDataFunction<? super R, V> after) {
|
||||
Objects.requireNonNull(after);
|
||||
return data -> after.parse(parse(data));
|
||||
return data -> after.handle(handle(data));
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package cc.carm.lib.configuration.function;
|
||||
|
||||
|
||||
import cc.carm.lib.configuration.adapter.ValueType;
|
||||
import cc.carm.lib.configuration.source.ConfigurationProvider;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ConfigValueHandler<T, R> {
|
||||
|
||||
@Nullable R handle(@NotNull ConfigurationProvider<?> provider, @NotNull T data) throws Exception;
|
||||
|
||||
default <V> ConfigValueHandler<T, V> andThen(@NotNull ConfigValueHandler<R, V> after) {
|
||||
Objects.requireNonNull(after);
|
||||
return ((provider, data) -> {
|
||||
R result = handle(provider, data);
|
||||
if (result == null) return null;
|
||||
else return after.handle(provider, result);
|
||||
});
|
||||
}
|
||||
|
||||
default <V> ConfigValueHandler<V, R> compose(@NotNull ConfigValueHandler<? super V, ? extends T> before) {
|
||||
Objects.requireNonNull(before);
|
||||
return ((provider, data) -> {
|
||||
T result = before.handle(provider, data);
|
||||
if (result == null) return null;
|
||||
return handle(provider, result);
|
||||
});
|
||||
}
|
||||
|
||||
default <V> ConfigValueHandler<V, R> compose(@NotNull ConfigDataFunction<? super V, ? extends T> before) {
|
||||
Objects.requireNonNull(before);
|
||||
return ((provider, data) -> {
|
||||
T result = before.handle(data);
|
||||
return handle(provider, result);
|
||||
});
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
static <T> @NotNull ConfigValueHandler<T, T> identity() {
|
||||
return (provider, input) -> input;
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
static <T> @NotNull ConfigValueHandler<T, Object> toObject() {
|
||||
return ConfigurationProvider::serialize;
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
static <T> @NotNull ConfigValueHandler<Object, T> fromObject(ValueType<T> type) {
|
||||
return (provider, input) -> provider.deserialize(type, input);
|
||||
}
|
||||
|
||||
|
||||
@Contract(pure = true)
|
||||
static <T, V> @NotNull ConfigValueHandler<T, V> required() {
|
||||
return (provider, input) -> {
|
||||
throw new IllegalArgumentException("Please specify the value parser.");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
package cc.carm.lib.configuration.function;
|
||||
|
||||
|
||||
import cc.carm.lib.configuration.source.ConfigurationProvider;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ConfigValueParser<T, R> {
|
||||
|
||||
@Nullable R parse(@NotNull ConfigurationProvider<?> provider,
|
||||
@NotNull T data, @Nullable R defaultValue) throws Exception;
|
||||
|
||||
default <V> ConfigValueParser<T, V> andThen(@NotNull ConfigValueParser<R, V> after) {
|
||||
Objects.requireNonNull(after);
|
||||
return ((provider, data, defaultValue) -> {
|
||||
R result = parse(provider, data, null);
|
||||
if (result == null) return defaultValue;
|
||||
else return after.parse(provider, result, defaultValue);
|
||||
});
|
||||
}
|
||||
|
||||
default <V> ConfigValueParser<V, R> compose(@NotNull ConfigValueParser<? super V, ? extends T> before) {
|
||||
Objects.requireNonNull(before);
|
||||
return ((provider, data, defaultValue) -> {
|
||||
T result = before.parse(provider, data, null);
|
||||
if (result == null) return null;
|
||||
return parse(provider, result, defaultValue);
|
||||
});
|
||||
}
|
||||
|
||||
default <V> ConfigValueParser<V, R> compose(@NotNull ConfigDataFunction<? super V, ? extends T> before) {
|
||||
Objects.requireNonNull(before);
|
||||
return ((provider, data, defaultValue) -> {
|
||||
T result = before.parse(data);
|
||||
return parse(provider, result, defaultValue);
|
||||
});
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
static <T> @NotNull ConfigValueParser<T, T> identity() {
|
||||
return (provider, input, defaultValue) -> input;
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
static <T> @NotNull ConfigValueParser<T, Object> toObject() {
|
||||
return (provider, input, defaultValue) -> input;
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
static <T, V> @NotNull ConfigValueParser<T, V> required() {
|
||||
return (provider, input, defaultValue) -> {
|
||||
throw new IllegalArgumentException("Please specify the value parser.");
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package cc.carm.lib.configuration.meta;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class PathMetadata<T> {
|
||||
|
||||
public static <T> PathMetadata<T> of() {
|
||||
return of(() -> null);
|
||||
}
|
||||
|
||||
public static <T> PathMetadata<T> of(T defaults) {
|
||||
return of(() -> defaults);
|
||||
}
|
||||
|
||||
public static <T> PathMetadata<T> of(@NotNull Supplier<@Nullable T> defaults) {
|
||||
return of(v -> defaults.get());
|
||||
}
|
||||
|
||||
public static <T> PathMetadata<T> of(@NotNull Function<String, @Nullable T> defaults) {
|
||||
return new PathMetadata<>(defaults);
|
||||
}
|
||||
|
||||
protected Function<String, @Nullable T> defaultFunction;
|
||||
|
||||
public PathMetadata(@NotNull Function<String, @Nullable T> defaults) {
|
||||
this.defaultFunction = defaults;
|
||||
}
|
||||
|
||||
public boolean isDefault(String path, @NotNull T value) {
|
||||
return value.equals(defaults(path));
|
||||
}
|
||||
|
||||
public boolean hasDefaults(String path) {
|
||||
return defaults(path) != null;
|
||||
}
|
||||
|
||||
public T getDefault(String path, @Nullable T suppliedValue) {
|
||||
T defaults = defaults(path);
|
||||
return defaults == null ? suppliedValue : defaults;
|
||||
}
|
||||
|
||||
public @Nullable T defaults(String path) {
|
||||
return defaultFunction.apply(path);
|
||||
}
|
||||
|
||||
public void setDefaults(Function<String, T> defaultFunction) {
|
||||
this.defaultFunction = defaultFunction;
|
||||
}
|
||||
|
||||
public void setDefaults(T value) {
|
||||
setDefaults((v) -> value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package cc.carm.lib.configuration.option;
|
||||
|
||||
|
||||
import cc.carm.lib.easyoptions.OptionType;
|
||||
|
||||
import static cc.carm.lib.easyoptions.OptionType.of;
|
||||
|
||||
public interface ConfigurationOptions {
|
||||
|
||||
/**
|
||||
* The configuration path separator.
|
||||
*/
|
||||
OptionType<Character> PATH_SEPARATOR = of('.');
|
||||
|
||||
/**
|
||||
* Whether to set & save default values if offered and not exists in configuration.
|
||||
*/
|
||||
OptionType<Boolean> SET_DEFAULTS = of(true);
|
||||
|
||||
/**
|
||||
* Whether to load subclasses of configuration class.
|
||||
*/
|
||||
OptionType<Boolean> LOAD_SUB_CLASSES = of(true);
|
||||
|
||||
}
|
||||
@@ -1,85 +1,84 @@
|
||||
package cc.carm.lib.configuration.source;
|
||||
|
||||
import cc.carm.lib.configuration.adapter.ValueAdapter;
|
||||
import cc.carm.lib.configuration.adapter.ValueAdapterRegistry;
|
||||
import cc.carm.lib.configuration.function.ConfigDataFunction;
|
||||
import cc.carm.lib.configuration.loader.ConfigurationLoader;
|
||||
import cc.carm.lib.configuration.loader.PathGenerator;
|
||||
import cc.carm.lib.easyoptions.OptionHolder;
|
||||
import cc.carm.lib.easyoptions.OptionType;
|
||||
import cc.carm.lib.configuration.source.loader.ConfigurationLoader;
|
||||
import cc.carm.lib.configuration.source.loader.PathGenerator;
|
||||
import cc.carm.lib.configuration.source.option.ConfigurationOption;
|
||||
import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder;
|
||||
import cc.carm.lib.configuration.source.section.ConfigurationSource;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public abstract class ConfigurationFactory<P extends ConfigurationSource<P, ?>, C> {
|
||||
public abstract class ConfigurationFactory<SOURCE extends ConfigurationSource<SOURCE, ?>, PROVIDER extends ConfigurationProvider<SOURCE>, SELF> {
|
||||
|
||||
protected Function<P, ConfigurationLoader> loaderFunction = p -> new ConfigurationLoader();
|
||||
protected Function<PROVIDER, ConfigurationLoader> loaderFunction = PROVIDER -> new ConfigurationLoader();
|
||||
protected Consumer<ConfigurationLoader> loaderConsumer = loader -> {
|
||||
};
|
||||
|
||||
protected ValueAdapterRegistry adapters = new ValueAdapterRegistry();
|
||||
protected OptionHolder options = new OptionHolder();
|
||||
protected ConfigurationOptionHolder options = new ConfigurationOptionHolder();
|
||||
|
||||
public abstract C getThis();
|
||||
public abstract SELF self();
|
||||
|
||||
public C loader(Function<P, ConfigurationLoader> loaderFunction) {
|
||||
public SELF loader(Function<PROVIDER, ConfigurationLoader> loaderFunction) {
|
||||
this.loaderFunction = loaderFunction;
|
||||
return getThis();
|
||||
return self();
|
||||
}
|
||||
|
||||
public C loader(ConfigurationLoader loader) {
|
||||
return loader(p -> loader);
|
||||
public SELF loader(ConfigurationLoader loader) {
|
||||
return loader(PROVIDER -> loader);
|
||||
}
|
||||
|
||||
public C loader(Consumer<ConfigurationLoader> loaderConsumer) {
|
||||
public SELF loader(Consumer<ConfigurationLoader> loaderConsumer) {
|
||||
this.loaderConsumer = this.loaderConsumer.andThen(loaderConsumer);
|
||||
return getThis();
|
||||
return self();
|
||||
}
|
||||
|
||||
public C pathGenerator(PathGenerator pathGenerator) {
|
||||
public SELF pathGenerator(PathGenerator pathGenerator) {
|
||||
return loader(loader -> {
|
||||
loader.setPathGenerator(pathGenerator);
|
||||
});
|
||||
}
|
||||
|
||||
public C adapters(ValueAdapterRegistry adapters) {
|
||||
public SELF adapters(ValueAdapterRegistry adapters) {
|
||||
this.adapters = adapters;
|
||||
return getThis();
|
||||
return self();
|
||||
}
|
||||
|
||||
public C adapter(Consumer<ValueAdapterRegistry> adapterRegistryConsumer) {
|
||||
public SELF adapter(Consumer<ValueAdapterRegistry> adapterRegistryConsumer) {
|
||||
adapterRegistryConsumer.accept(adapters);
|
||||
return getThis();
|
||||
return self();
|
||||
}
|
||||
|
||||
public C adapter(@NotNull ValueAdapter<?, ?> adapter) {
|
||||
return adapter(a -> a.register(adapter));
|
||||
}
|
||||
// public SELF adapter(@NotNull ValueAdapter<?, ?> adapter) {
|
||||
// return adapter(a -> a.register(adapter));
|
||||
// }
|
||||
//
|
||||
// public <T> SELF adapter(Class<T> clazz, @NotNull ValueAdapter<?, T> adapter) {
|
||||
// return adapter(a -> a.register(clazz, adapter));
|
||||
// }
|
||||
//
|
||||
// public <B, V> SELF adapter(Class<B> baseClass, Class<V> valueClass,
|
||||
// ConfigDataFunction<B, V> parser, ConfigDataFunction<V, B> serializer) {
|
||||
// return adapter(a -> a.register(baseClass, valueClass, parser, serializer));
|
||||
// }
|
||||
|
||||
public <T> C adapter(Class<T> clazz, @NotNull ValueAdapter<?, T> adapter) {
|
||||
return adapter(a -> a.register(clazz, adapter));
|
||||
}
|
||||
|
||||
public <B, V> C adapter(Class<B> baseClass, Class<V> valueClass,
|
||||
ConfigDataFunction<B, V> parser, ConfigDataFunction<V, B> serializer) {
|
||||
return adapter(a -> a.register(baseClass, valueClass, parser, serializer));
|
||||
}
|
||||
|
||||
public C options(OptionHolder options) {
|
||||
public SELF options(ConfigurationOptionHolder options) {
|
||||
this.options = options;
|
||||
return getThis();
|
||||
return self();
|
||||
}
|
||||
|
||||
public C option(Consumer<OptionHolder> optionsConsumer) {
|
||||
public SELF option(Consumer<ConfigurationOptionHolder> optionsConsumer) {
|
||||
optionsConsumer.accept(options);
|
||||
return getThis();
|
||||
return self();
|
||||
}
|
||||
|
||||
public <O> C option(OptionType<O> option, O value) {
|
||||
public <O> SELF option(ConfigurationOption<O> option, O value) {
|
||||
return option(o -> o.set(option, value));
|
||||
}
|
||||
|
||||
public abstract @NotNull P build();
|
||||
public abstract @NotNull PROVIDER build();
|
||||
|
||||
}
|
||||
|
||||
@@ -2,24 +2,36 @@ package cc.carm.lib.configuration.source;
|
||||
|
||||
import cc.carm.lib.configuration.Configuration;
|
||||
import cc.carm.lib.configuration.adapter.ValueAdapterRegistry;
|
||||
import cc.carm.lib.configuration.loader.ConfigurationLoader;
|
||||
import cc.carm.lib.easyoptions.OptionHolder;
|
||||
import cc.carm.lib.easyoptions.OptionType;
|
||||
import cc.carm.lib.configuration.adapter.ValueType;
|
||||
import cc.carm.lib.configuration.meta.PathMetadata;
|
||||
import cc.carm.lib.configuration.source.loader.ConfigurationLoader;
|
||||
import cc.carm.lib.configuration.source.option.ConfigurationOption;
|
||||
import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder;
|
||||
import cc.carm.lib.configuration.source.section.ConfigurationSource;
|
||||
import cc.carm.lib.configuration.value.ValueManifest;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ConfigurationProvider<S extends ConfigurationSource<S, ?>> {
|
||||
|
||||
protected final @NotNull S source;
|
||||
protected final @NotNull ConfigurationLoader loader;
|
||||
protected final @NotNull ValueAdapterRegistry adapters;
|
||||
protected final @NotNull OptionHolder options;
|
||||
protected final @NotNull ConfigurationOptionHolder options;
|
||||
protected final @NotNull Map<String, Map<PathMetadata<?>, Object>> pathMetadata;
|
||||
|
||||
public ConfigurationProvider(@NotNull S source, @NotNull ConfigurationLoader loader,
|
||||
@NotNull ValueAdapterRegistry adapters, @NotNull OptionHolder options) {
|
||||
@NotNull ValueAdapterRegistry adapters,
|
||||
@NotNull ConfigurationOptionHolder options,
|
||||
@NotNull Map<String, Map<PathMetadata<?>, Object>> pathMetadata) {
|
||||
this.source = source;
|
||||
this.loader = loader;
|
||||
this.adapters = adapters;
|
||||
this.options = options;
|
||||
this.pathMetadata = pathMetadata;
|
||||
}
|
||||
|
||||
public @NotNull S source() {
|
||||
@@ -34,15 +46,15 @@ public class ConfigurationProvider<S extends ConfigurationSource<S, ?>> {
|
||||
source().save();
|
||||
}
|
||||
|
||||
public OptionHolder options() {
|
||||
public ConfigurationOptionHolder options() {
|
||||
return options;
|
||||
}
|
||||
|
||||
public <T> @NotNull T option(@NotNull OptionType<T> option) {
|
||||
public <T> @NotNull T option(@NotNull ConfigurationOption<T> option) {
|
||||
return options.get(option);
|
||||
}
|
||||
|
||||
public <T> void option(@NotNull OptionType<T> option, @NotNull T value) {
|
||||
public <T> void option(@NotNull ConfigurationOption<T> option, @NotNull T value) {
|
||||
options.set(option, value);
|
||||
}
|
||||
|
||||
@@ -50,11 +62,117 @@ public class ConfigurationProvider<S extends ConfigurationSource<S, ?>> {
|
||||
return this.adapters;
|
||||
}
|
||||
|
||||
|
||||
public ConfigurationLoader loader() {
|
||||
return loader;
|
||||
}
|
||||
|
||||
public @NotNull Map<String, Map<PathMetadata<?>, Object>> pathMetadata() {
|
||||
return pathMetadata;
|
||||
}
|
||||
|
||||
public @NotNull Map<PathMetadata<?>, Object> metadata(@NotNull String path) {
|
||||
return pathMetadata().computeIfAbsent(path, k -> new java.util.HashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of option.
|
||||
*
|
||||
* @param type {@link PathMetadata}
|
||||
* @param defaultValue Default value if the value of option is not set.
|
||||
* @param <V> Value type
|
||||
* @return Value of option
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Contract("_,_, !null -> !null")
|
||||
public <V> @Nullable V meta(@NotNull String path,
|
||||
@NotNull PathMetadata<V> type, @Nullable V defaultValue) {
|
||||
return (V) metadata(path).getOrDefault(type, type.getDefault(path, defaultValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of option.
|
||||
*
|
||||
* @param type {@link PathMetadata}
|
||||
* @param <V> Value type
|
||||
* @return Value of option
|
||||
*/
|
||||
public <V> @Nullable V meta(@NotNull String path, @NotNull PathMetadata<V> type) {
|
||||
return meta(path, type, null);
|
||||
}
|
||||
|
||||
public boolean hasMeta(@NotNull String path, @NotNull PathMetadata<?> type) {
|
||||
return metadata(path).containsKey(type) || type.hasDefaults(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of meta, if the value is null, the meta will be removed.
|
||||
* <br> Will only be changed in current holder.
|
||||
*
|
||||
* @param type {@link PathMetadata}
|
||||
* @param value Value of meta
|
||||
* @param <V> Value type
|
||||
* @return Previous value of meta
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V> @Nullable V setMeta(@NotNull String path, @NotNull PathMetadata<V> type, @Nullable V value) {
|
||||
if (value == null || type.isDefault(path, value)) {
|
||||
return (V) metadata(path).remove(type);
|
||||
} else {
|
||||
return (V) metadata(path).put(type, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of meta, if the value is null, the meta will not be changed.
|
||||
* <br> Will only be changed in current holder.
|
||||
*
|
||||
* @param type {@link PathMetadata}
|
||||
* @param value Value of meta
|
||||
* @param <V> Value type
|
||||
*/
|
||||
public <V> void setMetaIfAbsent(@NotNull String path, @NotNull PathMetadata<V> type, @Nullable V value) {
|
||||
if (value == null || type.isDefault(path, value)) {
|
||||
metadata(path).remove(type);
|
||||
} else {
|
||||
metadata(path).putIfAbsent(type, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of meta, if the value is null, the meta will not be changed.
|
||||
* <br> Will only be changed in current holder.
|
||||
*
|
||||
* @param type {@link PathMetadata}
|
||||
* @param value Value of meta
|
||||
* @param <V> Value type
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V> @Nullable V setMetaIfPresent(@NotNull String path, @NotNull PathMetadata<V> type, @Nullable V value) {
|
||||
Object exists = metadata(path).get(type);
|
||||
if (exists == null) return null;
|
||||
|
||||
if (value == null || type.isDefault(path, value)) {
|
||||
return (V) metadata(path).remove(type);
|
||||
} else {
|
||||
return (V) metadata(path).put(type, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Contract("_,null -> null")
|
||||
public <T> T deserialize(@NotNull Class<T> type, @Nullable Object source) throws Exception {
|
||||
return adapters().deserialize(this, type, source);
|
||||
}
|
||||
|
||||
@Contract("_,null -> null")
|
||||
public <T> T deserialize(@NotNull ValueType<T> type, @Nullable Object source) throws Exception {
|
||||
return adapters().deserialize(this, type, source);
|
||||
}
|
||||
|
||||
@Contract("null -> null")
|
||||
public <T> Object serialize(@Nullable T value) throws Exception {
|
||||
return adapters().serialize(this, value);
|
||||
}
|
||||
|
||||
public void load(Class<? extends Configuration> configClass) {
|
||||
try {
|
||||
loader.load(this, configClass);
|
||||
@@ -71,4 +189,8 @@ public class ConfigurationProvider<S extends ConfigurationSource<S, ?>> {
|
||||
}
|
||||
}
|
||||
|
||||
public void load(@NotNull ValueManifest<?> value) {
|
||||
value.provider(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+37
-11
@@ -1,11 +1,14 @@
|
||||
package cc.carm.lib.configuration.loader;
|
||||
package cc.carm.lib.configuration.source.loader;
|
||||
|
||||
import cc.carm.lib.configuration.Configuration;
|
||||
import cc.carm.lib.configuration.source.ConfigurationProvider;
|
||||
import cc.carm.lib.configuration.option.ConfigurationOptions;
|
||||
import cc.carm.lib.configuration.source.option.ConfigurationOptions;
|
||||
import cc.carm.lib.configuration.value.ConfigValue;
|
||||
import cc.carm.lib.configuration.value.ValueManifest;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -15,6 +18,20 @@ import java.util.Arrays;
|
||||
*/
|
||||
public class ConfigurationLoader {
|
||||
|
||||
public static final Field PATH_FIELD;
|
||||
public static final Field PROVIDER_FIELD;
|
||||
|
||||
static {
|
||||
try {
|
||||
PATH_FIELD = ValueManifest.class.getDeclaredField("path");
|
||||
PATH_FIELD.setAccessible(true);
|
||||
PROVIDER_FIELD = ValueManifest.class.getDeclaredField("provider");
|
||||
PROVIDER_FIELD.setAccessible(true);
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected PathGenerator pathGenerator;
|
||||
|
||||
public ConfigurationLoader() {
|
||||
@@ -83,13 +100,15 @@ public class ConfigurationLoader {
|
||||
field.setAccessible(true);
|
||||
Object object = field.get(source);
|
||||
//
|
||||
// if (object instanceof ConfigValue<?>) {
|
||||
// // 目标是 ConfigValue 实例,进行具体的初始化注入
|
||||
//
|
||||
// } else
|
||||
|
||||
if (source instanceof Configuration && object instanceof Configuration) {
|
||||
// 当且仅当 源字段与字段 均为ConfigurationRoot实例时,才对目标字段进行下一步初始化加载。
|
||||
if (object instanceof ConfigValue<?>) {
|
||||
// 目标是 ConfigValue 实例,进行具体的初始化注入
|
||||
ConfigValue<?> value = (ConfigValue<?>) object;
|
||||
String path = getFieldPath(provider, parent, field);
|
||||
if (path == null) return;
|
||||
insertIfAbsent(value, PATH_FIELD, path);
|
||||
insertIfAbsent(value, PROVIDER_FIELD, provider);
|
||||
} else if (source instanceof Configuration && object instanceof Configuration) {
|
||||
// 当且仅当 源字段与字段 均为Configuration实例时,才对目标字段进行下一步初始化加载。
|
||||
initializeInstance(provider, (Configuration) object, parent, field);
|
||||
} else if (source instanceof Class<?> && object instanceof Class<?>) {
|
||||
// 当且仅当 源字段与字段 均为静态类时,才对目标字段进行下一步初始化加载。
|
||||
@@ -97,11 +116,18 @@ public class ConfigurationLoader {
|
||||
}
|
||||
|
||||
// 以上判断实现以下规范:
|
||||
// - 实例类中仅加载 ConfigValue实例 与 ConfigurationRoot实例
|
||||
// - 静态类中仅加载 静态ConfigValue实例 与 静态ConfigurationRoot类
|
||||
// - 实例类中仅加载 ConfigValue实例 与 Configuration实例
|
||||
// - 静态类中仅加载 静态ConfigValue实例 与 静态Configuration类
|
||||
|
||||
} catch (IllegalAccessException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private void insertIfAbsent(@NotNull ValueManifest<?> value, @NotNull Field field, @NotNull Object obj) {
|
||||
try {
|
||||
if (field.get(obj) == null) field.set(obj, value);
|
||||
} catch (IllegalAccessException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package cc.carm.lib.configuration.loader;
|
||||
package cc.carm.lib.configuration.source.loader;
|
||||
|
||||
import cc.carm.lib.configuration.source.ConfigurationProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
package cc.carm.lib.configuration.loader;
|
||||
package cc.carm.lib.configuration.source.loader;
|
||||
|
||||
import cc.carm.lib.configuration.annotation.ConfigPath;
|
||||
import cc.carm.lib.configuration.source.ConfigurationProvider;
|
||||
import cc.carm.lib.configuration.option.ConfigurationOptions;
|
||||
import cc.carm.lib.configuration.source.option.ConfigurationOptions;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package cc.carm.lib.configuration.source.option;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ConfigurationOption<V> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> ConfigurationOption<T> of(@NotNull T defaultValue) {
|
||||
return of((Class<T>) defaultValue.getClass(), defaultValue);
|
||||
}
|
||||
|
||||
public static <T> ConfigurationOption<T> of(@NotNull Class<T> valueClazz, @NotNull T defaultValue) {
|
||||
return new ConfigurationOption<>(valueClazz, defaultValue);
|
||||
}
|
||||
|
||||
private final @NotNull Class<V> valueClazz;
|
||||
private @NotNull V defaultValue;
|
||||
|
||||
public ConfigurationOption(@NotNull Class<V> valueClazz, @NotNull V defaultValue) {
|
||||
this.valueClazz = valueClazz;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Class<V> valueClass() {
|
||||
return this.valueClazz;
|
||||
}
|
||||
|
||||
public @NotNull V defaults() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default value of option.
|
||||
*
|
||||
* @param defaultValue Default value
|
||||
*/
|
||||
public void defaults(@NotNull V defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public boolean isDefault(@NotNull V value) {
|
||||
return value.equals(defaultValue);
|
||||
}
|
||||
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
package cc.carm.lib.configuration.source.option;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class ConfigurationOptionHolder {
|
||||
|
||||
public static <V> @NotNull ConfigurationOptionHolder of(@NotNull Map<ConfigurationOption<V>, V> options) {
|
||||
return new ConfigurationOptionHolder(new ConcurrentHashMap<>(options));
|
||||
}
|
||||
|
||||
protected final Map<ConfigurationOption<?>, Object> options;
|
||||
|
||||
public ConfigurationOptionHolder() {
|
||||
this(new ConcurrentHashMap<>());
|
||||
}
|
||||
|
||||
public ConfigurationOptionHolder(Map<ConfigurationOption<?>, Object> options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public @NotNull Map<ConfigurationOption<?>, Object> options() {
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of option.
|
||||
*
|
||||
* @param type {@link ConfigurationOption}
|
||||
* @param <V> Value type
|
||||
* @return Value of option
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V> @NotNull V get(@NotNull ConfigurationOption<V> type) {
|
||||
return Optional.ofNullable(options().get(type)).map(v -> (V) v).orElseGet(type::defaults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of option.
|
||||
*
|
||||
* @param type {@link ConfigurationOption}
|
||||
* @param value Value of option
|
||||
* @param <V> Value type
|
||||
* @return Previous value of option
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V> @Nullable V set(@NotNull ConfigurationOption<V> type, @Nullable V value) {
|
||||
if (value == null) {
|
||||
return (V) options().remove(type);
|
||||
} else {
|
||||
return (V) options().put(type, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of option to option's {@link ConfigurationOption#defaults()}.
|
||||
*
|
||||
* @param type {@link ConfigurationOption}
|
||||
* @param <V> Value type
|
||||
* @return Previous value of option
|
||||
*/
|
||||
public <V> @Nullable V clear(@NotNull ConfigurationOption<V> type) {
|
||||
return set(type, null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package cc.carm.lib.configuration.source.option;
|
||||
|
||||
import cc.carm.lib.configuration.Configuration;
|
||||
|
||||
import static cc.carm.lib.configuration.source.option.ConfigurationOption.of;
|
||||
|
||||
public interface ConfigurationOptions {
|
||||
|
||||
/**
|
||||
* The configuration path separator.
|
||||
*/
|
||||
ConfigurationOption<Character> PATH_SEPARATOR = of('.');
|
||||
|
||||
/**
|
||||
* Whether to set & save default values if offered and not exists in configuration.
|
||||
*/
|
||||
ConfigurationOption<Boolean> SET_DEFAULTS = of(true);
|
||||
|
||||
/**
|
||||
* Whether to load subclasses of configuration class.
|
||||
*/
|
||||
ConfigurationOption<Boolean> LOAD_SUB_CLASSES = of(true);
|
||||
|
||||
/**
|
||||
* Whether to pre parse the config values.
|
||||
* <br> if false, the values will be parsed when calling
|
||||
* {@link cc.carm.lib.configuration.value.ConfigValue#get()}
|
||||
* <br> if true, the values will be parsed when
|
||||
* {@link cc.carm.lib.configuration.source.ConfigurationProvider#load(Configuration)}.
|
||||
*/
|
||||
ConfigurationOption<Boolean> PRELOAD = of(false);
|
||||
|
||||
}
|
||||
+16
-15
@@ -1,7 +1,6 @@
|
||||
package cc.carm.lib.configuration.source;
|
||||
package cc.carm.lib.configuration.source.section;
|
||||
|
||||
import cc.carm.lib.configuration.function.ConfigDataFunction;
|
||||
import cc.carm.lib.configuration.function.ConfigValueParser;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -12,7 +11,9 @@ import java.util.*;
|
||||
public interface ConfigurationSection {
|
||||
|
||||
@NotNull
|
||||
Set<String> getKeys(boolean deep);
|
||||
default Set<String> getKeys(boolean deep) {
|
||||
return getValues(deep).keySet();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
Map<String, Object> getValues(boolean deep);
|
||||
@@ -40,22 +41,22 @@ public interface ConfigurationSection {
|
||||
return get(path, null, clazz);
|
||||
}
|
||||
|
||||
default @Nullable <T> T get(@NotNull String path, @NotNull ConfigValueParser<Object, T> parser) {
|
||||
default @Nullable <T> T get(@NotNull String path, @NotNull ConfigDataFunction<Object, T> parser) {
|
||||
return get(path, null, parser);
|
||||
}
|
||||
|
||||
@Contract("_,!null,_->!null")
|
||||
default @Nullable <T> T get(@NotNull String path, @Nullable T defaultValue, @NotNull Class<T> clazz) {
|
||||
return get(path, defaultValue, ConfigValueParser.castObject(clazz));
|
||||
return get(path, defaultValue, ConfigDataFunction.castObject(clazz));
|
||||
}
|
||||
|
||||
@Contract("_,!null,_->!null")
|
||||
default @Nullable <T> T get(@NotNull String path, @Nullable T defaultValue,
|
||||
@NotNull ConfigValueParser<Object, T> parser) {
|
||||
@NotNull ConfigDataFunction<Object, T> parser) {
|
||||
Object value = get(path);
|
||||
if (value != null) {
|
||||
try {
|
||||
return parser.parse(value, defaultValue);
|
||||
return parser.handle(value);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -74,7 +75,7 @@ public interface ConfigurationSection {
|
||||
|
||||
@Contract("_, !null -> !null")
|
||||
default @Nullable Boolean getBoolean(@NotNull String path, @Nullable Boolean def) {
|
||||
return get(path, def, ConfigValueParser.booleanValue());
|
||||
return get(path, def, ConfigDataFunction.booleanValue());
|
||||
}
|
||||
|
||||
default @Nullable Boolean isByte(@NotNull String path) {
|
||||
@@ -87,7 +88,7 @@ public interface ConfigurationSection {
|
||||
|
||||
@Contract("_, !null -> !null")
|
||||
default @Nullable Byte getByte(@NotNull String path, @Nullable Byte def) {
|
||||
return get(path, def, ConfigValueParser.byteValue());
|
||||
return get(path, def, ConfigDataFunction.byteValue());
|
||||
}
|
||||
|
||||
default boolean isShort(@NotNull String path) {
|
||||
@@ -100,7 +101,7 @@ public interface ConfigurationSection {
|
||||
|
||||
@Contract("_, !null -> !null")
|
||||
default @Nullable Short getShort(@NotNull String path, @Nullable Short def) {
|
||||
return get(path, def, ConfigValueParser.shortValue());
|
||||
return get(path, def, ConfigDataFunction.shortValue());
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +115,7 @@ public interface ConfigurationSection {
|
||||
|
||||
@Contract("_, !null -> !null")
|
||||
default @Nullable Integer getInt(@NotNull String path, @Nullable Integer def) {
|
||||
return get(path, def, ConfigValueParser.intValue());
|
||||
return get(path, def, ConfigDataFunction.intValue());
|
||||
}
|
||||
|
||||
|
||||
@@ -128,7 +129,7 @@ public interface ConfigurationSection {
|
||||
|
||||
@Contract("_, !null -> !null")
|
||||
default @Nullable Long getLong(@NotNull String path, @Nullable Long def) {
|
||||
return get(path, def, ConfigValueParser.longValue());
|
||||
return get(path, def, ConfigDataFunction.longValue());
|
||||
}
|
||||
|
||||
|
||||
@@ -142,7 +143,7 @@ public interface ConfigurationSection {
|
||||
|
||||
@Contract("_, !null -> !null")
|
||||
default @Nullable Float getFloat(@NotNull String path, @Nullable Float def) {
|
||||
return get(path, def, ConfigValueParser.floatValue());
|
||||
return get(path, def, ConfigDataFunction.floatValue());
|
||||
}
|
||||
|
||||
|
||||
@@ -156,7 +157,7 @@ public interface ConfigurationSection {
|
||||
|
||||
@Contract("_, !null -> !null")
|
||||
default @Nullable Double getDouble(@NotNull String path, @Nullable Double def) {
|
||||
return get(path, def, ConfigValueParser.doubleValue());
|
||||
return get(path, def, ConfigDataFunction.doubleValue());
|
||||
}
|
||||
|
||||
|
||||
@@ -232,7 +233,7 @@ public interface ConfigurationSection {
|
||||
List<T> values = new ArrayList<>();
|
||||
for (Object o : list) {
|
||||
try {
|
||||
values.add(parser.parse(o));
|
||||
values.add(parser.handle(o));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
+11
-14
@@ -1,10 +1,9 @@
|
||||
package cc.carm.lib.configuration.source;
|
||||
package cc.carm.lib.configuration.source.section;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public abstract class ConfigurationSource<S extends ConfigurationSource<S, O>, O> implements ConfigurationSection {
|
||||
public abstract class ConfigurationSource<SELF extends ConfigurationSource<SELF, ORIGINAL>, ORIGINAL>
|
||||
implements ConfigurationSection {
|
||||
|
||||
protected long updateMillis;
|
||||
|
||||
@@ -17,25 +16,23 @@ public abstract class ConfigurationSource<S extends ConfigurationSource<S, O>, O
|
||||
this.updateMillis = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
protected abstract S getThis();
|
||||
protected abstract SELF self();
|
||||
|
||||
/**
|
||||
* @return Original configuration object
|
||||
*/
|
||||
public abstract @NotNull ORIGINAL original();
|
||||
|
||||
public abstract void save() throws Exception;
|
||||
|
||||
protected abstract void onReload() throws Exception;
|
||||
|
||||
public abstract @NotNull O original();
|
||||
|
||||
@NotNull
|
||||
public Set<String> getKeys(boolean deep) {
|
||||
return getValues(deep).keySet();
|
||||
}
|
||||
|
||||
public long getUpdateMillis() {
|
||||
return this.updateMillis;
|
||||
}
|
||||
|
||||
public boolean isExpired(long time) {
|
||||
return getUpdateMillis() > time;
|
||||
public boolean isExpired(long parsedTime) {
|
||||
return getUpdateMillis() > parsedTime;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,12 +9,8 @@ import java.util.Optional;
|
||||
|
||||
public abstract class ConfigValue<T> extends ValueManifest<T> {
|
||||
|
||||
// public static @NotNull ConfigBuilder builder() {
|
||||
// return new ConfigBuilder();
|
||||
// }
|
||||
|
||||
protected ConfigValue(@NotNull ValueManifest<T> manifest) {
|
||||
super(manifest.metadata, manifest.provider, manifest.defaultSupplier);
|
||||
super(manifest.type, manifest.provider, manifest.path, manifest.defaultSupplier);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,7 +37,7 @@ public abstract class ConfigValue<T> extends ValueManifest<T> {
|
||||
* @throws NullPointerException 对应数据为空时抛出
|
||||
*/
|
||||
public @NotNull T getNotNull() {
|
||||
return Objects.requireNonNull(getOrDefault(), "Value(" + path() + ") is null.");
|
||||
return Objects.requireNonNull(getOrDefault(), "Value(" + path() + ") [" + type() + "] is null.");
|
||||
}
|
||||
|
||||
public @NotNull Optional<@Nullable T> optional() {
|
||||
|
||||
@@ -1,30 +1,56 @@
|
||||
package cc.carm.lib.configuration.value;
|
||||
|
||||
import cc.carm.lib.configuration.adapter.ValueType;
|
||||
import cc.carm.lib.configuration.source.ConfigurationProvider;
|
||||
import cc.carm.lib.configuration.source.ConfigurationSource;
|
||||
import cc.carm.lib.configuration.value.meta.ValueMetaList;
|
||||
import cc.carm.lib.configuration.value.meta.ValueMetaType;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import cc.carm.lib.configuration.source.section.ConfigurationSource;
|
||||
import cc.carm.lib.configuration.meta.PathMetadata;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ValueManifest<T> {
|
||||
|
||||
protected final @NotNull Map<ValueMetaType<?>, Object> metadata;
|
||||
protected final @NotNull ValueType<T> type;
|
||||
protected @Nullable ConfigurationProvider<?> provider;
|
||||
protected @Nullable String path; // Section path
|
||||
|
||||
protected @NotNull Supplier<@Nullable T> defaultSupplier;
|
||||
|
||||
public ValueManifest(@NotNull Map<ValueMetaType<?>, Object> metadata,
|
||||
@Nullable ConfigurationProvider<?> provider, @NotNull Supplier<@Nullable T> defaultSupplier) {
|
||||
this.metadata = metadata;
|
||||
public ValueManifest(ValueType<T> type) {
|
||||
this(type, null, null, () -> null);
|
||||
}
|
||||
|
||||
public ValueManifest(@NotNull T defaultValue) {
|
||||
this(ValueType.of(defaultValue), null, null, () -> defaultValue);
|
||||
}
|
||||
|
||||
public ValueManifest(@NotNull ValueType<T> type, @NotNull Supplier<@Nullable T> defaultSupplier) {
|
||||
this(type, null, null, defaultSupplier);
|
||||
}
|
||||
|
||||
public ValueManifest(@NotNull ValueType<T> type,
|
||||
@Nullable ConfigurationProvider<?> provider, @Nullable String path,
|
||||
@NotNull Supplier<@Nullable T> defaultSupplier) {
|
||||
this.type = type;
|
||||
this.provider = provider;
|
||||
this.path = path;
|
||||
this.defaultSupplier = defaultSupplier;
|
||||
}
|
||||
|
||||
public @NotNull ValueType<T> type() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public void provider(@NotNull ConfigurationProvider<?> provider) {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
public void path(@NotNull String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public @Nullable T defaults() {
|
||||
return this.defaultSupplier.get();
|
||||
}
|
||||
@@ -37,6 +63,15 @@ public class ValueManifest<T> {
|
||||
this.defaultSupplier = defaultValue;
|
||||
}
|
||||
|
||||
public boolean hasDefaults() {
|
||||
return this.defaultSupplier.get() != null;
|
||||
}
|
||||
|
||||
public @NotNull String path() {
|
||||
if (path != null) return path;
|
||||
else throw new IllegalStateException("No section path provided.");
|
||||
}
|
||||
|
||||
public @NotNull ConfigurationProvider<?> provider() {
|
||||
if (this.provider != null) return this.provider;
|
||||
throw new IllegalStateException("Value does not have a provider.");
|
||||
@@ -46,106 +81,16 @@ public class ValueManifest<T> {
|
||||
return provider().source();
|
||||
}
|
||||
|
||||
public @NotNull String path() {
|
||||
String path = getMeta(ValueMetaList.PATH);
|
||||
if (path != null) return path;
|
||||
else throw new IllegalStateException("No section path provided.");
|
||||
}
|
||||
|
||||
protected Object getValue() {
|
||||
protected Object getData() {
|
||||
return config().get(path());
|
||||
}
|
||||
|
||||
protected void setValue(@Nullable Object value) {
|
||||
protected void setData(@Nullable Object value) {
|
||||
config().set(path(), value);
|
||||
}
|
||||
|
||||
public Map<ValueMetaType<?>, Object> metadata() {
|
||||
return metadata;
|
||||
public Map<PathMetadata<?>, Object> metadata() {
|
||||
return provider().metadata(path());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of option.
|
||||
*
|
||||
* @param type {@link ValueMetaType}
|
||||
* @param defaultValue Default value if the value of option is not set.
|
||||
* @param <V> Value type
|
||||
* @return Value of option
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Contract("_, !null -> !null")
|
||||
public <V> @Nullable V getMeta(@NotNull ValueMetaType<V> type, @Nullable V defaultValue) {
|
||||
return (V) metadata().getOrDefault(type, type.getDefault(this, defaultValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of option.
|
||||
*
|
||||
* @param type {@link ValueMetaType}
|
||||
* @param <V> Value type
|
||||
* @return Value of option
|
||||
*/
|
||||
public <V> @Nullable V getMeta(@NotNull ValueMetaType<V> type) {
|
||||
return getMeta(type, null);
|
||||
}
|
||||
|
||||
public boolean hasMeta(@NotNull ValueMetaType<?> type) {
|
||||
return metadata().containsKey(type) || type.hasDefaults(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of meta, if the value is null, the meta will be removed.
|
||||
* <br> Will only be changed in current holder.
|
||||
*
|
||||
* @param type {@link ValueMetaType}
|
||||
* @param value Value of meta
|
||||
* @param <V> Value type
|
||||
* @return Previous value of meta
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V> @Nullable V setMeta(@NotNull ValueMetaType<V> type, @Nullable V value) {
|
||||
if (value == null || type.isDefault(this, value)) {
|
||||
return (V) metadata().remove(type);
|
||||
} else {
|
||||
return (V) metadata().put(type, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of meta, if the value is null, the meta will not be changed.
|
||||
* <br> Will only be changed in current holder.
|
||||
*
|
||||
* @param type {@link ValueMetaType}
|
||||
* @param value Value of meta
|
||||
* @param <V> Value type
|
||||
*/
|
||||
public <V> void setMetaIfAbsent(@NotNull ValueMetaType<V> type, @Nullable V value) {
|
||||
if (value == null || type.isDefault(this, value)) {
|
||||
metadata().remove(type);
|
||||
} else {
|
||||
metadata().putIfAbsent(type, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of meta, if the value is null, the meta will not be changed.
|
||||
* <br> Will only be changed in current holder.
|
||||
*
|
||||
* @param type {@link ValueMetaType}
|
||||
* @param value Value of meta
|
||||
* @param <V> Value type
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V> @Nullable V setMetaIfPresent(@NotNull ValueMetaType<V> type, @Nullable V value) {
|
||||
Object exists = metadata().get(type);
|
||||
if (exists == null) return null;
|
||||
|
||||
if (value == null || type.isDefault(this, value)) {
|
||||
return (V) metadata().remove(type);
|
||||
} else {
|
||||
return (V) metadata().put(type, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public abstract class CachedConfigValue<T> extends ConfigValue<T> {
|
||||
|
||||
|
||||
protected @Nullable T cachedValue;
|
||||
protected long parsedTime = -1;
|
||||
|
||||
@@ -30,13 +30,24 @@ public abstract class CachedConfigValue<T> extends ConfigValue<T> {
|
||||
}
|
||||
|
||||
protected final T getDefaultFirst(@Nullable T value) {
|
||||
return updateCache(this.defaultSupplier == null ? value : this.defaultSupplier);
|
||||
return updateCache(this.defaults() == null ? value : this.defaults());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cached value or the default value if the cached value is null
|
||||
*
|
||||
* @return the cached value or the default value
|
||||
*/
|
||||
protected @Nullable T getCachedOrDefault() {
|
||||
return getCachedOrDefault(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cached value or the default value if the cached value is null
|
||||
*
|
||||
* @param emptyValue the value to return if the cached value and the default value are null
|
||||
* @return the cached value or the default value
|
||||
*/
|
||||
@Contract("!null->!null")
|
||||
protected T getCachedOrDefault(@Nullable T emptyValue) {
|
||||
if (getCachedValue() != null) return getCachedValue();
|
||||
|
||||
@@ -1,213 +0,0 @@
|
||||
//package cc.carm.lib.configuration.value.impl;
|
||||
//
|
||||
//import cc.carm.lib.configuration.builder.map.ConfigMapCreator;
|
||||
//import cc.carm.lib.configuration.function.ConfigDataFunction;
|
||||
//import cc.carm.lib.configuration.value.ValueManifest;
|
||||
//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 abstract class ConfigValueMap<K, V, S> extends CachedConfigValue<Map<K, V>> implements Map<K, V> {
|
||||
//
|
||||
// public static <K, V> @NotNull ConfigMapCreator<K, V> builderOf(@NotNull Class<K> keyClass,
|
||||
// @NotNull Class<V> valueClass) {
|
||||
// return builder().asMap(keyClass, valueClass);
|
||||
// }
|
||||
//
|
||||
// protected final @NotNull Supplier<? extends Map<K, V>> supplier;
|
||||
//
|
||||
// protected final @NotNull Class<? super S> sourceClass;
|
||||
// protected final @NotNull Class<K> keyClass;
|
||||
// protected final @NotNull Class<V> valueClass;
|
||||
//
|
||||
// protected final @NotNull ConfigDataFunction<String, K> keyParser;
|
||||
// protected final @NotNull ConfigDataFunction<S, V> valueParser;
|
||||
//
|
||||
// protected final @NotNull ConfigDataFunction<K, String> keySerializer;
|
||||
// protected final @NotNull ConfigDataFunction<V, Object> valueSerializer;
|
||||
//
|
||||
//
|
||||
// protected ConfigValueMap(@NotNull ValueManifest<Map<K, V>> manifest, @NotNull Class<? super S> sourceClass,
|
||||
// @NotNull Supplier<? extends Map<K, V>> mapObjSupplier,
|
||||
// @NotNull Class<K> keyClass, @NotNull ConfigDataFunction<String, K> keyParser,
|
||||
// @NotNull Class<V> valueClass, @NotNull ConfigDataFunction<S, V> valueParser,
|
||||
// @NotNull ConfigDataFunction<K, String> keySerializer,
|
||||
// @NotNull ConfigDataFunction<V, Object> valueSerializer) {
|
||||
// super(manifest);
|
||||
// this.supplier = mapObjSupplier;
|
||||
// this.sourceClass = sourceClass;
|
||||
// this.keyClass = keyClass;
|
||||
// this.valueClass = valueClass;
|
||||
// this.keyParser = keyParser;
|
||||
// this.valueParser = valueParser;
|
||||
// this.keySerializer = keySerializer;
|
||||
// this.valueSerializer = valueSerializer;
|
||||
// }
|
||||
//
|
||||
// public @NotNull Class<? super S> getSourceClass() {
|
||||
// return sourceClass;
|
||||
// }
|
||||
//
|
||||
// public @NotNull Class<K> getKeyClass() {
|
||||
// return keyClass;
|
||||
// }
|
||||
//
|
||||
// public @NotNull Class<V> getValueClass() {
|
||||
// return valueClass;
|
||||
// }
|
||||
//
|
||||
// public @NotNull ConfigDataFunction<String, K> getKeyParser() {
|
||||
// return keyParser;
|
||||
// }
|
||||
//
|
||||
// public @NotNull ConfigDataFunction<S, V> getValueParser() {
|
||||
// return valueParser;
|
||||
// }
|
||||
//
|
||||
// public @NotNull ConfigDataFunction<K, String> getKeySerializer() {
|
||||
// return keySerializer;
|
||||
// }
|
||||
//
|
||||
// public @NotNull ConfigDataFunction<V, Object> getValueSerializer() {
|
||||
// return valueSerializer;
|
||||
// }
|
||||
//
|
||||
// public abstract S getSource(ConfigurationWrapper<?> section, String dataKey);
|
||||
//
|
||||
// @Override
|
||||
// public @NotNull Map<K, V> get() {
|
||||
// if (!isExpired()) return getCachedOrDefault(supplier.get());
|
||||
//
|
||||
// // 已过时的数据,需要重新解析一次。
|
||||
// Map<K, V> map = supplier.get();
|
||||
//
|
||||
// ConfigurationWrapper<?> section = getConfiguration().getConfigurationSection(getConfigPath());
|
||||
// if (section == null) return getDefaultFirst(map);
|
||||
//
|
||||
// Set<String> keys = section.getKeys(false);
|
||||
// if (keys.isEmpty()) return getDefaultFirst(map);
|
||||
//
|
||||
// for (String dataKey : keys) {
|
||||
// S dataVal = getSource(section, dataKey);
|
||||
// if (dataVal == null) continue;
|
||||
// try {
|
||||
// K key = keyParser.parse(dataKey);
|
||||
// V value = valueParser.parse(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<K, V> value) {
|
||||
// updateCache(value);
|
||||
// if (value == null) setValue(null);
|
||||
// else {
|
||||
// Map<String, Object> data = new LinkedHashMap<>();
|
||||
// for (Map.Entry<K, V> entry : value.entrySet()) {
|
||||
// try {
|
||||
// data.put(
|
||||
// keySerializer.parse(entry.getKey()),
|
||||
// valueSerializer.parse(entry.getValue())
|
||||
// );
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// setValue(data);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public <T> @NotNull T modifyValue(Function<Map<K, V>, T> function) {
|
||||
// Map<K, V> m = get();
|
||||
// T result = function.apply(m);
|
||||
// set(m);
|
||||
// return result;
|
||||
// }
|
||||
//
|
||||
// public @NotNull Map<K, V> modifyMap(Consumer<Map<K, V>> consumer) {
|
||||
// Map<K, V> m = get();
|
||||
// consumer.accept(m);
|
||||
// set(m);
|
||||
// return m;
|
||||
// }
|
||||
//
|
||||
// @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 modifyValue(m -> m.put(key, value));
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public V remove(Object key) {
|
||||
// return modifyValue(m -> m.remove(key));
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void putAll(@NotNull Map<? extends K, ? extends V> m) {
|
||||
// modifyMap(map -> map.putAll(m));
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void clear() {
|
||||
// modifyMap(Map::clear);
|
||||
// }
|
||||
//
|
||||
// @NotNull
|
||||
// @Override
|
||||
// public Set<K> keySet() {
|
||||
// return get().keySet();
|
||||
// }
|
||||
//
|
||||
// @NotNull
|
||||
// @Override
|
||||
// public Collection<V> values() {
|
||||
// return get().values();
|
||||
// }
|
||||
//
|
||||
// @NotNull
|
||||
// @Override
|
||||
// @Unmodifiable
|
||||
// public Set<Entry<K, V>> entrySet() {
|
||||
// return get().entrySet();
|
||||
// }
|
||||
//
|
||||
//}
|
||||
@@ -1,11 +0,0 @@
|
||||
package cc.carm.lib.configuration.value.meta;
|
||||
|
||||
public interface ValueMetaList {
|
||||
|
||||
/**
|
||||
* The value path in configuration.
|
||||
* Also see {@link cc.carm.lib.configuration.option.ConfigurationOptions#PATH_SEPARATOR}
|
||||
*/
|
||||
ValueMetaType<String> PATH = ValueMetaType.of();
|
||||
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package cc.carm.lib.configuration.value.meta;
|
||||
|
||||
import cc.carm.lib.configuration.value.ValueManifest;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ValueMetaType<T> {
|
||||
|
||||
public static <T> ValueMetaType<T> of() {
|
||||
return of(() -> null);
|
||||
}
|
||||
|
||||
public static <T> ValueMetaType<T> of(T defaults) {
|
||||
return of(() -> defaults);
|
||||
}
|
||||
|
||||
public static <T> ValueMetaType<T> of(@NotNull Supplier<@Nullable T> defaults) {
|
||||
return of(v -> defaults.get());
|
||||
}
|
||||
|
||||
public static <T> ValueMetaType<T> of(@NotNull Function<ValueManifest<?>, @Nullable T> defaults) {
|
||||
return new ValueMetaType<>(defaults);
|
||||
}
|
||||
|
||||
protected Function<ValueManifest<?>, @Nullable T> defaultFunction;
|
||||
|
||||
public ValueMetaType(@NotNull Function<ValueManifest<?>, @Nullable T> defaults) {
|
||||
this.defaultFunction = defaults;
|
||||
}
|
||||
|
||||
public boolean isDefault(ValueManifest<?> manifest, @NotNull T value) {
|
||||
return value.equals(defaults(manifest));
|
||||
}
|
||||
|
||||
public boolean hasDefaults(ValueManifest<?> manifest) {
|
||||
return defaults(manifest) != null;
|
||||
}
|
||||
|
||||
public T getDefault(ValueManifest<?> manifest, @Nullable T suppliedValue) {
|
||||
T defaults = defaults(manifest);
|
||||
return defaults == null ? suppliedValue : defaults;
|
||||
}
|
||||
|
||||
public @Nullable T defaults(ValueManifest<?> manifest) {
|
||||
return defaultFunction.apply(manifest);
|
||||
}
|
||||
|
||||
public void setDefaults(Function<ValueManifest<?>, T> defaultFunction) {
|
||||
this.defaultFunction = defaultFunction;
|
||||
}
|
||||
|
||||
public void setDefaults(T value) {
|
||||
setDefaults((v) -> value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,229 +1,231 @@
|
||||
//package cc.carm.lib.configuration.value.standard;
|
||||
//
|
||||
//import cc.carm.lib.configuration.builder.list.ConfigListBuilder;
|
||||
//import cc.carm.lib.configuration.function.ConfigDataFunction;
|
||||
//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 java.util.*;
|
||||
//import java.util.function.Consumer;
|
||||
//import java.util.function.Function;
|
||||
//
|
||||
//public class ConfiguredList<V> extends CachedConfigValue<List<V>> implements List<V> {
|
||||
//
|
||||
// public static <V> @NotNull ConfigListBuilder<V> builderOf(@NotNull Class<V> valueClass) {
|
||||
// return builder().asList(valueClass);
|
||||
// }
|
||||
//
|
||||
// public static <V> @NotNull ConfiguredList<V> of(@NotNull Class<V> valueClass, @NotNull Collection<V> defaults) {
|
||||
// return builderOf(valueClass).fromObject().defaults(defaults).build();
|
||||
// }
|
||||
//
|
||||
// @SafeVarargs
|
||||
// public static <V> @NotNull ConfiguredList<V> of(@NotNull Class<V> valueClass, @NotNull V... defaults) {
|
||||
// return builderOf(valueClass).fromObject().defaults(defaults).build();
|
||||
// }
|
||||
//
|
||||
// @SafeVarargs
|
||||
// @SuppressWarnings("unchecked")
|
||||
// public static <V> @NotNull ConfiguredList<V> of(@NotNull V defaultValue, @NotNull V... moreDefaults) {
|
||||
// Collection<V> values = new ArrayList<>();
|
||||
// values.add(defaultValue);
|
||||
// values.addAll(Arrays.asList(moreDefaults));
|
||||
// return of((Class<V>) defaultValue.getClass(), values);
|
||||
// }
|
||||
//
|
||||
// protected final @NotNull Class<V> valueClass;
|
||||
//
|
||||
// protected final @NotNull ConfigDataFunction<Object, V> parser;
|
||||
// protected final @NotNull ConfigDataFunction<V, Object> serializer;
|
||||
//
|
||||
// public ConfiguredList(@NotNull ValueManifest<List<V>> manifest, @NotNull Class<V> valueClass,
|
||||
// @NotNull ConfigDataFunction<Object, V> parser,
|
||||
// @NotNull ConfigDataFunction<V, Object> serializer) {
|
||||
// super(manifest);
|
||||
// this.valueClass = valueClass;
|
||||
// this.parser = parser;
|
||||
// this.serializer = serializer;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public @NotNull List<V> get() {
|
||||
// if (!isExpired()) return getCachedOrDefault(new ArrayList<>());
|
||||
// // Data that is outdated and needs to be parsed again.
|
||||
// List<V> list = new ArrayList<>();
|
||||
// List<?> data = getConfiguration().contains(getConfigPath()) ?
|
||||
// getConfiguration().getList(getConfigPath()) : null;
|
||||
// if (data == null) return getDefaultFirst(list);
|
||||
// for (Object dataVal : data) {
|
||||
// if (dataVal == null) continue;
|
||||
// try {
|
||||
// list.add(parser.parse(dataVal));
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// return updateCache(list);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public V get(int index) {
|
||||
// return get().get(index);
|
||||
// }
|
||||
//
|
||||
// public @NotNull List<V> copy() {
|
||||
// return new ArrayList<>(get());
|
||||
// }
|
||||
//
|
||||
// public <T> @NotNull T handle(Function<List<V>, T> function) {
|
||||
// List<V> list = get();
|
||||
// T result = function.apply(list);
|
||||
// set(list);
|
||||
// return result;
|
||||
// }
|
||||
//
|
||||
// public @NotNull List<V> modify(Consumer<List<V>> consumer) {
|
||||
// List<V> list = get();
|
||||
// consumer.accept(list);
|
||||
// set(list);
|
||||
// return list;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void set(@Nullable List<V> value) {
|
||||
// updateCache(value);
|
||||
// if (value == null) setValue(null);
|
||||
// else {
|
||||
// List<Object> data = new ArrayList<>();
|
||||
// for (V val : value) {
|
||||
// if (val == null) continue;
|
||||
// try {
|
||||
// data.add(serializer.parse(val));
|
||||
// } catch (Exception ex) {
|
||||
// ex.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// setValue(data);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public V set(int index, V element) {
|
||||
// return handle(list -> list.set(index, element));
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public int size() {
|
||||
// return get().size();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean isEmpty() {
|
||||
// return get().isEmpty();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean contains(Object o) {
|
||||
// return get().contains(o);
|
||||
// }
|
||||
//
|
||||
// @NotNull
|
||||
// @Override
|
||||
// public Iterator<V> iterator() {
|
||||
// return get().iterator();
|
||||
// }
|
||||
//
|
||||
// @NotNull
|
||||
// @Override
|
||||
// public Object @NotNull [] toArray() {
|
||||
// return get().toArray();
|
||||
// }
|
||||
//
|
||||
// @NotNull
|
||||
// @Override
|
||||
// public <T> T @NotNull [] toArray(@NotNull T[] a) {
|
||||
// return get().toArray(a);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean containsAll(@NotNull Collection<?> c) {
|
||||
// return new HashSet<>(get()).containsAll(c);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean add(V v) {
|
||||
// handle(list -> list.add(v));
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void add(int index, V element) {
|
||||
// modify(list -> list.add(index, element));
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean addAll(@NotNull Collection<? extends V> c) {
|
||||
// return handle(list -> list.addAll(c));
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean addAll(int index, @NotNull Collection<? extends V> c) {
|
||||
// return handle(list -> list.addAll(index, c));
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean remove(Object o) {
|
||||
// return handle(list -> list.remove(o));
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public V remove(int index) {
|
||||
// return handle(list -> list.remove(index));
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean removeAll(@NotNull Collection<?> c) {
|
||||
// return handle(list -> list.removeAll(c));
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean retainAll(@NotNull Collection<?> c) {
|
||||
// return handle(list -> list.retainAll(c));
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void clear() {
|
||||
// modify(List::clear);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public int indexOf(Object o) {
|
||||
// return get().indexOf(o);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public int lastIndexOf(Object o) {
|
||||
// return get().lastIndexOf(o);
|
||||
// }
|
||||
//
|
||||
// @NotNull
|
||||
// @Override
|
||||
// public ListIterator<V> listIterator() {
|
||||
// return get().listIterator();
|
||||
// }
|
||||
//
|
||||
// @NotNull
|
||||
// @Override
|
||||
// public ListIterator<V> listIterator(int index) {
|
||||
// return get().listIterator(index);
|
||||
// }
|
||||
//
|
||||
// @NotNull
|
||||
// @Override
|
||||
// public List<V> subList(int fromIndex, int toIndex) {
|
||||
// return get().subList(fromIndex, toIndex);
|
||||
// }
|
||||
//
|
||||
//}
|
||||
package cc.carm.lib.configuration.value.standard;
|
||||
|
||||
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.value.ValueManifest;
|
||||
import cc.carm.lib.configuration.value.impl.CachedConfigValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class ConfiguredList<V> extends CachedConfigValue<List<V>> implements List<V> {
|
||||
|
||||
protected final @NotNull ValueType<V> valueType;
|
||||
protected final @Nullable ValueParser<V> parser;
|
||||
protected final @Nullable ValueSerializer<V> serializer;
|
||||
|
||||
private ConfiguredList(@NotNull ValueManifest<List<V>> manifest, @NotNull ValueType<V> valueType,
|
||||
@Nullable ValueParser<V> parser, @Nullable ValueSerializer<V> serializer) {
|
||||
super(manifest);
|
||||
this.valueType = valueType;
|
||||
this.parser = parser;
|
||||
this.serializer = serializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Value's parser, parse base object to value.
|
||||
*/
|
||||
public @Nullable ValueParser<V> parser() {
|
||||
return parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Value's serializer, parse value to base object.
|
||||
*/
|
||||
public @Nullable ValueSerializer<V> serializer() {
|
||||
return serializer;
|
||||
}
|
||||
|
||||
public @NotNull ValueType<V> valueType() {
|
||||
return valueType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<V> get() {
|
||||
if (!isExpired()) return getCachedOrDefault(new ArrayList<>());
|
||||
// Data that is outdated and needs to be parsed again.
|
||||
List<V> list = new ArrayList<>();
|
||||
List<?> data = config().contains(path()) ? config().getList(path()) : null;
|
||||
if (data == null) return getDefaultFirst(list);
|
||||
|
||||
ValueParser<V> parser = this.parser;
|
||||
if (parser == null) return getDefaultFirst(list);
|
||||
|
||||
for (Object dataVal : data) {
|
||||
if (dataVal == null) continue;
|
||||
try {
|
||||
list.add(parser.deserialize(provider(), valueType(), dataVal));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return updateCache(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(@Nullable List<V> value) {
|
||||
updateCache(value);
|
||||
if (value == null) {
|
||||
setData(null);
|
||||
return;
|
||||
}
|
||||
|
||||
ValueSerializer<V> serializer = serializer();
|
||||
if (serializer == null) return;
|
||||
List<Object> data = new ArrayList<>();
|
||||
for (V val : value) {
|
||||
if (val == null) continue;
|
||||
try {
|
||||
data.add(serializer.serialize(provider(), valueType, val));
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
setData(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(int index) {
|
||||
return getNotNull().get(index);
|
||||
}
|
||||
|
||||
public @NotNull List<V> copy() {
|
||||
return new ArrayList<>(getNotNull());
|
||||
}
|
||||
|
||||
public <T> @NotNull T handle(Function<List<V>, T> function) {
|
||||
List<V> list = getNotNull();
|
||||
T result = function.apply(list);
|
||||
set(list);
|
||||
return result;
|
||||
}
|
||||
|
||||
public @NotNull ConfiguredList<V> modify(Consumer<List<V>> consumer) {
|
||||
List<V> list = getNotNull();
|
||||
consumer.accept(list);
|
||||
set(list);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V set(int index, V element) {
|
||||
return handle(list -> list.set(index, element));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return getNotNull().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return getNotNull().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return getNotNull().contains(o);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<V> iterator() {
|
||||
return getNotNull().iterator();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Object @NotNull [] toArray() {
|
||||
return getNotNull().toArray();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public <T> T @NotNull [] toArray(@NotNull T[] a) {
|
||||
return getNotNull().toArray(a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(@NotNull Collection<?> c) {
|
||||
return new HashSet<>(getNotNull()).containsAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(V v) {
|
||||
handle(list -> list.add(v));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, V element) {
|
||||
modify(list -> list.add(index, element));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(@NotNull Collection<? extends V> c) {
|
||||
return handle(list -> list.addAll(c));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, @NotNull Collection<? extends V> c) {
|
||||
return handle(list -> list.addAll(index, c));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
return handle(list -> list.remove(o));
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(int index) {
|
||||
return handle(list -> list.remove(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(@NotNull Collection<?> c) {
|
||||
return handle(list -> list.removeAll(c));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(@NotNull Collection<?> c) {
|
||||
return handle(list -> list.retainAll(c));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
modify(List::clear);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object o) {
|
||||
return getNotNull().indexOf(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastIndexOf(Object o) {
|
||||
return getNotNull().lastIndexOf(o);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ListIterator<V> listIterator() {
|
||||
return getNotNull().listIterator();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ListIterator<V> listIterator(int index) {
|
||||
return getNotNull().listIterator(index);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<V> subList(int fromIndex, int toIndex) {
|
||||
return getNotNull().subList(fromIndex, toIndex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
//package cc.carm.lib.configuration.value.standard;
|
||||
//
|
||||
//import cc.carm.lib.configuration.function.ConfigDataFunction;
|
||||
//import cc.carm.lib.configuration.value.ValueManifest;
|
||||
//import cc.carm.lib.configuration.value.impl.ConfigValueMap;
|
||||
//import org.jetbrains.annotations.NotNull;
|
||||
//
|
||||
//import java.util.Map;
|
||||
//import java.util.function.Supplier;
|
||||
//
|
||||
//public class ConfiguredMap<K, V> extends ConfigValueMap<K, V, Object> {
|
||||
//
|
||||
// public ConfiguredMap(@NotNull ValueManifest<Map<K, V>> manifest,
|
||||
// @NotNull Supplier<? extends Map<K, V>> mapObjSupplier,
|
||||
// @NotNull Class<K> keyClass, @NotNull ConfigDataFunction<String, K> keyParser,
|
||||
// @NotNull Class<V> valueClass, @NotNull ConfigDataFunction<Object, V> valueParser,
|
||||
// @NotNull ConfigDataFunction<K, String> keySerializer,
|
||||
// @NotNull ConfigDataFunction<V, Object> valueSerializer) {
|
||||
// super(manifest, Object.class, mapObjSupplier, keyClass, keyParser, valueClass, valueParser, keySerializer, valueSerializer);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Object getSource(ConfigurationWrapper<?> section, String dataKey) {
|
||||
// return section.get(dataKey);
|
||||
// }
|
||||
//
|
||||
//}
|
||||
@@ -1,96 +0,0 @@
|
||||
//package cc.carm.lib.configuration.value.standard;
|
||||
//
|
||||
//import cc.carm.lib.configuration.builder.value.SectionValueBuilder;
|
||||
//import cc.carm.lib.configuration.function.ConfigDataFunction;
|
||||
//import cc.carm.lib.configuration.function.ConfigValueParser;
|
||||
//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 java.util.Map;
|
||||
//
|
||||
//public class ConfiguredSection<V> extends CachedConfigValue<V> {
|
||||
//
|
||||
// public static <V> @NotNull SectionValueBuilder<V> builderOf(@NotNull Class<V> valueClass) {
|
||||
// return builder().asValue(valueClass).fromSection();
|
||||
// }
|
||||
//
|
||||
// protected final @NotNull Class<V> valueClass;
|
||||
//
|
||||
// protected final @NotNull ConfigValueParser<ConfigurationWrapper<?>, V> parser;
|
||||
// protected final @NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer;
|
||||
//
|
||||
// public ConfiguredSection(@NotNull ValueManifest<V> manifest, @NotNull Class<V> valueClass,
|
||||
// @NotNull ConfigValueParser<ConfigurationWrapper<?>, V> parser,
|
||||
// @NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer) {
|
||||
// super(manifest);
|
||||
// this.valueClass = valueClass;
|
||||
// this.parser = parser;
|
||||
// this.serializer = serializer;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @return Value's type class
|
||||
// */
|
||||
// public @NotNull Class<V> getValueClass() {
|
||||
// return valueClass;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @return Value's parser, cast value from section.
|
||||
// */
|
||||
// public @NotNull ConfigValueParser<ConfigurationWrapper<?>, V> getParser() {
|
||||
// return parser;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @return Value's serializer, serialize value to section.
|
||||
// */
|
||||
// public @NotNull ConfigDataFunction<V, ? extends Map<String, Object>> getSerializer() {
|
||||
// return serializer;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @return Get the value that parsed from the configuration section.
|
||||
// */
|
||||
// @Override
|
||||
// public @Nullable V get() {
|
||||
// if (!isExpired()) return getCachedOrDefault();
|
||||
// // Data that is outdated and needs to be parsed again.
|
||||
//
|
||||
// ConfigurationWrapper<?> section = getConfiguration().getConfigurationSection(getConfigPath());
|
||||
// if (section == null) return getDefaultValue();
|
||||
//
|
||||
// try {
|
||||
// // If there are no errors, update the cache and return.
|
||||
// return updateCache(this.parser.parse(section, this.defaultValue));
|
||||
// } catch (Exception e) {
|
||||
// // There was a parsing error, prompted and returned the default value.
|
||||
// e.printStackTrace();
|
||||
// return getDefaultValue();
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Use the specified value to update the configuration section.
|
||||
// * Will use {@link #getSerializer()} to serialize the value to section.
|
||||
// *
|
||||
// * @param value The value that needs to be set in the configuration.
|
||||
// */
|
||||
// @Override
|
||||
// public void set(V value) {
|
||||
// updateCache(value);
|
||||
// if (value == null) setValue(null);
|
||||
// else {
|
||||
// try {
|
||||
// setValue(serializer.parse(value));
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
//}
|
||||
@@ -1,31 +0,0 @@
|
||||
//package cc.carm.lib.configuration.value.standard;
|
||||
//
|
||||
//import cc.carm.lib.configuration.function.ConfigDataFunction;
|
||||
//import cc.carm.lib.configuration.value.ValueManifest;
|
||||
//import cc.carm.lib.configuration.value.impl.ConfigValueMap;
|
||||
//import org.jetbrains.annotations.NotNull;
|
||||
//
|
||||
//import java.util.Map;
|
||||
//import java.util.function.Supplier;
|
||||
//
|
||||
//public class ConfiguredSectionMap<K, V> extends ConfigValueMap<K, V, ConfigurationWrapper<?>> {
|
||||
//
|
||||
// public ConfiguredSectionMap(@NotNull ValueManifest<Map<K, V>> manifest,
|
||||
// @NotNull Supplier<? extends Map<K, V>> mapObjSupplier,
|
||||
// @NotNull Class<K> keyClass, @NotNull ConfigDataFunction<String, K> keyParser,
|
||||
// @NotNull Class<V> valueClass, @NotNull ConfigDataFunction<ConfigurationWrapper<?>, V> valueParser,
|
||||
// @NotNull ConfigDataFunction<K, String> keySerializer,
|
||||
// @NotNull ConfigDataFunction<V, ? extends Map<String, Object>> valueSerializer) {
|
||||
// super(
|
||||
// manifest, ConfigurationWrapper.class, mapObjSupplier,
|
||||
// keyClass, keyParser, valueClass, valueParser,
|
||||
// keySerializer, valueSerializer.andThen(s -> (Object) s)
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public ConfigurationWrapper<?> getSource(ConfigurationWrapper<?> section, String dataKey) {
|
||||
// return section.getConfigurationSection(dataKey);
|
||||
// }
|
||||
//
|
||||
//}
|
||||
@@ -1,62 +1,79 @@
|
||||
package cc.carm.lib.configuration.value.standard;
|
||||
|
||||
import cc.carm.lib.configuration.function.ConfigDataFunction;
|
||||
import cc.carm.lib.configuration.function.ConfigValueParser;
|
||||
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;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ConfiguredValue<V> extends CachedConfigValue<V> {
|
||||
|
||||
// public static <V> ConfigValueBuilder<V> builderOf(Class<V> valueClass) {
|
||||
// return builder().asValue(valueClass);
|
||||
// }
|
||||
//
|
||||
// @SuppressWarnings("unchecked")
|
||||
// public static <V> ConfiguredValue<V> of(@NotNull V defaultValue) {
|
||||
// return of((Class<V>) defaultValue.getClass(), defaultValue);
|
||||
// }
|
||||
//
|
||||
// public static <V> ConfiguredValue<V> of(Class<V> valueClass) {
|
||||
// return of(valueClass, null);
|
||||
// }
|
||||
//
|
||||
// public static <V> ConfiguredValue<V> of(Class<V> valueClass, @Nullable V defaultValue) {
|
||||
// return builderOf(valueClass).fromObject().defaults(defaultValue).build();
|
||||
// }
|
||||
public static <V> ConfigValueBuilder<V> builderOf(@NotNull Class<V> type) {
|
||||
return new ConfigValueBuilder<>(ValueType.of(type));
|
||||
}
|
||||
|
||||
protected final @NotNull Class<V> valueClass;
|
||||
public static <V> ConfigValueBuilder<V> builderOf(@NotNull ValueType<V> type) {
|
||||
return new ConfigValueBuilder<>(type);
|
||||
}
|
||||
|
||||
protected final @NotNull ConfigValueParser<Object, V> parser;
|
||||
protected final @NotNull ConfigDataFunction<V, Object> serializer;
|
||||
public static <V> ConfiguredValue<V> of(@NotNull V defaults) {
|
||||
return of(ValueType.of(defaults), () -> defaults);
|
||||
}
|
||||
|
||||
public ConfiguredValue(@NotNull ValueManifest<V> manifest, @NotNull Class<V> valueClass,
|
||||
@NotNull ConfigValueParser<Object, V> parser,
|
||||
@NotNull ConfigDataFunction<V, Object> serializer) {
|
||||
public static <V> ConfiguredValue<V> of(@NotNull Class<V> type) {
|
||||
return of(ValueType.of(type), () -> null);
|
||||
}
|
||||
|
||||
public static <V> ConfiguredValue<V> of(@NotNull Class<V> type, @NotNull Supplier<@Nullable V> defaultSupplier) {
|
||||
return of(ValueType.of(type), defaultSupplier);
|
||||
}
|
||||
|
||||
public static <V> ConfiguredValue<V> of(@NotNull ValueType<V> type) {
|
||||
return of(type, () -> null);
|
||||
}
|
||||
|
||||
public static <V> ConfiguredValue<V> of(@NotNull ValueType<V> type, @NotNull Supplier<@Nullable V> defaultSupplier) {
|
||||
return of(
|
||||
new ValueManifest<>(type, defaultSupplier),
|
||||
(provider, t, data) -> provider.deserialize(type, data),
|
||||
(provider, t, value) -> provider.serialize(value)
|
||||
);
|
||||
}
|
||||
|
||||
public static <V> ConfiguredValue<V> of(@NotNull ValueManifest<V> manifest,
|
||||
@Nullable ValueParser<V> parser,
|
||||
@Nullable ValueSerializer<V> serializer) {
|
||||
return new ConfiguredValue<>(manifest, parser, serializer);
|
||||
}
|
||||
|
||||
protected final @Nullable ValueParser<V> parser;
|
||||
protected final @Nullable ValueSerializer<V> serializer;
|
||||
|
||||
public ConfiguredValue(@NotNull ValueManifest<V> manifest,
|
||||
@Nullable ValueParser<V> parser,
|
||||
@Nullable ValueSerializer<V> serializer) {
|
||||
super(manifest);
|
||||
this.valueClass = valueClass;
|
||||
this.parser = parser;
|
||||
this.serializer = serializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Value's type class
|
||||
* @return Value's parser, parse base object to value.
|
||||
*/
|
||||
public @NotNull Class<V> getValueClass() {
|
||||
return valueClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Value's parser, cast value from base object.
|
||||
*/
|
||||
public @NotNull ConfigValueParser<Object, V> getParser() {
|
||||
public @Nullable ValueParser<V> parser() {
|
||||
return parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Value's serializer, serialize value to base object.
|
||||
* @return Value's serializer, parse value to base object.
|
||||
*/
|
||||
public @NotNull ConfigDataFunction<V, Object> getSerializer() {
|
||||
public @Nullable ValueSerializer<V> serializer() {
|
||||
return serializer;
|
||||
}
|
||||
|
||||
@@ -65,12 +82,15 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
|
||||
if (!isExpired()) return getCachedOrDefault();
|
||||
// Data that is outdated and needs to be parsed again.
|
||||
|
||||
Object value = getValue();
|
||||
if (value == null) return defaults();
|
||||
Object data = getData();
|
||||
if (data == null) return defaults();
|
||||
|
||||
ValueParser<V> parser = parser();
|
||||
if (parser == null) return defaults(); // No parser, return default value.
|
||||
|
||||
try {
|
||||
// If there are no errors, update the cache and return.
|
||||
return updateCache(this.parser.parse(provider(), value, defaults()));
|
||||
return updateCache(parser.deserialize(provider(), type(), data));
|
||||
} catch (Exception e) {
|
||||
// There was a parsing error, prompted and returned the default value.
|
||||
e.printStackTrace();
|
||||
@@ -81,21 +101,27 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
|
||||
|
||||
/**
|
||||
* Set the value of the configuration path.
|
||||
* Will use {@link #getSerializer()} to serialize the value.
|
||||
* Will use {@link #serializer()} to serialize the value.
|
||||
*
|
||||
* @param value The value to be set
|
||||
*/
|
||||
@Override
|
||||
public void set(V value) {
|
||||
updateCache(value);
|
||||
if (value == null) setValue(null);
|
||||
else {
|
||||
try {
|
||||
setValue(serializer.parse(value));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
updateCache(value); // Update cache
|
||||
if (value == null) {
|
||||
setData(null);
|
||||
return;
|
||||
}
|
||||
|
||||
ValueSerializer<V> serializer = serializer();
|
||||
if (serializer == null) return; // No serializer, do nothing.
|
||||
|
||||
try {
|
||||
setData(serializer.serialize(provider(), type(), value));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
package cc.carm.lib.configuration.value;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Unmodifiable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* ConfigValue Manifests.
|
||||
* The basic information that describes a configuration value.
|
||||
*
|
||||
* @param <T> Value type
|
||||
* @author CarmJos
|
||||
*/
|
||||
public class ValueManifest<T> {
|
||||
|
||||
public static <V> ValueManifest<V> of(@Nullable ConfigurationProvider<?> provider, @Nullable String configPath,
|
||||
@Nullable List<String> headerComments, @Nullable String inlineComments) {
|
||||
return new ValueManifest<>(provider, configPath, headerComments, inlineComments, null);
|
||||
}
|
||||
|
||||
public static <V> ValueManifest<V> of(@Nullable ConfigurationProvider<?> provider, @Nullable String configPath,
|
||||
@Nullable List<String> headerComments, @Nullable String inlineComments,
|
||||
@Nullable V defaultValue) {
|
||||
return new ValueManifest<>(provider, configPath, headerComments, inlineComments, defaultValue);
|
||||
}
|
||||
|
||||
protected @Nullable ConfigurationProvider<?> provider;
|
||||
protected @Nullable String configPath;
|
||||
|
||||
protected @Nullable List<String> headerComments;
|
||||
protected @Nullable String inlineComment;
|
||||
|
||||
protected @Nullable T defaultValue;
|
||||
|
||||
/**
|
||||
* @param provider Provider of config files {@link ConfigurationProvider}
|
||||
* @param configPath Config path of this value
|
||||
* @param headerComments Header comment contents
|
||||
* @param inlineComment Inline comment content
|
||||
* @param defaultValue The default value
|
||||
*/
|
||||
public ValueManifest(@Nullable ConfigurationProvider<?> provider, @Nullable String configPath,
|
||||
@Nullable List<String> headerComments, @Nullable String inlineComment,
|
||||
@Nullable T defaultValue) {
|
||||
this.provider = provider;
|
||||
this.configPath = configPath;
|
||||
this.headerComments = headerComments;
|
||||
this.inlineComment = inlineComment;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* The initialize method for {@link ConfigInitializer}, which is used to initialize the value.
|
||||
*
|
||||
* @param provider Provider of config files {@link ConfigurationProvider}
|
||||
* @param configPath Config path of this value
|
||||
* @param headerComments Header comment contents
|
||||
* @param inlineComment Inline comment content
|
||||
*/
|
||||
protected void initialize(@NotNull ConfigurationProvider<?> provider, @NotNull String configPath,
|
||||
@Nullable List<String> headerComments, @Nullable String inlineComment) {
|
||||
if (this.provider == null) this.provider = provider;
|
||||
if (this.configPath == null) this.configPath = configPath;
|
||||
if (this.headerComments == null) this.headerComments = headerComments;
|
||||
if (this.inlineComment == null) this.inlineComment = inlineComment;
|
||||
|
||||
if (getHeaderComments() != null) {
|
||||
this.provider.setHeaderComment(getConfigPath(), getHeaderComments());
|
||||
}
|
||||
if (getInlineComment() != null) {
|
||||
this.provider.setInlineComment(getConfigPath(), getInlineComment());
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable T getDefaultValue() {
|
||||
return this.defaultValue;
|
||||
}
|
||||
|
||||
public void setDefaultValue(@Nullable T defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public @NotNull ConfigurationProvider<?> getProvider() {
|
||||
return Optional.ofNullable(this.provider)
|
||||
.orElseThrow(() -> new IllegalStateException("Value(" + configPath + ") does not have a provider."));
|
||||
}
|
||||
|
||||
public final @NotNull ConfigurationWrapper<?> getConfiguration() {
|
||||
try {
|
||||
return getProvider().getConfiguration();
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException("Value(" + configPath + ") has not been initialized", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public @NotNull String getConfigPath() {
|
||||
return Optional.ofNullable(this.configPath)
|
||||
.orElseThrow(() -> new IllegalStateException("No section path provided."));
|
||||
}
|
||||
|
||||
protected Object getValue() {
|
||||
String path = getConfigPath(); // 当未指定路径时,优先抛出异常
|
||||
return getConfiguration().get(path);
|
||||
}
|
||||
|
||||
protected void setValue(@Nullable Object value) {
|
||||
getConfiguration().set(getConfigPath(), value);
|
||||
}
|
||||
|
||||
public @Nullable String getInlineComment() {
|
||||
return inlineComment;
|
||||
}
|
||||
|
||||
@Unmodifiable
|
||||
public @Nullable List<String> getHeaderComments() {
|
||||
return headerComments;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -31,12 +31,12 @@ public abstract class AbstractConfigBuilder<T, B extends AbstractConfigBuilder<T
|
||||
|
||||
public @NotNull B from(@Nullable P provider) {
|
||||
this.provider = provider;
|
||||
return getThis();
|
||||
return self();
|
||||
}
|
||||
|
||||
public @NotNull B path(@Nullable String path) {
|
||||
this.path = path;
|
||||
return getThis();
|
||||
return self();
|
||||
}
|
||||
|
||||
public @NotNull B comments(@NotNull String... comments) {
|
||||
@@ -49,17 +49,17 @@ public abstract class AbstractConfigBuilder<T, B extends AbstractConfigBuilder<T
|
||||
|
||||
public @NotNull B headerComments(@NotNull List<String> comments) {
|
||||
this.headerComments = comments;
|
||||
return getThis();
|
||||
return self();
|
||||
}
|
||||
|
||||
public @NotNull B inlineComment(@NotNull String comment) {
|
||||
this.inlineComment = comment;
|
||||
return getThis();
|
||||
return self();
|
||||
}
|
||||
|
||||
public @NotNull B defaults(@Nullable T defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
return getThis();
|
||||
return self();
|
||||
}
|
||||
|
||||
public @NotNull B defaults(@NotNull Supplier<@Nullable T> defaultValueSupplier) {
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
package cc.carm.lib.configuration.builder;
|
||||
|
||||
import cc.carm.lib.configuration.builder.map.ConfigMapBuilder;
|
||||
import cc.carm.lib.configuration.builder.map.ConfigMapCreator;
|
||||
import cc.carm.lib.configuration.builder.list.ConfigListBuilder;
|
||||
import cc.carm.lib.configuration.builder.value.ConfigValueBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class ConfigBuilder {
|
||||
|
||||
public <V> @NotNull ConfigValueBuilder<V> asValue(@NotNull Class<V> valueClass) {
|
||||
return new ConfigValueBuilder<>(valueClass);
|
||||
}
|
||||
|
||||
public <V> @NotNull ConfigListBuilder<V> asList(@NotNull Class<V> valueClass) {
|
||||
return new ConfigListBuilder<>(valueClass);
|
||||
}
|
||||
|
||||
public <K, V> @NotNull ConfigMapCreator<K, V> asMap(@NotNull Class<K> keyClass,
|
||||
@NotNull Class<V> valueClass) {
|
||||
return new ConfigMapCreator<>(keyClass, valueClass);
|
||||
}
|
||||
|
||||
public <K, V> @NotNull ConfigMapBuilder<HashMap<K, V>, K, V> asHashMap(@NotNull Class<K> keyClass,
|
||||
@NotNull Class<V> valueClass) {
|
||||
return asMap(keyClass, valueClass).asHashMap();
|
||||
}
|
||||
|
||||
public <K, V> @NotNull ConfigMapBuilder<LinkedHashMap<K, V>, K, V> asLinkedMap(@NotNull Class<K> keyClass,
|
||||
@NotNull Class<V> valueClass) {
|
||||
return asMap(keyClass, valueClass).asLinkedMap();
|
||||
}
|
||||
|
||||
public <K extends Comparable<K>, V> @NotNull ConfigMapBuilder<TreeMap<K, V>, K, V> asTreeMap(@NotNull Class<K> keyClass,
|
||||
@NotNull Class<V> valueClass) {
|
||||
return asMap(keyClass, valueClass).asTreeMap();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package cc.carm.lib.configuration.builder.value;
|
||||
import cc.carm.lib.configuration.builder.CommonConfigBuilder;
|
||||
import cc.carm.lib.configuration.function.ConfigDataFunction;
|
||||
import cc.carm.lib.configuration.function.ConfigValueParser;
|
||||
import cc.carm.lib.configuration.value.standard.ConfiguredSection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
import cc.carm.lib.configuration.adapter.ValueAdapterRegistry;
|
||||
import cc.carm.lib.configuration.adapter.strandard.EnumAdapter;
|
||||
import cc.carm.lib.configuration.adapter.ValueType;
|
||||
import cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapters;
|
||||
import cc.carm.lib.configuration.source.ConfigurationProvider;
|
||||
import cc.carm.lib.configuration.loader.ConfigurationLoader;
|
||||
import cc.carm.lib.easyoptions.OptionHolder;
|
||||
import cc.carm.lib.configuration.source.loader.ConfigurationLoader;
|
||||
import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder;
|
||||
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||
import cc.carm.test.config.TestSource;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class AdaptTest {
|
||||
|
||||
@@ -16,42 +20,29 @@ public class AdaptTest {
|
||||
public void test() throws Exception {
|
||||
|
||||
ValueAdapterRegistry registry = new ValueAdapterRegistry();
|
||||
registry.register(Long.class, PrimitiveAdapters.ofLong());
|
||||
registry.register(long.class, PrimitiveAdapters.ofLong());
|
||||
registry.register(Integer.class, PrimitiveAdapters.ofInteger());
|
||||
registry.register(int.class, PrimitiveAdapters.ofInteger());
|
||||
registry.register(Double.class, PrimitiveAdapters.ofDouble());
|
||||
registry.register(double.class, PrimitiveAdapters.ofDouble());
|
||||
registry.register(Float.class, PrimitiveAdapters.ofFloat());
|
||||
registry.register(float.class, PrimitiveAdapters.ofFloat());
|
||||
registry.register(Short.class, PrimitiveAdapters.ofShort());
|
||||
registry.register(short.class, PrimitiveAdapters.ofShort());
|
||||
registry.register(Byte.class, PrimitiveAdapters.ofByte());
|
||||
registry.register(byte.class, PrimitiveAdapters.ofByte());
|
||||
registry.register(Character.class, PrimitiveAdapters.ofCharacter());
|
||||
registry.register(char.class, PrimitiveAdapters.ofCharacter());
|
||||
registry.register(Boolean.class, PrimitiveAdapters.ofBoolean());
|
||||
registry.register(boolean.class, PrimitiveAdapters.ofBoolean());
|
||||
registry.register(String.class, PrimitiveAdapters.ofString());
|
||||
registry.register(new EnumAdapter());
|
||||
registry.register(PrimitiveAdapters.ADAPTERS);
|
||||
registry.register(PrimitiveAdapters.ofEnum());
|
||||
|
||||
registry.register(Long.class, Duration.class, Duration::ofSeconds, Duration::getSeconds);
|
||||
|
||||
registry.register(ValueType.of(Long.class), ValueType.of(Duration.class), Duration::ofMillis, Duration::toMillis);
|
||||
registry.register(
|
||||
Duration.class, LocalTime.class,
|
||||
ValueType.of(Duration.class), ValueType.of(LocalTime.class),
|
||||
duration -> LocalTime.now().plus(duration),
|
||||
data -> Duration.between(LocalTime.now(), data)
|
||||
);
|
||||
|
||||
ConfigurationProvider<TestSource> provider = new ConfigurationProvider<>(new TestSource(), new ConfigurationLoader(), registry, new OptionHolder());
|
||||
ConfigurationProvider<TestSource> provider = new ConfigurationProvider<>(
|
||||
new TestSource(), new ConfigurationLoader(),
|
||||
registry, new ConfigurationOptionHolder(), new ConcurrentHashMap<>()
|
||||
);
|
||||
|
||||
LocalTime v = registry.deserialize(provider, LocalTime.class, "600");
|
||||
LocalTime v = registry.deserialize(provider, LocalTime.class, 600000L);
|
||||
Object d = registry.serialize(provider, v);
|
||||
|
||||
System.out.println(v);
|
||||
System.out.println(d);
|
||||
System.out.println(registry.deserialize(provider, TestEnum.class, "b"));
|
||||
System.out.println(registry.deserialize(provider, TestEnum.class, "C"));
|
||||
System.out.println(registry.serialize(provider, TestEnum.C).getClass());
|
||||
|
||||
}
|
||||
|
||||
enum TestEnum {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import cc.carm.lib.configuration.loader.PathGenerator;
|
||||
import cc.carm.lib.configuration.source.loader.PathGenerator;
|
||||
import org.junit.Test;
|
||||
|
||||
public class NameTest {
|
||||
|
||||
@@ -4,15 +4,17 @@ import cc.carm.lib.configuration.adapter.ValueAdapterRegistry;
|
||||
import cc.carm.lib.configuration.annotation.ConfigPath;
|
||||
import cc.carm.lib.configuration.Configuration;
|
||||
import cc.carm.lib.configuration.source.ConfigurationProvider;
|
||||
import cc.carm.lib.configuration.loader.ConfigurationLoader;
|
||||
import cc.carm.lib.easyoptions.OptionHolder;
|
||||
import cc.carm.lib.configuration.source.loader.ConfigurationLoader;
|
||||
import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class LoaderTest {
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
ConfigurationProvider<TestSource> provider = new ConfigurationProvider<>(new TestSource(), new ConfigurationLoader(), new ValueAdapterRegistry(), new OptionHolder());
|
||||
ConfigurationProvider<TestSource> provider = new ConfigurationProvider<>(new TestSource(), new ConfigurationLoader(), new ValueAdapterRegistry(), new ConfigurationOptionHolder(), new ConcurrentHashMap<>());
|
||||
|
||||
ConfigurationLoader loader = new ConfigurationLoader();
|
||||
loader.load(provider, ROOT.class);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package cc.carm.test.config;
|
||||
|
||||
import cc.carm.lib.configuration.source.ConfigurationSection;
|
||||
import cc.carm.lib.configuration.source.ConfigurationSource;
|
||||
import cc.carm.lib.configuration.source.section.ConfigurationSection;
|
||||
import cc.carm.lib.configuration.source.section.ConfigurationSource;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -16,7 +16,7 @@ public class TestSource extends ConfigurationSource<TestSource, Map<String, Stri
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TestSource getThis() {
|
||||
protected TestSource self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user