From 37b3cb4a30824566cfe5bacbae995957db095a72 Mon Sep 17 00:00:00 2001 From: md_5 Date: Mon, 15 Aug 2016 18:41:52 +1000 Subject: [PATCH] #1934: Better in memory config representation --- .../net/md_5/bungee/config/Configuration.java | 37 ++++++++++++++----- .../md_5/bungee/config/YamlConfiguration.java | 21 ++++++++++- .../bungee/config/YamlConfigurationTest.java | 29 ++++++++++++++- 3 files changed, 74 insertions(+), 13 deletions(-) diff --git a/config/src/main/java/net/md_5/bungee/config/Configuration.java b/config/src/main/java/net/md_5/bungee/config/Configuration.java index 1366f449..9f3464d9 100644 --- a/config/src/main/java/net/md_5/bungee/config/Configuration.java +++ b/config/src/main/java/net/md_5/bungee/config/Configuration.java @@ -7,10 +7,7 @@ import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import lombok.AccessLevel; -import lombok.RequiredArgsConstructor; -@RequiredArgsConstructor(access = AccessLevel.PACKAGE) public final class Configuration { @@ -28,6 +25,25 @@ public final class Configuration this( new LinkedHashMap(), defaults ); } + Configuration(Map map, Configuration defaults) + { + this.self = new LinkedHashMap<>(); + this.defaults = defaults; + + for ( Map.Entry entry : map.entrySet() ) + { + String key = entry.getKey().toString(); + + if ( entry.getValue() instanceof Map ) + { + this.self.put( key, new Configuration( (Map) entry.getValue(), ( defaults == null ) ? null : defaults.getSection( key ) ) ); + } else + { + this.self.put( key, entry.getValue() ); + } + } + } + private Configuration getSectionFor(String path) { int index = path.indexOf( SEPARATOR ); @@ -40,15 +56,11 @@ public final class Configuration Object section = self.get( root ); if ( section == null ) { - section = new LinkedHashMap<>(); + section = new Configuration( ( defaults == null ) ? null : defaults.getSection( path ) ); self.put( root, section ); } - if ( section instanceof Configuration ) - { - return (Configuration) section; - } - return new Configuration( (Map) section, ( defaults == null ) ? null : defaults.getSectionFor( path ) ); + return (Configuration) section; } private String getChild(String path) @@ -71,6 +83,11 @@ public final class Configuration val = section.get( getChild( path ), def ); } + if ( val == null && def instanceof Configuration ) + { + self.put( path, def ); + } + return ( val != null ) ? (T) val : def; } @@ -106,7 +123,7 @@ public final class Configuration public Configuration getSection(String path) { Object def = getDefault( path ); - return new Configuration( (Map) ( get( path, ( def instanceof Map ) ? def : Collections.EMPTY_MAP ) ), ( defaults == null ) ? null : defaults.getSection( path ) ); + return (Configuration) get( path, ( def instanceof Configuration ) ? def : new Configuration( ( defaults == null ) ? null : defaults.getSection( path ) ) ); } /** diff --git a/config/src/main/java/net/md_5/bungee/config/YamlConfiguration.java b/config/src/main/java/net/md_5/bungee/config/YamlConfiguration.java index 0a936025..db8aa4be 100644 --- a/config/src/main/java/net/md_5/bungee/config/YamlConfiguration.java +++ b/config/src/main/java/net/md_5/bungee/config/YamlConfiguration.java @@ -13,6 +13,10 @@ import lombok.AccessLevel; import lombok.NoArgsConstructor; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.Constructor; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.representer.Represent; +import org.yaml.snakeyaml.representer.Representer; @NoArgsConstructor(access = AccessLevel.PACKAGE) public class YamlConfiguration extends ConfigurationProvider @@ -23,9 +27,24 @@ public class YamlConfiguration extends ConfigurationProvider @Override protected Yaml initialValue() { + Representer representer = new Representer() + { + { + representers.put( Configuration.class, new Represent() + { + @Override + public Node representData(Object data) + { + return represent( ( (Configuration) data ).self ); + } + } ); + } + }; + DumperOptions options = new DumperOptions(); options.setDefaultFlowStyle( DumperOptions.FlowStyle.BLOCK ); - return new Yaml( options ); + + return new Yaml( new Constructor(), representer, options ); } }; diff --git a/config/src/test/java/net/md_5/bungee/config/YamlConfigurationTest.java b/config/src/test/java/net/md_5/bungee/config/YamlConfigurationTest.java index 8f15168f..df135b0f 100644 --- a/config/src/test/java/net/md_5/bungee/config/YamlConfigurationTest.java +++ b/config/src/test/java/net/md_5/bungee/config/YamlConfigurationTest.java @@ -10,7 +10,7 @@ import org.junit.Test; public class YamlConfigurationTest { - private String document = "" + private static final String TEST_DOCUMENT = "" + "receipt: Oz-Ware Purchase Invoice\n" + "date: 2012-08-06\n" + "customer:\n" @@ -43,11 +43,17 @@ public class YamlConfigurationTest + " Road to the Emerald City.\n" + " Pay no attention to the\n" + " man behind the curtain."; + private static final String NUMBER_TEST = "" + + "someKey:\n" + + " 1: 1\n" + + " 2: 2\n" + + " 3: 3\n" + + " 4: 4"; @Test public void testConfig() throws Exception { - Configuration conf = ConfigurationProvider.getProvider( YamlConfiguration.class ).load( document ); + Configuration conf = ConfigurationProvider.getProvider( YamlConfiguration.class ).load( TEST_DOCUMENT ); testSection( conf ); StringWriter sw = new StringWriter(); @@ -77,5 +83,24 @@ public class YamlConfigurationTest conf.set( "receipt", null ); Assert.assertEquals( null, conf.get( "receipt" ) ); Assert.assertEquals( "foo", conf.get( "receipt", "foo" ) ); + + Configuration newSection = conf.getSection( "new.section" ); + newSection.set( "value", "foo" ); + Assert.assertEquals( "foo", conf.get( "new.section.value" ) ); + + conf.set( "other.new.section", "bar" ); + Assert.assertEquals( "bar", conf.get( "other.new.section" ) ); + } + + @Test + public void testNumberedKeys() + { + Configuration conf = ConfigurationProvider.getProvider( YamlConfiguration.class ).load( NUMBER_TEST ); + + Configuration section = conf.getSection( "someKey" ); + for ( String key : section.getKeys() ) + { + // empty + } } }