{"id":12552,"date":"2015-09-20T16:09:00","date_gmt":"2015-09-20T15:09:00","guid":{"rendered":"https:\/\/touk.pl\/blog\/?guid=ab744f3d01827fe093659c423d218d69"},"modified":"2022-07-29T12:34:06","modified_gmt":"2022-07-29T10:34:06","slug":"easy-configuration-usage-with-configslurper","status":"publish","type":"post","link":"https:\/\/touk.pl\/blog\/2015\/09\/20\/easy-configuration-usage-with-configslurper\/","title":{"rendered":"Easy configuration usage with ConfigSlurper"},"content":{"rendered":"<h1 id=\"whats-the-problem\">What&#8217;s the problem?<\/h1>\n<p>We have to deal with properties in almost every projects that we write. <a href=\"http:\/\/docs.oracle.com\/javase\/8\/docs\/api\/java\/util\/Properties.html\">Properties<\/a> class, which we use in these cases, is just mapping key to value. Sometimes it is fine, but in many cases properties look like tree. Example of properties file is shown below:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">systemName=test\r\nendpoint.first.protocol=http\r\nendpoint.first.address=localhost\r\nendpoint.first.port=8080\r\nendpoint.first.path=test\r\nendpoint.second.protocol=ftp\r\nendpoint.second.address=localhost\r\nendpoint.second.port=21\r\nendpoint.second.user=admin\r\nendpoint.second.password=pass\r\n<\/pre>\n<p>Here we have simple properties like systemName and also complex endpoints definition (all properties which start with <i>endpoint<\/i>) and single endpoints definition (each endpoint properties starts with <i>endpoint.&lt;ENDPOINT_NAME&gt;<\/i>).<\/p>\n<p>How simple could it be to treat this properties like a tree and simply extract subset of them?<\/p>\n<p>The answer is using <a href=\"http:\/\/docs.groovy-lang.org\/latest\/html\/gapi\/groovy\/util\/ConfigSlurper.html\">ConfigSlurper<\/a>.<\/p>\n<h1 id=\"configslurper-from-properties\">ConfigSlurper from properties<\/h1>\n<p>To use ConfigSlurper just parse properties object:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\">def 'should import configuration from properties'() {\r\n    given: Properties p = new Properties()\r\n    p.load(ConfigSlurperTest.getResourceAsStream('\/configuration.properties'))\r\n    expect: new ConfigSlurper().parse(p).systemName as String == 'test'\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>Parse method returns <a href=\"http:\/\/docs.groovy-lang.org\/latest\/html\/gapi\/groovy\/util\/ConfigObject.html\">ConfigObject<\/a> which is just very clever map <a href=\"http:\/\/\">Map<\/a>.<\/p>\n<p>Now you could get property using dot notation:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\">def 'should get nested property'() {\r\n    expect:\r\n        fromProperties.endpoint.first.protocol == 'http'\r\n}<\/pre>\n<p>But there is a deal. If you use ConfigObject then you cannot use it like normal Properties and get property with dots.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\">def 'should not used nested property as one string'() {\r\n    expect:\r\n        fromProperties.'endpoint.first.protocol' != 'http'\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>ConfigObject allows you to extract subtree as Properties:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\">def 'should get first endpoint info from properties'() {\r\n    expect:\r\n        fromProperties.endpoint.first.toProperties() == [\r\n            protocol: 'http',\r\n            address : 'localhost',\r\n            port    : '8080',\r\n            path    : 'test'\r\n        ]\r\n}<\/pre>\n<p>and even:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\">def 'should allow for nested property as one string when toProperties called'() {\r\n    expect: fromProperties.endpoint.toProperties()['first.protocol'] == 'http'\r\n}<\/pre>\n<p>If you want to know how many endpoint you have and how they are named you could use keySet method:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\">def 'should get list of endpoints'() {\r\n    expect: fromProperties.endpoint.keySet() == ['first', 'second'] as Set\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>ConfigSlurper do not return null even if property is not found, so you could get nested property without fear:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\">def 'should not throw exception when missing property'() {\r\n    expect: fromProperties.endpoint.third.port.toProperties() == [: ] as Properties\r\n}<\/pre>\n<p>You have only to be careful, when have property named like begining of another property:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\">def 'should throw exception when asking for too nested property'() {\r\n    when:\r\n        fromProperties.endpoint.first.port.test\r\n    then:\r\n        thrown(MissingPropertyException)\r\n}<\/pre>\n<p><i>fromProperties.endpoint.first.port<\/i> returns String and do not have test property.<\/p>\n<p>You could also print properties from ConfigObject:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\">println fromProperties.prettyPrint()<\/pre>\n<p>The output looks like this:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">endpoint {\r\n    first {\r\n        path='test'\r\n        port='8080'\r\n        protocol='http'\r\n        address='localhost'\r\n    }\r\n    second {\r\n        password='pass'\r\n        protocol='ftp'\r\n        address='localhost'\r\n        port='21'\r\n        user='admin'\r\n    }\r\n}\r\nsystemName='test'<\/pre>\n<p>Hmm&#8230; It looks like DSL. Why do not keep your configuration in this manner?<\/p>\n<h1 id=\"configslurper-from-script\">ConfigSlurper from script<\/h1>\n<p>Your configuration could be a groovy script.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">systemName = 'test'\r\nendpoint {\r\n    first {\r\n        path = 'test'\r\n        port = 8080\r\n        protocol = 'http'\r\n        address = 'localhost'\r\n    }\r\n    second {\r\n        password = 'pass'\r\n        protocol = 'ftp'\r\n        address = 'localhost'\r\n        port = 21\r\n        user = 'admin'\r\n    }\r\n}\r\ntest.key = ['really': 'nested?'] as Properties<\/pre>\n<p>You could pass such configuration as resource stream or file content:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\">def 'should get config from script as url'() {\r\n    given: ConfigObject config = new ConfigSlurper().parse(ConfigSlurperTest.getResource('\/configuration.groovy'))\r\n    expect: config.systemName == 'test'\r\n}<\/pre>\n<p>What interesting all your properties do not have to be strings. It could be any object: String, long, int, etc.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\">def 'should get nested properties from script as int'() {\r\n    expect: fromScript.endpoint.first.port == 8080\r\n}<\/pre>\n<h1 id=\"conclusion\">Conclusion<\/h1>\n<p>You could deal with properties like simple Map, but why if you could instead use it like tree of properties?<\/p>\n<p>Sources are available <a href=\"https:\/\/github.com\/alien11689\/ConfigSlurperDemo\">here<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"What&#8217;s the problem?We have to deal with properties in almost every projects that we write. Properties class, which we use in these cases, is just mapping key to value. Sometimes it is fine, but in many cases properties look like tree. Example of proper&#8230;\n","protected":false},"author":54,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11],"tags":[50],"_links":{"self":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/12552"}],"collection":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/users\/54"}],"replies":[{"embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/comments?post=12552"}],"version-history":[{"count":9,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/12552\/revisions"}],"predecessor-version":[{"id":14712,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/12552\/revisions\/14712"}],"wp:attachment":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/media?parent=12552"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/categories?post=12552"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/tags?post=12552"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}