From 7aec97546b95cf97d168aa5bac83682f0e42fada Mon Sep 17 00:00:00 2001 From: Bukkit/Spigot Date: Tue, 4 Jan 2022 09:25:20 +1100 Subject: [PATCH] Add workaround for SnakeYAML 100 comment limit By: md_5 --- .../bukkit/configuration/file/BukkitYaml.java | 74 +++++++++++++++++++ .../configuration/file/YamlConfiguration.java | 2 +- .../file/YamlConfigurationTest.java | 19 +++++ 3 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 paper-api/src/main/java/org/bukkit/configuration/file/BukkitYaml.java diff --git a/paper-api/src/main/java/org/bukkit/configuration/file/BukkitYaml.java b/paper-api/src/main/java/org/bukkit/configuration/file/BukkitYaml.java new file mode 100644 index 0000000000..ba20419c6d --- /dev/null +++ b/paper-api/src/main/java/org/bukkit/configuration/file/BukkitYaml.java @@ -0,0 +1,74 @@ +package org.bukkit.configuration.file; + +import java.io.IOException; +import java.io.Writer; +import java.lang.reflect.Field; +import java.util.ArrayDeque; +import java.util.Queue; +import org.jetbrains.annotations.NotNull; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.LoaderOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.comments.CommentEventsCollector; +import org.yaml.snakeyaml.comments.CommentType; +import org.yaml.snakeyaml.constructor.BaseConstructor; +import org.yaml.snakeyaml.emitter.Emitter; +import org.yaml.snakeyaml.error.YAMLException; +import org.yaml.snakeyaml.events.Event; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.representer.Representer; +import org.yaml.snakeyaml.serializer.Serializer; + +final class BukkitYaml extends Yaml { + + private static final Field events; + private static final Field blockCommentsCollector; + private static final Field inlineCommentsCollector; + + private static Field getEmitterField(String name) { + Field field = null; + try { + field = Emitter.class.getDeclaredField(name); + field.setAccessible(true); + } catch (ReflectiveOperationException ex) { + // Ignore as a fail-safe fallback + } + return field; + } + + static { + events = getEmitterField("events"); + blockCommentsCollector = getEmitterField("blockCommentsCollector"); + inlineCommentsCollector = getEmitterField("inlineCommentsCollector"); + } + + public BukkitYaml(@NotNull BaseConstructor constructor, @NotNull Representer representer, @NotNull DumperOptions dumperOptions, @NotNull LoaderOptions loadingConfig) { + super(constructor, representer, dumperOptions, loadingConfig); + } + + @Override + public void serialize(@NotNull Node node, @NotNull Writer output) { + Emitter emitter = new Emitter(output, dumperOptions); + if (events != null && blockCommentsCollector != null && inlineCommentsCollector != null) { + Queue newEvents = new ArrayDeque<>(100); + + try { + events.set(emitter, newEvents); + blockCommentsCollector.set(emitter, new CommentEventsCollector(newEvents, CommentType.BLANK_LINE, CommentType.BLOCK)); + inlineCommentsCollector.set(emitter, new CommentEventsCollector(newEvents, CommentType.IN_LINE)); + } catch (ReflectiveOperationException ex) { + // Don't ignore this as we could be in an inconsistent state + throw new RuntimeException("Could not update Yaml event queue", ex); + } + } + + Serializer serializer = new Serializer(emitter, resolver, dumperOptions, null); + try { + serializer.open(); + serializer.serialize(node); + serializer.close(); + } catch (IOException ex) { + throw new YAMLException(ex); + } + } +} diff --git a/paper-api/src/main/java/org/bukkit/configuration/file/YamlConfiguration.java b/paper-api/src/main/java/org/bukkit/configuration/file/YamlConfiguration.java index 019eec6a25..1ee942b478 100644 --- a/paper-api/src/main/java/org/bukkit/configuration/file/YamlConfiguration.java +++ b/paper-api/src/main/java/org/bukkit/configuration/file/YamlConfiguration.java @@ -64,7 +64,7 @@ public class YamlConfiguration extends FileConfiguration { yamlLoaderOptions = new LoaderOptions(); yamlLoaderOptions.setMaxAliasesForCollections(Integer.MAX_VALUE); // SPIGOT-5881: Not ideal, but was default pre SnakeYAML 1.26 - yaml = new Yaml(constructor, representer, yamlDumperOptions, yamlLoaderOptions); + yaml = new BukkitYaml(constructor, representer, yamlDumperOptions, yamlLoaderOptions); } @NotNull diff --git a/paper-api/src/test/java/org/bukkit/configuration/file/YamlConfigurationTest.java b/paper-api/src/test/java/org/bukkit/configuration/file/YamlConfigurationTest.java index 3e01af7643..01ede44449 100644 --- a/paper-api/src/test/java/org/bukkit/configuration/file/YamlConfigurationTest.java +++ b/paper-api/src/test/java/org/bukkit/configuration/file/YamlConfigurationTest.java @@ -144,4 +144,23 @@ public class YamlConfigurationTest extends FileConfigurationTest { + " height-offset: 2\n"; assertEquals(expected, config.saveToString()); } + + @Test + public void test100Comments() throws InvalidConfigurationException { + StringBuilder commentBuilder = new StringBuilder(); + for (int i = 0; i < 100; i++) { + commentBuilder.append("# Comment ").append(i).append("\n"); + } + + final String data = "" + + commentBuilder + + "simpleKey: simpleValue\n" + + "\n"; + + YamlConfiguration config = getConfig(); + config.loadFromString(data); + + String result = config.saveToString(); + assertEquals(data, result); + } }