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 df250bf41..f9abe6991 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 @@ -144,8 +144,8 @@ public class YamlConfiguration extends FileConfiguration { private void fromNodeTree(@NotNull MappingNode input, @NotNull ConfigurationSection section) { constructor.flattenMapping(input); for (NodeTuple nodeTuple : input.getValue()) { - ScalarNode key = (ScalarNode) nodeTuple.getKeyNode(); - String keyString = key.getValue(); + Node key = nodeTuple.getKeyNode(); + String keyString = String.valueOf(constructor.construct(key)); Node value = nodeTuple.getValueNode(); while (value instanceof AnchorNode) { @@ -169,7 +169,9 @@ public class YamlConfiguration extends FileConfiguration { private boolean hasSerializedTypeKey(MappingNode node) { for (NodeTuple nodeTuple : node.getValue()) { - String key = ((ScalarNode) nodeTuple.getKeyNode()).getValue(); + Node keyNode = nodeTuple.getKeyNode(); + if (!(keyNode instanceof ScalarNode)) continue; + String key = ((ScalarNode) keyNode).getValue(); if (key.equals(ConfigurationSerialization.SERIALIZED_TYPE_KEY)) { return true; } @@ -180,7 +182,7 @@ public class YamlConfiguration extends FileConfiguration { private MappingNode toNodeTree(@NotNull ConfigurationSection section) { List nodeTuples = new ArrayList<>(); for (Map.Entry entry : section.getValues(false).entrySet()) { - ScalarNode key = (ScalarNode) representer.represent(entry.getKey()); + Node key = representer.represent(entry.getKey()); Node value; if (entry.getValue() instanceof ConfigurationSection) { value = toNodeTree((ConfigurationSection) entry.getValue()); diff --git a/paper-api/src/main/java/org/bukkit/configuration/file/YamlConstructor.java b/paper-api/src/main/java/org/bukkit/configuration/file/YamlConstructor.java index 7052f8a56..092599425 100644 --- a/paper-api/src/main/java/org/bukkit/configuration/file/YamlConstructor.java +++ b/paper-api/src/main/java/org/bukkit/configuration/file/YamlConstructor.java @@ -22,7 +22,7 @@ public class YamlConstructor extends SafeConstructor { super.flattenMapping(node); } - @NotNull + @Nullable public Object construct(@NotNull Node node) { return constructObject(node); } 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 a0ff42abd..3522baa0a 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 @@ -174,4 +174,31 @@ public class YamlConfigurationTest extends FileConfigurationTest { assertEquals(expected, result); } + + @Test + public void testUnusualMappingKeys() throws InvalidConfigurationException { + YamlConfiguration config = getConfig(); + String content = "[1]: odd\n" + + "{2}: choice\n" + + "\"3\": of\n" + + "4: keys\n" + + "null: A\n" + + "'null': B\n" + + "!!null null: C\n" + + "'!!null': X\n"; + // The keys are parsed as arbitrary Yaml types and then converted to their String representation during config loading. + // Consequently, the String representation used by the loaded config might be different to how these keys were originally represented. + // Since SnakeYaml does not preserve the original representation in its parsed node tree, we are also not able to reconstruct the original keys during config loading. + config.loadFromString(content); + + // This difference in representations also becomes apparent when the config is written back. + // Also note: All keys that are parsed as null overwrite each other's values. + String expected = "'[1]': odd\n" + + "'{2=null}': choice\n" + + "'3': of\n" + + "'4': keys\n" + + "'null': C\n" + + "'!!null': X\n"; + assertEquals(expected, config.saveToString()); + } }