diff --git a/src/main/java/com/ilummc/tlib/inject/TConfigInjector.java b/src/main/java/com/ilummc/tlib/inject/TConfigInjector.java index da6445e..063a1c9 100644 --- a/src/main/java/com/ilummc/tlib/inject/TConfigInjector.java +++ b/src/main/java/com/ilummc/tlib/inject/TConfigInjector.java @@ -1,33 +1,20 @@ package com.ilummc.tlib.inject; +import com.google.common.io.Files; +import com.ilummc.tlib.TLib; +import com.ilummc.tlib.annotations.Config; +import me.skymc.taboolib.fileutils.ConfigUtils; +import org.apache.commons.lang3.Validate; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.Plugin; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; + import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.nio.charset.Charset; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; -import java.util.stream.Collectors; - -import org.apache.commons.lang3.Validate; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.configuration.serialization.ConfigurationSerializable; -import org.bukkit.configuration.serialization.ConfigurationSerialization; -import org.bukkit.plugin.Plugin; -import org.yaml.snakeyaml.DumperOptions; -import org.yaml.snakeyaml.Yaml; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; -import com.google.common.io.Files; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.annotations.SerializedName; -import com.ilummc.tlib.TLib; -import com.ilummc.tlib.annotations.Config; -import com.ilummc.tlib.bean.Property; public class TConfigInjector { @@ -83,9 +70,10 @@ public class TConfigInjector { try { Config config = clazz.getAnnotation(Config.class); Validate.notNull(config); - return new GsonBuilder().disableHtmlEscaping().excludeFieldsWithModifiers(config.excludeModifiers()) - .create().fromJson(new Gson().toJson(new Yaml() - .dump(Files.toString(new File(plugin.getDataFolder(), config.name()), Charset.forName(config.charset())))), clazz); + return ConfigUtils.confToObj( + ConfigUtils.mapToConf( + ConfigUtils.yamlToMap( + Files.toString(new File(plugin.getDataFolder(), config.name()), Charset.forName(config.charset())))), clazz); } catch (NullPointerException e) { TLib.getTLib().getLogger().warn("插件 " + plugin + " 的配置类 " + clazz.getSimpleName() + " 加载失败:没有 @Config 注解或文件不存在"); return null; @@ -103,7 +91,7 @@ public class TConfigInjector { try { Config config = object.getClass().getAnnotation(Config.class); Validate.notNull(config); - return new Serializer(new LinkedHashMap<>(), object, config.excludeModifiers()).get(); + return ConfigUtils.objToConf(object).getValues(false); } catch (NullPointerException e) { TLib.getTLib().getLogger().warn("插件 " + plugin + " 的配置类 " + object.getClass().getSimpleName() + " 序列化失败:没有 @Config 注解"); } catch (Exception e) { @@ -128,64 +116,4 @@ public class TConfigInjector { Files.write(arr, target); } - private static final List> primitiveType = Lists.newArrayList(Integer.class, - Double.class, Float.class, Boolean.class, Short.class, Byte.class, Character.class, Long.class, String.class); - - private static class Serializer { - - private HashMap map; - private Object o; - private int modifiers; - - private Serializer(HashMap map, Object o, int modifiers) { - this.map = map; - this.o = o; - this.modifiers = modifiers; - } - - private HashMap get() { - for (Field field : o.getClass().getDeclaredFields()) { - if ((field.getModifiers() & modifiers) == 0 && !field.isSynthetic()) - try { - SerializedName node = field.getAnnotation(SerializedName.class); - if (!field.isAccessible()) field.setAccessible(true); - Object obj = field.get(o); - map.put(node == null ? field.getName() : node.value(), serialize(obj)); - } catch (Exception ignored) { - } - } - return map; - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - private Object serialize(Object o) { - try { - if (o.getClass().isPrimitive() || primitiveType.contains(o.getClass())) { - return o; - } else if (o.getClass().isArray()) { - return ImmutableList.copyOf(((Object[]) o)); - } else if (o instanceof Collection) { - return ((Collection) o).stream().map(this::serialize).collect(Collectors.toList()); - } else if (o instanceof Map) { - Map map = new LinkedHashMap<>(); - ((Map) o).forEach((o1, o2) -> map.put(o1, serialize(o2))); - return map; - } else if (o instanceof ConfigurationSerializable) { - Map map = new LinkedHashMap<>(); - map.put(ConfigurationSerialization.SERIALIZED_TYPE_KEY, - ConfigurationSerialization.getAlias((Class) o.getClass())); - map.putAll(((ConfigurationSerializable) o).serialize()); - return map; - } else if (o instanceof Property) { - return serialize(((Property) o).get()); - } else { - return new Serializer(new HashMap<>(), o, modifiers).get(); - } - } catch (Exception ignored) { - return null; - } - } - - } - } diff --git a/src/main/java/com/ilummc/tlib/util/Ref.java b/src/main/java/com/ilummc/tlib/util/Ref.java index 8e83627..0ee1f1e 100644 --- a/src/main/java/com/ilummc/tlib/util/Ref.java +++ b/src/main/java/com/ilummc/tlib/util/Ref.java @@ -1,25 +1,18 @@ package com.ilummc.tlib.util; -import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - -import javax.annotation.concurrent.ThreadSafe; - -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassWriter; - +import com.google.gson.annotations.SerializedName; import com.ilummc.tlib.TLib; import com.ilummc.tlib.util.asm.AsmAnalyser; - +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; import sun.reflect.Reflection; +import javax.annotation.concurrent.ThreadSafe; +import java.lang.reflect.Field; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + @ThreadSafe public class Ref { @@ -70,7 +63,20 @@ public class Ref { public static Optional> getCallerClass(int depth) { return Optional.ofNullable(CallerClass.impl.getCallerClass(depth + 1)); } - + + public static String getSerializedName(Field field) { + return field.isAnnotationPresent(SerializedName.class) ? field.getAnnotation(SerializedName.class).value() : field.getName(); + } + + public static Optional getFieldBySerializedName(Class clazz, String name) { + for (Field field : Ref.getDeclaredFields(clazz, 0, false)) { + if (field.isAnnotationPresent(SerializedName.class)) + if (field.getAnnotation(SerializedName.class).value().equals(name)) return Optional.of(field); + else if (field.getName().equals(name)) return Optional.of(field); + } + return Optional.empty(); + } + private static abstract class CallerClass { private static CallerClass impl; @@ -87,9 +93,9 @@ public class Ref { abstract Class getCallerClass(int i); private static class ReflectionImpl extends CallerClass { - - @SuppressWarnings({ "deprecation", "restriction" }) - @Override + + @SuppressWarnings({"deprecation", "restriction"}) + @Override Class getCallerClass(int i) { return Reflection.getCallerClass(i); } diff --git a/src/main/java/me/skymc/taboolib/fileutils/ConfigUtils.java b/src/main/java/me/skymc/taboolib/fileutils/ConfigUtils.java index ead25ad..b7a5658 100644 --- a/src/main/java/me/skymc/taboolib/fileutils/ConfigUtils.java +++ b/src/main/java/me/skymc/taboolib/fileutils/ConfigUtils.java @@ -1,68 +1,183 @@ package me.skymc.taboolib.fileutils; +import com.google.common.base.Charsets; +import com.google.common.collect.Maps; +import com.ilummc.tlib.TLib; +import com.ilummc.tlib.util.Ref; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.MemoryConfiguration; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.Plugin; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder; + import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.io.StringReader; - -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.plugin.Plugin; -import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder; - -import com.google.common.base.Charsets; -import com.ilummc.tlib.TLib; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.LinkedHashMap; +import java.util.Map; public class ConfigUtils { - - public static FileConfiguration decodeYAML(String args) { - return YamlConfiguration.loadConfiguration(new StringReader(Base64Coder.decodeString(args))); - } - - public static String encodeYAML(FileConfiguration file) { - return Base64Coder.encodeLines(file.saveToString().getBytes()).replaceAll("\\s+", ""); - } - - /** - * 以 UTF-8 的格式释放配置文件并载入 - * - * 录入时间:2018年2月10日21:28:30 - * 录入版本:3.49 - * - * @param plugin - * @return - */ - public static FileConfiguration saveDefaultConfig(Plugin plugin, String name) { - File file = new File(plugin.getDataFolder(), name); - if (!file.exists()) { - plugin.saveResource(name, true); - } - return load(plugin, file); - } - - /** - * 以 UTF-8 的格式载入配置文件 - * - * @return - */ - public static FileConfiguration load(Plugin plugin, File file) { - return loadYaml(plugin, file); - } - - public static YamlConfiguration loadYaml(Plugin plugin, File file) { - YamlConfiguration yaml = new YamlConfiguration(); - try { - yaml = YamlConfiguration.loadConfiguration(new InputStreamReader(new FileInputStream(file), Charsets.UTF_8)); - } catch (Exception e) { - TLib.getTLib().getLogger().error("配置文件载入失败!"); - TLib.getTLib().getLogger().error("插件: &4" + plugin.getName()); - TLib.getTLib().getLogger().error("文件: &4" + file); - } - return yaml; - } - - @Deprecated - public static FileConfiguration load(Plugin plugin, String file) { - return load(plugin, FileUtils.file(file)); - } + + private static final Yaml YAML; + + static { + DumperOptions options = new DumperOptions(); + options.setAllowUnicode(false); + options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + YAML = new Yaml(options); + } + + @SuppressWarnings("unchecked") + public static Map yamlToMap(String yamlText) { + return YAML.loadAs(yamlText, LinkedHashMap.class); + } + + public static MemoryConfiguration objToConf(Object object) { + return mapToConf(objToMap(object)); + } + + public static MemoryConfiguration objToConf(Object object, int excludedModifiers) { + return mapToConf(objToMap(object, excludedModifiers)); + } + + public static Object confToObj(MemoryConfiguration configuration, Class clazz) { + try { + return mapToObj(configuration.getValues(false), clazz.newInstance()); + } catch (InstantiationException | IllegalAccessException e) { + return null; + } + } + + public static Object confToObj(MemoryConfiguration configuration, T obj) { + return mapToObj(configuration.getValues(false), obj); + } + + public static String mapToYaml(Map map) { + String dump = YAML.dump(map); + if (dump.equals("{}\n")) { + dump = ""; + } + return dump; + } + + public static MemoryConfiguration mapToConf(Map map) { + MemoryConfiguration configuration = new MemoryConfiguration(); + convertMapsToSections(map, configuration); + return configuration; + } + + public static Map confToMap(MemoryConfiguration configuration) { + return configuration.getValues(false); + } + + /** + * 将会在该类无默认构造方法时返回 null + */ + public static T mapToObj(Map map, Class clazz) { + try { + return mapToObj(map, clazz.newInstance()); + } catch (InstantiationException | IllegalAccessException e) { + return null; + } + } + + public static T mapToObj(Map map, T obj) { + Class clazz = obj.getClass(); + map.forEach((string, value) -> Ref.getFieldBySerializedName(clazz, string).ifPresent(field -> { + if (!field.isAccessible()) + field.setAccessible(true); + try { + field.set(obj, value); + } catch (IllegalAccessException ignored) { + } + })); + return obj; + } + + public static Map objToMap(Object object) { + return objToMap(object, Modifier.TRANSIENT & Modifier.STATIC & Ref.ACC_SYNTHETIC); + } + + public static Map objToMap(Object object, int excludedModifiers) { + Map map = Maps.newHashMap(); + for (Field field : Ref.getDeclaredFields(object.getClass(), excludedModifiers, false)) { + try { + if (!field.isAccessible()) field.setAccessible(true); + map.put(Ref.getSerializedName(field), field.get(object)); + } catch (IllegalAccessException ignored) { + } + } + return map; + } + + private static void convertMapsToSections(Map input, ConfigurationSection section) { + for (Object o : input.entrySet()) { + Map.Entry entry = (Map.Entry) o; + String key = entry.getKey().toString(); + Object value = entry.getValue(); + if (value instanceof Map) { + convertMapsToSections((Map) value, section.createSection(key)); + } else { + section.set(key, value); + } + } + } + + public static FileConfiguration decodeYAML(String args) { + return YamlConfiguration.loadConfiguration(new StringReader(Base64Coder.decodeString(args))); + } + + public static String encodeYAML(FileConfiguration file) { + return Base64Coder.encodeLines(file.saveToString().getBytes()).replaceAll("\\s+", ""); + } + + /** + * 以 UTF-8 的格式释放配置文件并载入 + *

+ * 录入时间:2018年2月10日21:28:30 + * 录入版本:3.49 + * + * @param plugin + * @return + */ + public static FileConfiguration saveDefaultConfig(Plugin plugin, String name) { + File file = new File(plugin.getDataFolder(), name); + if (!file.exists()) { + plugin.saveResource(name, true); + } + return load(plugin, file); + } + + /** + * 以 UTF-8 的格式载入配置文件 + * + * @return + */ + public static FileConfiguration load(Plugin plugin, File file) { + return loadYaml(plugin, file); + } + + public static YamlConfiguration loadYaml(Plugin plugin, File file) { + YamlConfiguration yaml = new YamlConfiguration(); + try { + yaml = YamlConfiguration.loadConfiguration(new InputStreamReader(new FileInputStream(file), Charsets.UTF_8)); + } catch (Exception e) { + TLib.getTLib().getLogger().error("配置文件载入失败!"); + TLib.getTLib().getLogger().error("插件: &4" + plugin.getName()); + TLib.getTLib().getLogger().error("文件: &4" + file); + } + return yaml; + } + + + @Deprecated + public static FileConfiguration load(Plugin plugin, String file) { + return load(plugin, FileUtils.file(file)); + } }