Show Navigation

@ConfigurationProperties in Grails App

Grails 3 apps are Spring Boot apps. Learn how property values can be bound to structured objects through @ConfigurationProperties.

Authors: Sergio del Amo

Grails Version: 3.3.8

1 Training

Grails Training - Developed and delivered by the folks who created and actively maintain the Grails framework!.

2 Getting Started

In this guide, we are going to demonstrate Grails file transfer capabilities by creating an app which downloads an excel file with a list of books.

2.1 What you will need

To complete this guide, you will need the following:

  • Some time on your hands

  • A decent text editor or IDE

  • JDK 1.7 or greater installed with JAVA_HOME configured appropriately

2.2 Solution

We recommend you to follow the instructions in the next sections and create the app step by step. However, you can go right to the completed example.

or

Then, cd into the complete folder which you will find in the root project of the downloaded/cloned project.

3 Writing the App

grails create-app example.grails.complete --features=events,geb2,hibernate5

we are using geb2 feature which includes Geb 2 and Gradle WebDriver Binaries plugin. Geb 2 requires JDK 1.8 or greater.

3.1 Configuration Properties

In this section we are going to explore how property values can be bound to structured objects through @ConfigurationProperties.

First, we need to annotate Application.groovy with @ComponentScan.

grails-app/init/example/grails/Application.groovy
package example.grails

import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import groovy.transform.CompileStatic
import org.springframework.context.annotation.ComponentScan

@CompileStatic
@ComponentScan (1)
class Application extends GrailsAutoConfiguration {
    static void main(String[] args) {
        GrailsApp.run(Application, args)
    }
}
1 @ComponentScan tells Spring to look for other components, configurations, and services in the specified package. Spring is able to auto scan, detect and register your beans or components from pre-defined project package. If no package is specified current class package is taken as the root package.

Create a file named AddressConfiguration.groovy.

src/main/groovy/example/grails/AddressConfiguration.groovy
package example.grails

import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Configuration
import org.springframework.stereotype.Component

@Configuration (1)
@ConfigurationProperties(prefix = "address") (2)
class AddressConfiguration {
    String street
    String city
    String country
}
1 We have added the @Configuration annotation for Spring to be able to find this bean and make it a candidate for injection.
2 The @ConfigurationProperties annotation takes the configuration prefix.

Any properties defined in the property file that has the prefix address and the same name as one of the properties are automatically assigned to this object.

Add some properties to application.yml

grails-app/conf/application.yml
address:
    street: 221B Baker Street
    city: London
    country: United Kingdom

3.2 Tag Lib

Create a Tag Library to render the address:

grails-app/taglib/example/grails/AddressTagLib.groovy
package example.grails

class AddressTagLib {

    static namespace = "app" (1)

    AddressConfiguration addressConfiguration (2)

    def address = { attrs, body ->
        out << """\
<div class='adr'>
    <div class='street-address'>${addressConfiguration.street}</div>
    <span class='locality'>${addressConfiguration.city}</span>,
    <div class='country-name'>${addressConfiguration.country}</div>
</div>""" (3)
    }
}
1 By default, tags are added to the default Grails namespace and are used with the g: prefix in GSP pages. However, you can specify a different namespace by adding a static property to your TagLib class.
2 You can inject AddressConfiguration as any other bean into your TagLib.
3 Create a valid adr microformat HTML snippet.

3.3 Unit Tests

Create a unit test for the TagLib:

src/test/groovy/example/grails/AddressTagLibSpec.groovy
package example.grails

import grails.testing.web.taglib.TagLibUnitTest
import spock.lang.Specification

class AddressTagLibSpec extends Specification implements TagLibUnitTest<AddressTagLib> { (1)

    Closure doWithSpring() {{ -> (2)
        addressConfiguration(AddressConfiguration)
    }}

    void "test address tag"() {
        when:
        String returnString = tagLib.address().toString() (3)

        then:
         returnString == "<div class='adr'>\n    <div class='street-address'>221B Baker Street</div>\n    <span class='locality'>London</span>,\n    <div class='country-name'>United Kingdom</div>\n</div>"
    }
}
1 Tag libraries and GSP pages can be tested with the grails.testing.web.taglib.TagLibUnitTest trait.
2 To provide or replace beans in the context, you can override the doWithSpring method in your test.
3 Adding the TagLibUnitTest trait to a test causes a new tagLib field to be automatically created for the TagLib class under test. The tagLib property can be used to test calling tags as function calls.

3.4 Acceptance Tests

Edit grails-app/views/index.gsp, the GSP that is currently rendered when you visit the home page / and add the next snippet:

grails-app/views/index.gsp
...
 <div id="content" role="main">
 ....
 ...
         <app:address/>
 </div>
 ...

Now we can create an acceptance test with Geb to verify the address is rendered in the home page:

src/integration-test/groovy/example/grails/AddressSpec.groovy
package example.grails

import geb.spock.GebSpec
import grails.testing.mixin.integration.Integration
import spock.lang.IgnoreIf

@Integration
class AddressSpec extends GebSpec {

    @IgnoreIf({ !sys['geb.env'] })
    def "verify address is displayed in homepage"() {
        when:
        browser.go("/")

        then:
        browser.driver.pageSource.contains('221B Baker Street')
    }
}

4 Test the app

To run the tests:

./grailsw
grails> test-app
grails> open test-report

or

./gradlew check
open build/reports/tests/index.html

5 Help with Grails

OCI sponsored the creation of this Guide. OCI offers several Grails services:

Free consultation

The OCI Grails Team includes Grails co-founders, Jeff Scott Brown and Graeme Rocher. Check our Grails courses and learn from the engineers who developed, matured and maintain Grails.

Grails OCI Team