WILLIAM WOODMAN
WILLIAM WOODMAN

Reputation: 1231

Groovy ConfigSlurper is only partially building the structure when parsed

I am building a library for myself and using ConfigSlurper to parse a config.groovy file, and other config sources into an aggregated ConfigObject that I am using Micronaught compile time IOC to inject

    @Bean
    @Named('config')
    ConfigObject config () {

        Map envMap = [:]
        def sysProps = System.getenv()
        if (System.getProperty("env") ) {
            envMap = System.getenv().findResult { it.key?.toLowerCase().contains "env" }.collect { [(it.key?.toLowerCase().substring(0, 2)): it.value.toLowerCase()] }
        } else
            envMap.get ('env', "development")
        def env = envMap.get('env')

        def resourcePath = "src${File.separatorChar}${env =="test" ?: "main"}${File.separatorChar}resources${File.separatorChar}"
        ConfigObject config = new ConfigSlurper().parse(new File("${resourcePath}ApplicationConfig.groovy").text /*.toURI().toURL()*/)
        config.put('systemProperties', sysProps)
        config.putAll(envMap)

        config.put('projectPath', System.getProperty("user.dir"))
        config.put('resourcesPath', resourcePath.toString())

        File resourceDirectory = new File ("${System.getProperty("user.dir")}$File.separatorChar$resourcePath")
        FilenameFilter filter = {file, name -> name.matches(~/^.*properties$/) }
        List propsFiles = resourceDirectory.listFiles (filter)

        filter = {file, name -> name.matches(~/^.*yaml$/) }
        List yamlFiles = resourceDirectory.listFiles (filter)

        propsFiles.each {file ->
            Properties prop = new Properties()
            prop.load(new FileInputStream (file) )
            Map propsMap = [:]
            for (key in prop.stringPropertyNames()) {
                propsMap.put(key, prop.getProperty(key))
            }
            config.putAll(propsMap)
        }

        yamlFiles.each {file ->
            def yamlConfig = new YamlSlurper().parseText(file.text)
            config.putAll(yamlConfig)
        }

        config
    }

the resources/applicationConfig.groovy file looks like this

    framework {
        environments {
            development {
                server = "local" // choice of {local|clustered}
                vertxOptions {
    
                }
    
            }
            test {
                server = "local" // choice of {local|clustered}
                vertxOptions {
    
                }
    
            }
            production {
                server = "clustered" // choice of {local|clustered}
                vertxOptions {
    
                }
    
            }
        }
    }

The code parses the groovy file but when I look at what in the configObject, its created the tope level framework map entry - but the lower levels are not there.

calling configObject.framework in code returns the object but it is of size() == 0!

I don't understand why the rest of the structure is not getting built.

Can any one advise why the internal structure is not being parsed and built.

Can anyone suggest what I have done wrong ?

I have just done a stripped back version like this

    def configText = """
    
    framework {
        environments {
            development {
                server = "local" // choice of {local|clustered}
                vertxOptions {
    
                }
    
            }
            test {
                server = "local" // choice of {local|clustered}
                vertxOptions {
    
                }
    
            }
            production {
                server = "clustered" // choice of {local|clustered}
                vertxOptions {
    
                }
    
            }
        }
    }
    """
    
    ConfigObject conf = new ConfigSlurper().parse(configText)
    assert conf.framework?.environments?.size() == 3

where the error shows this

    Caught: Assertion failed: 
    
    assert conf.framework?.environments?.size() == 3
           |    |          |             |      |
           |    |          [:]           0      false
           |    ['environments':[:]]
           ['framework':['environments':[:]]]
    
    Assertion failed: 
    
    assert conf.framework?.environments?.size() == 3
           |    |          |             |      |
           |    |          [:]           0      false
           |    ['environments':[:]]
           ['framework':['environments':[:]]]
    
        at scripts.configSlurperTest.run(configSlurperTest.groovy:33)
        at

Upvotes: 1

Views: 120

Answers (1)

tim_yates
tim_yates

Reputation: 171124

The environments section when parsed by configslurper is conditional to the environment you pass to the constructor of ConfigSlurper itself.

Lets say you want the development config to be the default, but then you want to override this when run in test or production, you would do the following:

def configText = """

framework {

    // defaults
    
    mode = 'development'
    server = "local" // choice of {local|clustered}
    vertxOptions {

    }
    
    environments {
        // test settings
        test {
            mode = 'testing'
            
            server = "local" // choice of {local|clustered}
            vertxOptions {

            }

        }
        
        // production settings
        production {
            mode = 'live!'
            
            server = "clustered" // choice of {local|clustered}
            vertxOptions {

            }

        }
    }
}
"""

// Default values
assert new ConfigSlurper().parse(configText).framework.mode == 'development'
// Test values
assert new ConfigSlurper('test').parse(configText).framework.mode == 'testing'
// Production values
assert new ConfigSlurper('production').parse(configText).framework.mode == 'live!'

Upvotes: 2

Related Questions