1
mirror of https://github.com/CarmJos/EasyConfiguration.git synced 2026-06-04 10:38:19 +08:00

feat(exception): Supported ConfigExceptionHandler for holders.

This commit is contained in:
2025-03-17 01:06:57 +08:00
parent 65f3cc1b3d
commit 82cca5eca2
18 changed files with 190 additions and 131 deletions
@@ -1,21 +0,0 @@
package cc.carm.lib.configuration.annotation;
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
public class Ex {
static void init(ConfigurationInitializer initializer) {
initializer.appendFieldInitializer((holder, path, field, value) -> {
ValueRange range = field.getAnnotation(ValueRange.class);
if (range == null) return;
value.validate((h, v) -> {
if (!(v instanceof Number)) return;
Number number = (Number) v;
if (number.doubleValue() >= range.min() && number.doubleValue() <= range.max()) {
throw new IllegalArgumentException(range.message());
}
});
});
}
}
@@ -29,7 +29,7 @@ public abstract class AbstractConfigBuilder<
protected @Nullable HOLDER holder;
protected @Nullable String path;
protected @NotNull ValueValidator<? super UNIT> valueValidator = ValueValidator.none();
protected @NotNull ValueValidator<UNIT> valueValidator = ValueValidator.none();
protected @NotNull Supplier<@Nullable TYPE> defaultValueSupplier = () -> null;
protected @NotNull BiConsumer<ConfigurationHolder<?>, String> initializer = (h, p) -> {
};
@@ -63,7 +63,7 @@ public abstract class AbstractConfigBuilder<
* @param validator The validator to set.
* @return this builder
*/
public SELF validator(@NotNull ValueValidator<? super UNIT> validator) {
public SELF validator(@NotNull ValueValidator<UNIT> validator) {
this.valueValidator = validator;
return self();
}
@@ -81,20 +81,17 @@ public abstract class AbstractConfigBuilder<
/**
* Validate the value with the specified condition.
*
* @param validator The validator to set.
* @param validator The validator to append.
* @return this builder
*/
public SELF validate(@NotNull ValueValidator<? super UNIT> validator) {
return validator((h, v) -> {
this.valueValidator.validate(h, v);
validator.validate(h, v);
});
return validator(this.valueValidator.and(validator));
}
/**
* Validate the value with the specified condition.
*
* @param validator The validator to set.
* @param validator The validator to append.
* @return this builder
*/
public SELF validate(@NotNull DataValidator<? super UNIT> validator) {
@@ -0,0 +1,22 @@
package cc.carm.lib.configuration.function;
import org.jetbrains.annotations.NotNull;
@FunctionalInterface
public interface ConfigExceptionHandler {
void handle(@NotNull String path, @NotNull Throwable throwable);
static @NotNull ConfigExceptionHandler silence() {
return (path, throwable) -> {
};
}
static @NotNull ConfigExceptionHandler print() {
return (path, throwable) -> {
System.err.println("Error occurred at path: " + path);
throwable.printStackTrace();
};
}
}
@@ -9,7 +9,7 @@ public interface ValueValidator<T> {
void validate(@NotNull ConfigurationHolder<?> holder, @Nullable T value) throws Exception;
default ValueValidator<T> compose(ValueValidator<? super T> other) {
default ValueValidator<T> and(ValueValidator<? super T> other) {
return (holder, value) -> {
validate(holder, value);
other.validate(holder, value);
@@ -2,7 +2,9 @@ package cc.carm.lib.configuration.source;
import cc.carm.lib.configuration.adapter.*;
import cc.carm.lib.configuration.adapter.strandard.StandardAdapters;
import cc.carm.lib.configuration.function.ConfigExceptionHandler;
import cc.carm.lib.configuration.function.DataFunction;
import cc.carm.lib.configuration.function.ValueValidator;
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
import cc.carm.lib.configuration.source.loader.PathGenerator;
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
@@ -33,10 +35,11 @@ public abstract class ConfigurationFactory<
SELF
> {
protected ValueAdapterRegistry adapters = new ValueAdapterRegistry();
protected ConfigurationOptionHolder options = new ConfigurationOptionHolder();
protected @NotNull ValueAdapterRegistry adapters = new ValueAdapterRegistry();
protected @NotNull ConfigurationOptionHolder options = new ConfigurationOptionHolder();
protected @NotNull Map<String, ConfigurationMetaHolder> metadata = new HashMap<>();
protected ConfigurationInitializer initializer = new ConfigurationInitializer();
protected @NotNull ConfigurationInitializer initializer = new ConfigurationInitializer();
protected @NotNull ConfigExceptionHandler exceptionHandler = ConfigExceptionHandler.print();
protected ConfigurationFactory() {
this.adapters.register(StandardAdapters.PRIMITIVES);
@@ -147,6 +150,11 @@ public abstract class ConfigurationFactory<
return self();
}
public SELF exceptionally(@NotNull ConfigExceptionHandler handler) {
this.exceptionHandler = handler;
return self();
}
/**
* Supply the base path generator for this configuration holder
*
@@ -154,9 +162,7 @@ public abstract class ConfigurationFactory<
* @return this
*/
public SELF pathGenerator(PathGenerator generator) {
return initializer(loader -> {
loader.pathGenerator(generator);
});
return initializer(loader -> loader.pathGenerator(generator));
}
/**
@@ -175,6 +181,19 @@ public abstract class ConfigurationFactory<
return initializer(loader -> loader.registerAnnotation(annotation, metadata, extractor));
}
/**
* Register a new annotation for {@link ValueValidator} to the configuration loader
*
* @param annotation The {@link Annotation}
* @param builder The {@link Function} to build the {@link ValueValidator} from the annotation
* @param <A> The annotation type
* @return this
*/
public <A extends Annotation> SELF validAnnotation(@NotNull Class<A> annotation,
@NotNull Function<A, ValueValidator<Object>> builder) {
return initializer(loader -> loader.registerValidAnnotation(annotation, builder));
}
/**
* Build the configuration holder.
*
@@ -3,6 +3,7 @@ package cc.carm.lib.configuration.source;
import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.adapter.ValueAdapterRegistry;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.function.ConfigExceptionHandler;
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
@@ -31,14 +32,25 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
protected final @NotNull ConfigurationInitializer initializer;
protected @NotNull ConfigExceptionHandler exceptionHandler;
public ConfigurationHolder(@NotNull ValueAdapterRegistry adapters,
@NotNull ConfigurationOptionHolder options,
@NotNull Map<String, ConfigurationMetaHolder> metadata,
@NotNull ConfigurationInitializer initializer) {
this(adapters, options, metadata, initializer, ConfigExceptionHandler.print());
}
public ConfigurationHolder(@NotNull ValueAdapterRegistry adapters,
@NotNull ConfigurationOptionHolder options,
@NotNull Map<String, ConfigurationMetaHolder> metadata,
@NotNull ConfigurationInitializer initializer,
@NotNull ConfigExceptionHandler exceptionHandler) {
this.initializer = initializer;
this.adapters = adapters;
this.options = options;
this.metadata = metadata;
this.exceptionHandler = exceptionHandler;
}
public abstract @NotNull SOURCE config();
@@ -117,7 +129,7 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
try {
initializer.initialize(this, configClass);
} catch (Exception e) {
e.printStackTrace();
throwing(configClass.getName(), e);
}
}
@@ -125,7 +137,7 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
try {
initializer.initialize(this, config);
} catch (Exception e) {
e.printStackTrace();
throwing(config.getClass().getName(), e);
}
}
@@ -133,4 +145,12 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
value.holder(this);
}
public void throwing(@NotNull String path, @NotNull Throwable e) {
this.exceptionHandler.handle(path, e);
}
public void exceptionally(@NotNull ConfigExceptionHandler handler) {
this.exceptionHandler = handler;
}
}
@@ -134,7 +134,7 @@ public class ConfigurationInitializer {
try {
this.classInitializer.whenInitialize(holder, path, root.getClass(), root);
} catch (Exception e) {
e.printStackTrace();
holder.throwing(path, e);
}
Arrays.stream(root.getClass().getDeclaredFields()).forEach(field -> initializeField(holder, root, field, path));
}
@@ -151,7 +151,7 @@ public class ConfigurationInitializer {
try {
this.classInitializer.whenInitialize(holder, path, (Class<? extends Configuration>) clazz, configField);
} catch (Exception e) {
e.printStackTrace();
holder.throwing(path, e);
}
for (Field field : clazz.getDeclaredFields()) {
@@ -185,7 +185,7 @@ public class ConfigurationInitializer {
try {
this.valueInitializer.whenInitialize(holder, path, field, value);
} catch (Exception e) {
e.printStackTrace();
holder.throwing(path, e);
}
if (holder.option(StandardOptions.PRELOAD)) {
value.get(); // Preload the value by calling #get method.
@@ -20,7 +20,7 @@ public class ValueManifest<TYPE, UNIT> {
protected @Nullable ConfigurationHolder<?> holder;
protected @Nullable String path; // Section path
protected @NotNull ValueValidator<? super UNIT> validator;
protected @NotNull ValueValidator<UNIT> validator;
protected @NotNull Supplier<@Nullable TYPE> defaultSupplier;
public ValueManifest(@NotNull ValueType<TYPE> type) {
@@ -37,19 +37,19 @@ public class ValueManifest<TYPE, UNIT> {
public ValueManifest(@NotNull ValueType<TYPE> type,
@NotNull Supplier<@Nullable TYPE> defaultSupplier,
@NotNull ValueValidator<? super UNIT> validator) {
@NotNull ValueValidator<UNIT> validator) {
this(type, defaultSupplier, validator, EMPTY_INITIALIZER, null, null);
}
public ValueManifest(@NotNull ValueType<TYPE> type, @NotNull Supplier<@Nullable TYPE> defaultSupplier,
@NotNull ValueValidator<? super UNIT> validator,
@NotNull ValueValidator<UNIT> validator,
@NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer) {
this(type, defaultSupplier, validator, initializer, null, null);
}
public ValueManifest(@NotNull ValueType<TYPE> type,
@NotNull Supplier<@Nullable TYPE> defaultSupplier,
@NotNull ValueValidator<? super UNIT> validator,
@NotNull ValueValidator<UNIT> validator,
@NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer,
@Nullable ConfigurationHolder<?> holder, @Nullable String path) {
this.type = type;
@@ -103,19 +103,16 @@ public class ValueManifest<TYPE, UNIT> {
return defaults() != null;
}
public @NotNull ValueValidator<? super UNIT> validator() {
public @NotNull ValueValidator<UNIT> validator() {
return this.validator;
}
public void validator(@NotNull ValueValidator<? super UNIT> validator) {
public void validator(@NotNull ValueValidator<UNIT> validator) {
this.validator = validator;
}
public void validate(@NotNull ValueValidator<? super UNIT> validator) {
validator((h, v) -> {
this.validator.validate(h, v);
validator.validate(h, v);
});
public void validate(@NotNull ValueValidator<UNIT> validator) {
validator(this.validator.and(validator));
}
protected UNIT withValidated(@Nullable UNIT value) throws Exception {
@@ -151,6 +148,15 @@ public class ValueManifest<TYPE, UNIT> {
config().set(path(), value);
}
protected void throwing(@NotNull Throwable throwable) {
throwing(path, throwable);
}
protected void throwing(@NotNull String path, @NotNull Throwable throwable) {
if (holder == null) throwable.printStackTrace();
else holder.throwing(path, throwable);
}
private static final @NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> EMPTY_INITIALIZER = (provider, valuePath) -> {
};
@@ -87,19 +87,24 @@ public class ConfiguredList<V> extends CachedConfigValue<List<V>, V> implements
if (!cacheExpired()) return getCachedOrDefault(createList());
// Data that is outdated and needs to be parsed again.
List<V> list = createList();
List<?> data = config().contains(path()) ? config().getList(path()) : null;
if (data == null) return getDefaultFirst(list);
try {
List<?> data = config().contains(path()) ? config().getList(path()) : null;
if (data == null) return getDefaultFirst(list);
ValueParser<V> parser = parser();
if (parser == null) return getDefaultFirst(list);
ValueParser<V> parser = parser();
if (parser == null) return getDefaultFirst(list);
for (Object dataVal : data) {
if (dataVal == null) continue;
try {
list.add(withValidated(parser.parse(holder(), paramType(), dataVal)));
} catch (Exception e) {
e.printStackTrace();
int i = 0;
for (Object dataVal : data) {
if (dataVal == null) continue;
try {
list.add(withValidated(parser.parse(holder(), paramType(), dataVal)));
} catch (Exception e) {
throwing(path + "[" + i + "]", e);
}
}
} catch (Exception ex) {
throwing(ex);
}
return updateCache(list);
}
@@ -111,7 +116,7 @@ public class ConfiguredList<V> extends CachedConfigValue<List<V>, V> implements
setData(null);
return;
}
ValueSerializer<V> serializer = serializer();
if (serializer == null) return;
@@ -121,7 +126,7 @@ public class ConfiguredList<V> extends CachedConfigValue<List<V>, V> implements
try {
data.add(serializer.serialize(holder(), paramType(), withValidated(val)));
} catch (Exception ex) {
ex.printStackTrace();
throwing(ex);
}
}
setData(data);
@@ -77,27 +77,31 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>, V> impleme
// If the value is expired, we need to update it
Map<K, V> map = createMap();
ConfigureSection section = config().getSection(path());
if (section == null) return getDefaultFirst(map);
try {
ConfigureSection section = config().getSection(path());
if (section == null) return getDefaultFirst(map);
Set<String> keys = section.getKeys(false);
if (keys.isEmpty()) return getDefaultFirst(map);
Set<String> keys = section.getKeys(false);
if (keys.isEmpty()) return getDefaultFirst(map);
ValueParser<K> keyParser = parserFor(keyAdapter);
if (keyParser == null) return getDefaultFirst(map);
ValueParser<V> valueParser = parserFor(valueAdapter);
if (valueParser == null) return getDefaultFirst(map);
ValueParser<K> keyParser = parserFor(keyAdapter);
if (keyParser == null) return getDefaultFirst(map);
ValueParser<V> valueParser = parserFor(valueAdapter);
if (valueParser == null) return getDefaultFirst(map);
for (String dataKey : keys) {
Object dataVal = section.get(dataKey);
if (dataVal == null) continue;
try {
K key = keyParser.parse(holder(), keyType(), dataKey);
V value = valueParser.parse(holder(), valueType(), dataVal);
map.put(key, withValidated(value));
} catch (Exception e) {
e.printStackTrace();
for (String dataKey : keys) {
Object dataVal = section.get(dataKey);
if (dataVal == null) continue;
try {
K key = keyParser.parse(holder(), keyType(), dataKey);
V value = valueParser.parse(holder(), valueType(), dataVal);
map.put(key, withValidated(value));
} catch (Exception e) {
throwing(path + "." + dataKey, e);
}
}
} catch (Exception ex) {
throwing(ex);
}
return updateCache(map);
@@ -120,24 +124,28 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>, V> impleme
return;
}
ValueSerializer<K> keySerializer = serializerFor(keyAdapter);
if (keySerializer == null) return;
ValueSerializer<V> valueSerializer = serializerFor(valueAdapter);
if (valueSerializer == null) return;
try {
ValueSerializer<K> keySerializer = serializerFor(keyAdapter);
if (keySerializer == null) return;
ValueSerializer<V> valueSerializer = serializerFor(valueAdapter);
if (valueSerializer == null) return;
Map<Object, Object> data = new LinkedHashMap<>();
Map<Object, Object> data = new LinkedHashMap<>();
for (Map.Entry<K, V> entry : value.entrySet()) {
try {
data.put(
keySerializer.serialize(holder(), keyType(), entry.getKey()),
valueSerializer.serialize(holder(), valueType(), withValidated(entry.getValue()))
);
} catch (Exception e) {
e.printStackTrace();
for (Map.Entry<K, V> entry : value.entrySet()) {
try {
data.put(
keySerializer.serialize(holder(), keyType(), entry.getKey()),
valueSerializer.serialize(holder(), valueType(), withValidated(entry.getValue()))
);
} catch (Exception e) {
throwing(path + "." + entry.getKey(), e);
}
}
setData(data);
} catch (Exception ex) {
throwing(ex);
}
setData(data);
}
public <T> @NotNull T handle(Function<Map<K, V>, T> function) {
@@ -137,20 +137,19 @@ public class ConfiguredValue<V> extends CachedConfigValue<V, V> {
if (!cacheExpired()) return getCachedOrDefault();
// Data that is outdated and needs to be parsed again.
Object data = getData();
if (data == null) return defaults();
ValueParser<V> parser = parser();
if (parser == null) return defaults(); // No parser, return default value.
try {
Object data = getData();
if (data == null) return defaults();
ValueParser<V> parser = parser();
if (parser == null) return defaults(); // No parser, return default value.
// If there are no errors, update the cache and return.
V parsed = parser.parse(holder(), type(), data);
return updateCache(withValidated(parsed));
} catch (Exception e) {
// There was a validate or parsing error, prompted and returned the default value.
e.printStackTrace();
throwing(e);
return defaults();
}
@@ -169,14 +168,14 @@ public class ConfiguredValue<V> extends CachedConfigValue<V, V> {
setData(null);
return;
}
ValueSerializer<V> serializer = serializer();
if (serializer == null) return; // No serializer, do nothing.
try {
ValueSerializer<V> serializer = serializer();
if (serializer == null) return; // No serializer, do nothing.
setData(serializer.serialize(holder(), type(), withValidated(value)));
} catch (Exception e) {
e.printStackTrace();
throwing(e);
}
}