Search

Dark theme | Light theme

October 3, 2018

Micronaut Mastery: Configuration Property Name Is Lowercased And Hyphen Separated

In Micronaut we can inject configuration properties in different ways into our beans. We can use for example the @Value annotation using a string value with a placeholder for the configuration property name. If we don't want to use a placeholder we can also use the @Property annotation and set the name attribute to the configuration property name. We have to pay attention to the format of the configuration property name we use. If we refer to a configuration property name using @Value or @Property we must use lowercased and hyphen separated names (also known as kebab casing). Even if the name of the configuration property is camel cased in the configuration file. For example if we have a configuration property sample.theAnswer in our application.properties file, we must use the name sample.the-answer to get the value.

In the following Spock specification we see how to use it in code. The specification defines two beans that use the @Value and @Property annotations and we see that we need to use kebab casing for the configuration property names, even though we use camel casing to set the configuration property values:

package mrhaki

import groovy.transform.CompileStatic
import io.micronaut.context.ApplicationContext
import io.micronaut.context.annotation.Property
import io.micronaut.context.annotation.Value
import io.micronaut.context.exceptions.DependencyInjectionException
import spock.lang.Shared
import spock.lang.Specification

import javax.inject.Singleton

class ConfigurationPropertyNameSpec extends Specification {

    // Create application context with two configuration 
    // properties: reader.maxFileSize and reader.showProgress.
    @Shared
    private ApplicationContext context = 
            ApplicationContext.run('reader.maxFileSize': 1024, 
                                   'reader.showProgress': true)

    void "use kebab casing (hyphen-based) to get configuration property value"() {
        expect:
        with(context.getBean(FileReader)) {
            maxFileSize == 1024   
            showProgress == Boolean.TRUE
        }
    }

    void "using camel case to get configuration property should throw exception"() {
        when:
        context.getBean(InvalidFileReader).maxFileSize

        then:
        final dependencyException = thrown(DependencyInjectionException)
        dependencyException.message == """\
            |Failed to inject value for parameter [maxFileSize] of method [setMaxFileSize] of class: mrhaki.InvalidFileReader
            |
            |Message: Error resolving property value [\${reader.maxFileSize}]. Property doesn't exist
            |Path Taken: InvalidFileReader.setMaxFileSize([Integer maxFileSize])""".stripMargin()
    }
}

@CompileStatic
@Singleton
class FileReader {
    
    private Integer maxFileSize
    private Boolean showProgress
    
    // Configuration property names 
    // are normalized and 
    // stored lowercase hyphen separated (= kebab case).
    FileReader(
            @Property(name ='reader.max-file-size') Integer maxFileSize,
            @Value('${reader.show-progress:false}') Boolean showProgress) {
        
        this.maxFileSize = maxFileSize
        this.showProgress = showProgress
    }
    
    Integer getMaxFileSize() {
        return maxFileSize
    }
    
    Boolean showProgress() {
        return showProgress
    }
}

@CompileStatic
@Singleton
class InvalidFileReader {
    // Invalid reference to property name,
    // because the names are normalized and
    // stored lowercase hyphen separated.
    @Value('${reader.maxFileSize}')
    Integer maxFileSize
}

Written with Micronaut 1.0.0.RC1.