Best practice for map configurations?

I got a map that extends three layers deep and on the other side I got a plugin that should check if a given three-set of strings is in the map. So far it’s a statically written map directly in the plugin file, but I want to change it so that user of the plugin can freely configure the map.

    def myMap =
    [
        'level1' :
        [
            'level21' :
            [
                'level31: true,
                'level32' : true,
                'level33' : true
            ],
            'level22' :
            [
                'level31' : true,
                'level32' : true
            ]
        ]
    ]

   assert myMap.get('level1').get('level21').get('level32') == true

Needless to say, this is a ton of syntax overhead and not exactly flexible either. My idea was that this could be written in an external .properties file as nested DSL, but I don’t know what the best way to do that.

Can you just use a single map with dots/slashes to separate levels?

def myMap = [
   'level1/level21/level31': true
   'level1/level21/level32': true
  ...
]

assert myMap['level1/level21/level32'] == true

Unfortunately not, because that would introduce a lot of duplication overhead, the very thing I’m trying to avoid here (e.g. “level1/level21/” would appear multiple times).

My ideal solution would look like this, but I don’t have any idea if there’s a way at all to replicate it:

myMap {
    level1 {
        level21 {
            level31
            level32
            level33
        }
        level22 {
            level31
            level32
        }
    }
}

You know, writing in plain text without a bunch of syntax characters what the map should be.

What you are looking for are named domain object containers. Have a look at the project.container method. That gives you exactly the syntax you are looking for.

This might give you some additional ideas as well http://mrhaki.blogspot.ca/2016/02/gradle-goodness-using-nested-domain.html?m=1

The ConfigSlurper seems to be what you are looking for. Below is some example code from this blog - Gradle Goodness: Using Properties for Multiple Environments or Profiles - Messages from mrhaki. I used ConfigSlurper all a lot as it gives me not only the mapping but also the different environments if I want.

// File: build.gradle
loadConfiguration()

task printProps << {
println “serverName: $config.serverName”
println “mail.server: $config.mail.server”
println “mail.port: $config.mail.port”
}

def loadConfiguration() {
def environment = hasProperty(‘env’) ? env : ‘dev’
setProperty ‘environment’, environment
println “Environment is set to $environment”

def configFile = file('config.groovy')
def config = new ConfigSlurper(environment).parse(configFile.toURL())
setProperty 'config', config

}

The configuration file looks like this.

// File: config.groovy
mail {
server = ‘localhost’
port = 25
}

environments {
dev {
serverName = ‘http://localhost:9090
}

test {
    serverName = 'http://testserver'
    mail {
        server = 'mail.testserver'
    }
}
 
prod {
    serverName = 'http://www.mrhaki.com'
    mail {
        port = 552
        server = 'mail.host.com'
    }
}

}