Skip to content

Commit

Permalink
Fix collection loading to use proper YAML lists
Browse files Browse the repository at this point in the history
- Added wrapper DataHolder to abstract away implementation details of storage from the converters
- Switch SQLCache to use synchronized maps, which can store null keys and values
  • Loading branch information
boxbeam committed Dec 21, 2021
1 parent e444bb2 commit 0410f5e
Show file tree
Hide file tree
Showing 14 changed files with 378 additions and 38 deletions.
2 changes: 1 addition & 1 deletion res/plugin.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: RedLib
main: redempt.redlib.RedLib
version: 2021-12-20 06:09
version: 2021-12-21 04:50
author: Redempt
api-version: 1.13
load: STARTUP
18 changes: 13 additions & 5 deletions src/redempt/redlib/config/ConfigManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import redempt.redlib.config.conversion.StaticRootConverter;
import redempt.redlib.config.conversion.StringConverter;
import redempt.redlib.config.conversion.TypeConverter;
import redempt.redlib.config.data.ConfigurationSectionDataHolder;
import redempt.redlib.config.data.DataHolder;

import java.io.File;
import java.io.IOException;
Expand Down Expand Up @@ -77,6 +79,7 @@ public static ConfigManager create(Plugin plugin) {
}

private FileConfiguration config;
private DataHolder holder;
private File file;
private TypeConverter<?> converter;
private Object target;
Expand All @@ -86,12 +89,17 @@ private ConfigManager(File file) {
this.file = file;
file.getParentFile().mkdirs();
if (file.exists()) {
config = YamlConfiguration.loadConfiguration(file);
setConfig(YamlConfiguration.loadConfiguration(file));
} else {
config = new YamlConfiguration();
setConfig(new YamlConfiguration());
}
}

private void setConfig(FileConfiguration config) {
this.config = config;
this.holder = new ConfigurationSectionDataHolder(config);
}

/**
* Specifies the given Object to load config values to and save config values from. The Object
* must be from a ConfigMappable class, and all of its non-transient fields will be worked with.
Expand Down Expand Up @@ -150,20 +158,20 @@ public ConfigManager load() {
}

private <T> void load(TypeConverter<T> converter) {
converter.loadFrom(config, null, (T) target);
converter.loadFrom(holder, null, (T) target);
}

/**
* Loads the config from disk, then loads all values into the target
* @return This ConfigManager
*/
public ConfigManager reload() {
config = YamlConfiguration.loadConfiguration(file);
setConfig(YamlConfiguration.loadConfiguration(file));
return load();
}

private <T> void save(TypeConverter<T> converter, boolean overwrite) {
converter.saveTo((T) target, config, null, overwrite);
converter.saveTo((T) target, holder, null, overwrite);
try {
config.save(file);
} catch (IOException e) {
Expand Down
20 changes: 12 additions & 8 deletions src/redempt/redlib/config/conversion/CollectionConverter.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package redempt.redlib.config.conversion;

import org.bukkit.configuration.ConfigurationSection;
import redempt.redlib.config.ConfigManager;
import redempt.redlib.config.ConfigType;
import redempt.redlib.config.data.DataHolder;
import redempt.redlib.config.data.ListDataHolder;

import java.util.ArrayDeque;
import java.util.ArrayList;
Expand Down Expand Up @@ -39,34 +40,37 @@ public class CollectionConverter {
* @return A collection converter
*/
public static <V, T extends Collection<V>> TypeConverter<T> create(ConfigManager manager, ConfigType<?> collectionType) {
TypeConverter<V> converter = (TypeConverter<V>) manager.getConverter(collectionType.getComponentTypes().get(0));
ConfigType<?> componentType = collectionType.getComponentTypes().get(0);
TypeConverter<V> converter = (TypeConverter<V>) manager.getConverter(componentType);
return new TypeConverter<T>() {
@Override
public T loadFrom(ConfigurationSection section, String path, T currentValue) {
public T loadFrom(DataHolder section, String path, T currentValue) {
if (currentValue == null) {
currentValue = (T) defaults.get(collectionType.getType()).get();
} else {
currentValue.clear();
}
ConfigurationSection newSection = section.getConfigurationSection(path);
DataHolder newSection = path == null ? section : section.getList(path);
if (newSection == null) {
return null;
}
T collection = currentValue;
newSection.getKeys(false).forEach(k -> {
collection.add(converter.loadFrom(newSection, k, null));
newSection.getKeys().forEach(k -> {
V obj = converter.loadFrom(newSection, k, null);
collection.add(obj);
});
return collection;
}

@Override
public void saveTo(T t, ConfigurationSection section, String path) {
ConfigurationSection newSection = section.createSection(path);
public void saveTo(T t, DataHolder section, String path) {
DataHolder newSection = new ListDataHolder();
int pos = 0;
for (V obj : t) {
converter.saveTo(obj, newSection, String.valueOf(pos));
pos++;
}
section.set(path, newSection);
}
};
}
Expand Down
11 changes: 6 additions & 5 deletions src/redempt/redlib/config/conversion/MapConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.bukkit.configuration.ConfigurationSection;
import redempt.redlib.config.ConfigManager;
import redempt.redlib.config.ConfigType;
import redempt.redlib.config.data.DataHolder;

import java.util.LinkedHashMap;
import java.util.List;
Expand All @@ -29,18 +30,18 @@ public static <K, V, M extends Map<K, V>> TypeConverter<M> create(ConfigManager
TypeConverter<V> valueConverter = (TypeConverter<V>) manager.getConverter(types.get(1));
return new TypeConverter<M>() {
@Override
public M loadFrom(ConfigurationSection section, String path, M currentValue) {
public M loadFrom(DataHolder section, String path, M currentValue) {
if (currentValue == null) {
currentValue = (M) new LinkedHashMap<>();
} else {
currentValue.clear();
}
M map = currentValue;
ConfigurationSection newSection = section.getConfigurationSection(path);
DataHolder newSection = path == null ? section : section.getSubsection(path);
if (newSection == null) {
return null;
}
newSection.getKeys(false).forEach(k -> {
newSection.getKeys().forEach(k -> {
K key = keyConverter.fromString(k);
V value = valueConverter.loadFrom(newSection, k, null);
map.put(key, value);
Expand All @@ -49,8 +50,8 @@ public M loadFrom(ConfigurationSection section, String path, M currentValue) {
}

@Override
public void saveTo(M m, ConfigurationSection section, String path) {
ConfigurationSection newSection = section.createSection(path);
public void saveTo(M m, DataHolder section, String path) {
DataHolder newSection = path == null ? section : section.createSubsection(path);
m.forEach((k, v) -> {
String keyPath = keyConverter.toString(k);
valueConverter.saveTo(v, newSection, keyPath);
Expand Down
5 changes: 3 additions & 2 deletions src/redempt/redlib/config/conversion/NativeConverter.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package redempt.redlib.config.conversion;

import org.bukkit.configuration.ConfigurationSection;
import redempt.redlib.config.data.DataHolder;

/**
* A converter which saves and loads directly to config without modifying the data
Expand All @@ -16,12 +17,12 @@ public class NativeConverter {
public static <T> TypeConverter<T> create() {
return new TypeConverter<T>() {
@Override
public T loadFrom(ConfigurationSection section, String path, T currentValue) {
public T loadFrom(DataHolder section, String path, T currentValue) {
return (T) section.get(path);
}

@Override
public void saveTo(T t, ConfigurationSection section, String path) {
public void saveTo(T t, DataHolder section, String path) {
section.set(path, t);
}
};
Expand Down
13 changes: 7 additions & 6 deletions src/redempt/redlib/config/conversion/ObjectConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import redempt.redlib.config.ConfigType;
import redempt.redlib.config.annotations.ConfigPath;
import redempt.redlib.config.annotations.ConfigPostInit;
import redempt.redlib.config.data.DataHolder;
import redempt.redlib.config.instantiation.InstantiationInfo;
import redempt.redlib.config.instantiation.Instantiator;

Expand Down Expand Up @@ -71,8 +72,8 @@ public static <T> TypeConverter<T> create(ConfigManager manager, ConfigType<?> t
InstantiationInfo info = new InstantiationInfo(postInit, configPath, configPathConverter);
return new TypeConverter<T>() {
@Override
public T loadFrom(ConfigurationSection section, String path, T currentValue) {
ConfigurationSection newSection = path == null ? section : section.getConfigurationSection(path);
public T loadFrom(DataHolder section, String path, T currentValue) {
DataHolder newSection = path == null ? section : section.getSubsection(path);
List<Object> objs = new ArrayList<>();
for (Field field : fields) {
Object value = converters.get(field).loadFrom(newSection, field.getName(), null);
Expand All @@ -82,16 +83,16 @@ public T loadFrom(ConfigurationSection section, String path, T currentValue) {
}

@Override
public void saveTo(T t, ConfigurationSection section, String path) {
public void saveTo(T t, DataHolder section, String path) {
saveTo(t, section, path, true);
}

@Override
public void saveTo(T t, ConfigurationSection section, String path, boolean overwrite) {
public void saveTo(T t, DataHolder section, String path, boolean overwrite) {
if (path != null && section.isSet(path) && !overwrite) {
return;
}
ConfigurationSection newSection = path == null ? section : section.createSection(path);
DataHolder newSection = path == null ? section : section.createSubsection(path);
try {
for (Field field : fields) {
saveWith(converters.get(field), field.get(t), newSection, field.getName(), overwrite);
Expand All @@ -103,7 +104,7 @@ public void saveTo(T t, ConfigurationSection section, String path, boolean overw
};
}

private static <T> void saveWith(TypeConverter<T> converter, Object obj, ConfigurationSection section, String path, boolean overwrite) {
private static <T> void saveWith(TypeConverter<T> converter, Object obj, DataHolder section, String path, boolean overwrite) {
converter.saveTo((T) obj, section, path, overwrite);
}

Expand Down
9 changes: 5 additions & 4 deletions src/redempt/redlib/config/conversion/StaticRootConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.bukkit.configuration.ConfigurationSection;
import redempt.redlib.config.ConfigManager;
import redempt.redlib.config.ConfigType;
import redempt.redlib.config.data.DataHolder;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
Expand Down Expand Up @@ -38,7 +39,7 @@ public static <T> TypeConverter<T> create(ConfigManager manager, Class<?> root)
}
return new TypeConverter<T>() {
@Override
public T loadFrom(ConfigurationSection section, String path, T currentValue) {
public T loadFrom(DataHolder section, String path, T currentValue) {
try {
for (Field field : fields) {
Object val = converters.get(field).loadFrom(section, field.getName(), null);
Expand All @@ -51,12 +52,12 @@ public T loadFrom(ConfigurationSection section, String path, T currentValue) {
}

@Override
public void saveTo(T t, ConfigurationSection section, String path) {
public void saveTo(T t, DataHolder section, String path) {
saveTo(t, section, path, true);
}

@Override
public void saveTo(T t, ConfigurationSection section, String path, boolean overwrite) {
public void saveTo(T t, DataHolder section, String path, boolean overwrite) {
try {
for (Field field : fields) {
Object obj = field.get(null);
Expand All @@ -69,7 +70,7 @@ public void saveTo(T t, ConfigurationSection section, String path, boolean overw
};
}

private static <T> void saveWith(TypeConverter<T> converter, Object obj, ConfigurationSection section, String path, boolean overwrite) {
private static <T> void saveWith(TypeConverter<T> converter, Object obj, DataHolder section, String path, boolean overwrite) {
converter.saveTo((T) obj, section, path, overwrite);
}

Expand Down
5 changes: 3 additions & 2 deletions src/redempt/redlib/config/conversion/StringConverter.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package redempt.redlib.config.conversion;

import org.bukkit.configuration.ConfigurationSection;
import redempt.redlib.config.data.DataHolder;

import java.util.function.Function;

Expand Down Expand Up @@ -53,7 +54,7 @@ public String toString(T t) {
* @return
*/
@Override
public default T loadFrom(ConfigurationSection section, String path, T currentValue) {
public default T loadFrom(DataHolder section, String path, T currentValue) {
return fromString(section.getString(path));
}

Expand All @@ -63,7 +64,7 @@ public default T loadFrom(ConfigurationSection section, String path, T currentVa
* @param path The path to the data that should be saved in the ConfigurationSection
*/
@Override
public default void saveTo(T t, ConfigurationSection section, String path) {
public default void saveTo(T t, DataHolder section, String path) {
section.set(path, toString(t));
}

Expand Down
8 changes: 4 additions & 4 deletions src/redempt/redlib/config/conversion/TypeConverter.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package redempt.redlib.config.conversion;

import org.bukkit.configuration.ConfigurationSection;
import redempt.redlib.config.data.DataHolder;

/**
* An interface which converts data in config for a given type
Expand All @@ -16,15 +16,15 @@ public interface TypeConverter<T> {
* @param currentValue The current value, used for collections and maps
* @return The loaded object
*/
public T loadFrom(ConfigurationSection section, String path, T currentValue);
public T loadFrom(DataHolder section, String path, T currentValue);

/**
* Attemps to save the object to config
* @param t The object to save
* @param section The ConfigurationSection to save to
* @param path The path to the data that should be saved in the ConfigurationSection
*/
public void saveTo(T t, ConfigurationSection section, String path);
public void saveTo(T t, DataHolder section, String path);

/**
* Attemps to save the object to config
Expand All @@ -33,7 +33,7 @@ public interface TypeConverter<T> {
* @param path The path to the data that should be saved in the ConfigurationSection
* @param overwrite Whether to overwrite existing data
*/
public default void saveTo(T t, ConfigurationSection section, String path, boolean overwrite) {
public default void saveTo(T t, DataHolder section, String path, boolean overwrite) {
if (!overwrite && section.isSet(path)) {
return;
}
Expand Down
Loading

0 comments on commit 0410f5e

Please sign in to comment.