Skip to content

Commit

Permalink
๐Ÿบ๐Ÿ› ๏ธโŒ๐Ÿช„๐Ÿฅ“๐Ÿ’ป๐Ÿ’พโœจ๐Ÿ
Browse files Browse the repository at this point in the history
  • Loading branch information
AmarokIce committed Sep 17, 2024
1 parent 1150012 commit ae61b1e
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import band.kessoku.lib.config.api.AbstractConfig;
import band.kessoku.lib.config.api.ConfigSerializer;
Expand All @@ -31,36 +32,40 @@

public final class KessokuConfig {
private static final Map<AbstractConfig, Class<ConfigSerializer>> configs = new HashMap<>();
private static final Map<Class<ConfigSerializer>, ConfigSerializer> serializerCache = new HashMap<>();
private static final Map<Class<? extends ConfigSerializer>, ConfigSerializer> serializerCache = new HashMap<>();

public static final String MOD_ID = "kessoku_config";
public static final Marker MARKER = MarkerFactory.getMarker("[KessokuConfig]");

@SuppressWarnings({"unchecked", "unused"})
public static <T extends AbstractConfig, S extends ConfigSerializer> T register(T config, Class<S> serializer) {
if (config.getClass().isAnonymousClass()) throw new IllegalArgumentException();
final File file = config.getPath().toFile();

try {
FileUtils.touch(file);
FileUtils.touch(config.getPath().toFile());
} catch (IOException e) {
throw new RuntimeException(e);
}

configs.put(config, (Class<ConfigSerializer>) serializer);
return config;
}

@Contract(pure = true)
public static <T extends AbstractConfig> @Nullable Class<ConfigSerializer> getSerializer(T config) {
@Nullable
public static <T extends AbstractConfig> Class<ConfigSerializer> getSerializer(T config) {
return configs.get(config);
}

@Contract(pure = true)
@SuppressWarnings("unchecked")
public static <T extends ConfigSerializer> @NotNull ConfigSerializer getSerializerInstance(Class<T> serializer) {
if (serializerCache.containsKey(serializer)) return serializerCache.get(serializer);
@NotNull
public static <T extends ConfigSerializer> T getSerializerInstance(Class<T> serializer) {
try {
T serializerInstance = serializer.getConstructor().newInstance();
serializerCache.put((Class<ConfigSerializer>) serializer, serializerInstance);
return serializerInstance;
return (T) Objects.requireNonNull(serializerCache.containsKey(serializer)
? serializerCache.get(serializer)
: serializerCache.put(serializer,
serializer.getConstructor().newInstance()));
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,14 @@
import com.google.common.collect.ImmutableMap;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.logging.log4j.core.util.ReflectionUtil;

//@SuppressWarnings({"rawtypes", "unchecked", "unused"})
@SuppressWarnings({"rawtypes", "unused"})
public abstract class AbstractConfig {
private final List<Consumer> preSave = new ArrayList<>();
private final List<Consumer> preLoad = new ArrayList<>();
private final List<BiConsumer> postSave = new ArrayList<>();
private final List<BiConsumer> postLoad = new ArrayList<>();
private final List<Consumer<AbstractConfig>> preSave = new ArrayList<>();
private final List<Consumer<AbstractConfig>> preLoad = new ArrayList<>();
private final List<BiConsumer<AbstractConfig, Boolean>> postSave = new ArrayList<>();
private final List<BiConsumer<AbstractConfig, Boolean>> postLoad = new ArrayList<>();
private List<Field> values;
private List<Field> categories;
private boolean split = false;
Expand All @@ -53,13 +54,14 @@ public boolean save() {
preSave.forEach(consumer -> consumer.accept(this));
File file = this.getPath().toFile();
ConfigSerializer serializer = this.getSerializer();
boolean result;

boolean result = true;
try (FileWriter writer = new FileWriter(file, StandardCharsets.UTF_8)) {
writer.write(serializer.serialize(this.serialize()));
result = true;
} catch (IOException e) {
result = false;
}

final boolean finalResult = result;
postSave.forEach(biConsumer -> biConsumer.accept(this, finalResult));
return finalResult;
Expand All @@ -69,59 +71,62 @@ public boolean load() {
preLoad.forEach(consumer -> consumer.accept(this));
ConfigSerializer serializer = this.getSerializer();
File file = this.getPath().toFile();
boolean result;

boolean result = true;
try {
Map<String, Object> map = serializer.deserialize(FileUtils.readFileToString(file, StandardCharsets.UTF_8));
// Put values into the config
for (Map.Entry<String, Object> entry : map.entrySet()) {
String string = entry.getKey();
Object object = entry.getValue();
String key = entry.getKey();
Object cValue = entry.getValue();

ConfigValue value;
// Check the value is public and not static
try {
Field field = this.getClass().getField(string);
Field field = this.getClass().getField(key);
if (!Modifier.isPublic(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) continue;
value = (ConfigValue<?, ?>) field.get(this);
} catch (NoSuchFieldException | IllegalAccessException e) {
value = (ConfigValue) ReflectionUtil.getFieldValue(field, this);
} catch (NoSuchFieldException e) {
continue;
}
ConfigValue.Type type;

ConfigValue.Type type = ConfigValue.Type.asType(cValue);
// Check if the type is valid to deserialize
try {
type = ConfigValue.Type.asType(object);
} catch (IllegalArgumentException e) {
ModUtils.getLogger().error(KessokuConfig.MARKER, "Illegal type`{}` found in the file!", object.getClass().getName());
if (type == ConfigValue.Type.NULL) {
ModUtils.getLogger().error(KessokuConfig.MARKER, "Illegal type`{}` found in the file!", cValue.getClass().getName());
continue;
}

// Check if the type matches the value's type
if (value.getType() != type) {
ModUtils.getLogger().error(KessokuConfig.MARKER, "Illegal type`{}` found in the file! Expect {}.", type.toString().toLowerCase(), value.getType().toString().toLowerCase());
continue;
}
value.setTo(object);

value.setTo(cValue);
}
result = true;
} catch (IOException e) {
result = false;
}

final boolean finalResult = result;
postLoad.forEach(biConsumer -> biConsumer.accept(this, finalResult));
return finalResult;
}

public <T extends AbstractConfig> void registerPreSaveListener(Consumer<T> preSave) {
public void registerPreSaveListener(Consumer<AbstractConfig> preSave) {
this.preSave.add(preSave);
}

public <T extends AbstractConfig> void registerPreLoadListener(Consumer<T> preLoad) {
public void registerPreLoadListener(Consumer<AbstractConfig> preLoad) {
this.preLoad.add(preLoad);
}

public <T extends AbstractConfig> void registerPostSaveListener(BiConsumer<T, Boolean> postSave) {
public void registerPostSaveListener(BiConsumer<AbstractConfig, Boolean> postSave) {
this.postSave.add(postSave);
}

public <T extends AbstractConfig> void registerPostLoadListener(BiConsumer<T, Boolean> postLoad) {
public void registerPostLoadListener(BiConsumer<AbstractConfig, Boolean> postLoad) {
this.postLoad.add(postLoad);
}

Expand All @@ -131,68 +136,79 @@ public void reset() {
}

public ImmutableList<ConfigValue<?, ?>> getValidValues() {
if (this.values != null)
return ImmutableList.<ConfigValue<?, ?>>builder().addAll(this.values.stream().map(field -> {
try {
return (ConfigValue<?, ?>) field.get(this);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}).toList()).build();
if (this.values != null) {
return ImmutableList.<ConfigValue<?, ?>>builder().addAll(this.values.stream().map(field ->
(ConfigValue<?, ?>) ReflectionUtil.getFieldValue(field, this)).toList()).build();
}

List<Field> fields = new ArrayList<>();
for (Field declaredField : this.getClass().getDeclaredFields()) {
if (declaredField.getDeclaringClass().isAssignableFrom(ConfigValue.class) && Modifier.isPublic(declaredField.getModifiers()) && !Modifier.isStatic(declaredField.getModifiers()))
final boolean flag0 = declaredField.getDeclaringClass().isAssignableFrom(ConfigValue.class);
final boolean flag1 = Modifier.isPublic(declaredField.getModifiers());
final boolean flag2 = !Modifier.isStatic(declaredField.getModifiers());
if (flag0 && flag1 && flag2) {
fields.add(declaredField);
}
}

this.values = fields;
return this.getValidValues();
}

public ImmutableList<AbstractConfig> getValidCategories() {
if (this.categories != null)
return ImmutableList.<AbstractConfig>builder().addAll(this.categories.stream().map(field -> {
try {
return (AbstractConfig) field.get(this);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}).toList()).build();
if (this.categories != null){
return ImmutableList.<AbstractConfig>builder().addAll(this.categories.stream().map(field ->
(AbstractConfig) ReflectionUtil.getFieldValue(field, this)).toList()).build();
}

List<Field> fields = new ArrayList<>();
for (Field declaredField : this.getClass().getDeclaredFields()) {
if (declaredField.getDeclaringClass().isAssignableFrom(AbstractConfig.class) && Modifier.isPublic(declaredField.getModifiers()))

final boolean flag0 = declaredField.getDeclaringClass().isAssignableFrom(AbstractConfig.class);
final boolean flag1 = Modifier.isPublic(declaredField.getModifiers());
if (flag0 && flag1){
fields.add(declaredField);
}
}

this.categories = fields;
return this.getValidCategories();
}

private ImmutableList<Field> getValidFields() {
ImmutableList.Builder<Field> builder = ImmutableList.builder();
for (Field declaredField : this.getClass().getDeclaredFields()) {
if ((declaredField.getDeclaringClass().isAssignableFrom(AbstractConfig.class) || declaredField.getDeclaringClass().isAssignableFrom(ConfigValue.class)) && Modifier.isPublic(declaredField.getModifiers()))

final boolean flag0 = declaredField.getDeclaringClass().isAssignableFrom(AbstractConfig.class);
final boolean flag1 = declaredField.getDeclaringClass().isAssignableFrom(ConfigValue.class);
final boolean flag2 = Modifier.isPublic(declaredField.getModifiers());

final var flag = flag0 || flag1;

if (flag && flag2){
builder.add(declaredField);
}
}
return builder.build();
}

private Map<String, ValueWithComment> serialize() {
ImmutableMap.Builder<String, ValueWithComment> builder = ImmutableMap.builder();
for (Field field : this.getValidFields()) {
field.setAccessible(true);
final String name = field.isAnnotationPresent(Name.class) ? field.getAnnotation(Name.class).value() : field.getName();
final String[] comments = field.isAnnotationPresent(Comments.class) ? (String[]) Arrays.stream(field.getAnnotation(Comments.class).value()).map(Comment::value).toArray() : new String[0];
Object o;
try {
o = field.get(this);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}

Object fieldValue = ReflectionUtil.getFieldValue(field, this);

// ConfigValue
if (o instanceof ConfigValue<?, ?> value) {
if (fieldValue instanceof ConfigValue<?, ?> value) {
builder.put(name, new ValueWithComment(value.get(), comments));
continue;
}

// Category
AbstractConfig category = (AbstractConfig) o;
AbstractConfig category = (AbstractConfig) fieldValue;
if (this.split) {
if (!category.save()) {
ModUtils.getLogger().error(KessokuConfig.MARKER, "Failed to save category `{}!`", category.getSimpleName());
Expand All @@ -212,13 +228,20 @@ public boolean isSplitToFiles() {
return this.split;
}

/**
* Get config full name. If it's a sub file, it will include the paths.
* @return Get the full name of the config.
*/
// Not including file ext, but parent path `/`
public String getName() {
Name name = this.getClass().getAnnotation(Name.class);
return name == null ? this.getClass().getSimpleName() : name.value();
}

// Just config name
/**
* Get the config name. Even it's a sub file, just config name.
* @return The simple config name.
*/
public String getSimpleName() {
String[] strings = this.getName().split("/");
return strings[strings.length - 1];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ default F get() {
T getDefaultTo();

enum Type {
LIST, MAP, BOOLEAN, STRING, INTEGER, LONG, FLOAT, DOUBLE;
LIST, MAP, BOOLEAN, STRING, INTEGER, LONG, FLOAT, DOUBLE, NULL;

public static Type asType(Object o) {
return switch (o) {
Expand All @@ -54,7 +54,13 @@ public static Type asType(Object o) {
case Integer ignored -> INTEGER;
case Float ignored -> FLOAT;
case Double ignored -> DOUBLE;
case null, default -> throw new IllegalArgumentException();

/* AmarokIce Note:
try catch ๅฏนๆ€ง่ƒฝไผš้€ ๆˆ้ขๅค–ๅฝฑๅ“ใ€‚ๆญคๅค„ throw ๅŽๅœจ { @code AbstractConfig } ไธญๆ•่Žทๆ˜ฏๆ— ๆ„ไน‰็š„ใ€‚
ๅ› ๆญค๏ผŒๆ”น็”จ NULL ไฝœไธบ็ฉบ็ฝฎๅฏน่ฑกใ€‚
*/
case null, default -> NULL;
// case null, default -> throw new IllegalArgumentException();
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import club.someoneice.json.node.JsonNode;
import club.someoneice.json.processor.Json5Builder;

//todo
// TODO
public class Json5Serializer implements ConfigSerializer {
@Override
public String serialize(Map<String, AbstractConfig.ValueWithComment> value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public String serialize(Map<String, AbstractConfig.ValueWithComment> value) {
.map(it -> new Pair<>(it.getKey(), JsonNode.asJsonNodeOrEmpty(it.getValue().object())))
.filter(it -> it.getValue().nonNull())
.forEach(it -> node.put(it.getKey(), it.getValue()));

return JsonBuilder.prettyPrint(node);
}

Expand Down

0 comments on commit ae61b1e

Please sign in to comment.