From 85e43727cfc17fb1e910173665ef84b1d8b7c16d Mon Sep 17 00:00:00 2001 From: Mark Vainomaa Date: Thu, 25 Oct 2018 12:36:04 +0300 Subject: [PATCH] Improve code style, grammar and other fixes --- .../proxy/config/AnnotatedConfig.java | 142 +++++++++++------- 1 file changed, 86 insertions(+), 56 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/config/AnnotatedConfig.java b/proxy/src/main/java/com/velocitypowered/proxy/config/AnnotatedConfig.java index 55b87d405..61c967ead 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/config/AnnotatedConfig.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/config/AnnotatedConfig.java @@ -3,7 +3,6 @@ package com.velocitypowered.proxy.config; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.io.File; import java.io.IOException; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -11,9 +10,12 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Field; import java.nio.charset.StandardCharsets; -import java.nio.file.*; +import java.nio.file.AtomicMoveNotSupportedException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.nio.file.StandardOpenOption; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -35,7 +37,6 @@ public class AnnotatedConfig { @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.TYPE}) public @interface Table { - String value(); } @@ -45,7 +46,6 @@ public class AnnotatedConfig { @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.TYPE}) public @interface Comment { - String[] value(); } @@ -55,7 +55,6 @@ public class AnnotatedConfig { @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.TYPE}) public @interface ConfigKey { - String value(); } @@ -65,96 +64,125 @@ public class AnnotatedConfig { */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.TYPE}) - public @interface IsMap { - } + public @interface IsMap {} /** * Indicates that a field is a string converted to byte[] */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.TYPE}) - public @interface StringAsBytes { - } + public @interface StringAsBytes {} /** - * Indicates that a field should be skiped + * Indicates that a field should be skipped */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) - public @interface Ignore { - } + public @interface Ignore {} + /** + * Dumps this configuration to list of strings using {@link #dumpConfig(Object)} + * @return configuration dump + */ public List dumpConfig() { - List lines = new ArrayList<>(); - dumpFields(this, lines); - return lines; + return dumpConfig(this); } /** - * Dump all field and they annotations to List + * Creates TOML configuration from supplied
dumpable
object. * - * @param toSave object those we need to dump - * @param lines a list where store dumped lines + * @param dumpable object which is going to be dumped + * @throws RuntimeException if reading field value(s) fail + * @return string list of configuration file lines */ - private void dumpFields(Object toSave, List lines) { - + private static List dumpConfig(Object dumpable) { + List lines = new ArrayList<>(); try { - for (Field field : toSave.getClass().getDeclaredFields()) { - if (field.getAnnotation(Ignore.class) != null) { //Skip this field + for (Field field : dumpable.getClass().getDeclaredFields()) { + // Skip fields with @Ignore annotation + if (field.getAnnotation(Ignore.class) != null) { continue; } + + // Make field accessible + field.setAccessible(true); + + // Add comments Comment comment = field.getAnnotation(Comment.class); - if (comment != null) { //Add comments + if (comment != null) { for (String line : comment.value()) { lines.add("# " + line); } } - ConfigKey key = field.getAnnotation(ConfigKey.class); //Get a key name for config - String name = key == null ? field.getName() : key.value(); // Use a field name if name in annotation is not present - field.setAccessible(true); // Make field accessible + + // Get a key name for config + ConfigKey key = field.getAnnotation(ConfigKey.class); + String name = key == null ? field.getName() : key.value(); // Use field name if @ConfigKey annotation is not present + + // Check if field is table. Table table = field.getAnnotation(Table.class); - if (table != null) { // Check if field is table. - lines.add(table.value()); // Write [name] - dumpFields(field.get(toSave), lines); // dump fields of table class - } else { - if (field.getAnnotation(IsMap.class) != null) { // check if field is map - Map map = (Map) field.get(toSave); - for (Entry entry : map.entrySet()) { - lines.add(safeKey(entry.getKey()) + " = " + toString(entry.getValue())); // Save a map data - } - lines.add(""); //Add empty line - continue; - } - Object value = field.get(toSave); - if (field.getAnnotation(StringAsBytes.class) != null) { // Check if field is a byte[] representation of a string - value = new String((byte[]) value, StandardCharsets.UTF_8); - } - lines.add(name + " = " + toString(value)); // save field to config - lines.add(""); // add empty line + if (table != null) { + lines.add(table.value()); // Write [name] + lines.addAll(dumpConfig(field.get(dumpable))); // dump fields of table + continue; } + + if (field.getAnnotation(IsMap.class) != null) { // check if field is map + @SuppressWarnings("unchecked") + Map map = (Map) field.get(dumpable); + for (Entry entry : map.entrySet()) { + lines.add(entry.getKey() + " = " + serialize(entry.getValue())); // Save map data + } + lines.add(""); //Add empty line + continue; + } + + Object value = field.get(dumpable); + + // Check if field is a byte[] representation of a string + if (field.getAnnotation(StringAsBytes.class) != null) { + value = new String((byte[]) value, StandardCharsets.UTF_8); + } + + // Save field to config + lines.add(name + " = " + serialize(value)); + lines.add(""); // add empty line } } catch (IllegalAccessException | IllegalArgumentException | SecurityException e) { - throw new RuntimeException("Can not dump config", e); + throw new RuntimeException("Could not dump configuration", e); } + + return lines; } - private String toString(Object value) { + /** + * Serializes
value
so it could be parsed by TOML specification + * + * @param value object to serialize + * @return Serialized object + */ + private static String serialize(Object value) { if (value instanceof List) { - Collection listValue = (Collection) value; + List listValue = (List) value; if (listValue.isEmpty()) { return "[]"; } + StringBuilder m = new StringBuilder(); m.append("["); + for (Object obj : listValue) { - m.append(System.lineSeparator()).append(" ").append(toString(obj)).append(","); + m.append(System.lineSeparator()).append(" ").append(serialize(obj)).append(","); } + m.deleteCharAt(m.length() - 1).append(System.lineSeparator()).append("]"); return m.toString(); } + if (value instanceof Enum) { value = value.toString(); } + if (value instanceof String) { String stringValue = (String) value; if (stringValue.isEmpty()) { @@ -162,6 +190,7 @@ public class AnnotatedConfig { } return "\"" + stringValue.replace("\n", "\\n") + "\""; } + return value != null ? value.toString() : "null"; } @@ -173,23 +202,24 @@ public class AnnotatedConfig { } /** - * Saves lines to file + * Writes list of strings to file * - * @param lines Lines to save - * @param to A path of file where to save lines - * @throws IOException if lines is empty or was error during saving + * @param lines list of strings to write + * @param to Path of file where lines should be written + * @throws IOException if error occurred during writing + * @throws IllegalArgumentException if
lines
is empty list */ public static void saveConfig(List lines, Path to) throws IOException { if (lines.isEmpty()) { - throw new IOException("Can not save config because list is empty"); + throw new IllegalArgumentException("lines cannot be empty"); } - Path temp = new File(to.toFile().getParent(), "__tmp").toPath(); + + Path temp = to.getParent().resolve(to.getFileName().toString() + "__tmp"); Files.write(temp, lines, StandardCharsets.UTF_8, StandardOpenOption.CREATE); try { Files.move(temp, to, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); } catch (AtomicMoveNotSupportedException e) { Files.move(temp, to, StandardCopyOption.REPLACE_EXISTING); } - } }