Aan het einde van het eerste kwartaal van 2015 is Grails 3 uitgekomen. De code voor deze versie is totaal herschreven ten opzichte van de vorige versies. In dit artikel zullen we kijken naar wat Grails 3 te bieden heeft en wat de veranderingen zijn. Zo is bijvoorbeeld het build systeem veranderd naar Gradle en wordt Spring Boot gebruikt. We bekijken ook nieuwe features die nog niet in vorige versie van Grails zaten.
Gradle voor builds
Grails is altijd een platform geweest om web applicaties mee te maken. Als je Grails hebt gedownload, dan heb je alles bij de hand om meteen te beginnen. Er is een build systeem en de belangrijkste dependencies zijn al geconfigureerd. In de nieuwe Grails 3 versie is het build systeem vervangen door Gradle. Dit is al een grote verandering. In de oudere Grails versies werd gebruik gemaakt van Gant als build systeem. Gant was gebaseerd op Ant met een Groovy laagje eromheen. Door nu gebruik te maken van Gradle is het build systeem weer helemaal bij de tijd. We kunnen nu gebruik maken van alle mogelijkheden die Gradle al biedt. Grails biedt een eigen Gradle plugin die wordt gebruikt om specifieke Grails taken uit te voeren. Grails commando’s die we opgeven, worden nu gedelegeerd naar Gradle taken. Als we bijvoorbeeld het Grails commando compile gebruiken, wordt de Gradle taak classes aangeroepen. Dit betekent ook dat we de Gradle tasks direct kunnen aanroepen zonder de Grails commando’s.
Het mooie is nu ook dat een Grails project gemakkelijk mee kan draaien in een multi-module project dat al gebruik maakt van Gradle. Stel je voor dat je een project hebt waarbij je een aantal Java modules hebt en die wilt gebruiken in de Grails applicatie. Dan is er nu niks anders nodig dan dat het hele project, dus ook de Java modules, met Gradle worden gebouwd en het werkt.
Spring Boot
Grails was altijd al gebaseerd op bestaande tools, frameworks en technologieën. Zo is het Spring framework een belangrijk onderdeel van Grails. Een hoop onderdelen van Spring werden gebruikt, maar als ontwikkelaar zag je dat niet altijd, omdat Grails een hoop dingen al geconfigureerd had voor ons. Intussen was vanuit Spring zelf Spring Boot ontstaan. Met Spring Boot biedt het Spring framework een manier om snel aan de slag te kunnen met Spring en worden heel veel dingen op een makkelijke manier al geconfigureerd. Het is daarom niet vreemd dat Grails 3 nu gebaseerd is op Spring Boot. Grails kan meeliften op Spring Boot en hoeft zelf minder van de ‘magie’ meer te leveren, die in de vorige versie van Grails wel nodig was. Door middel van Spring Boot kan nu standaard makkelijker worden omgegaan met runnable JARs, embedded servers, monitoring en health checks.
In het volgende code voorbeeld zien we hoe een default Application class eruit ziet in Grails 3:
package grails.sample
import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
class Application extends GrailsAutoConfiguration {
static void main(String[] args) {
GrailsApp.run(Application)
}
}
Het mooie is nu ook dat de WAR file de we maken nu als standalone applicatie gestart kan worden. Er is een embedded Tomcat instantie beschikbaar, maar de WAR file kan altijd nog worden gedeployed naar een standalone applicatie server. Het volgende commando kunnen we gebruiken om onze applicatie starten als standalone applicatie:
java -jar build/libs/app-1.0.war
Groovy
De code die we schrijven voor een web applicatie in Grails is altijd al geschreven in Groovy. Groovy is een taal die gecompileerd wordt naar Java Virtual Machine code. Groovy lijkt erg op Java en is ook gemakkelijk te leren als je Java al kent. Grails 3 is gebaseerd op de laatste versie van Groovy 2.4. De codebase van Grails zelf is altijd een mix geweest van Java en Groovy code. Groovy 2.3 introduceert traits als taalconcept. Je kan een trait zien als een interface met een implementatie en state. Een nieuwe class kan meerdere traits toepassen, zonder class inheritance aan te tasten. Met een trait kunnen we code schrijven die op meerdere manieren her te gebruiken is en hiervan maakt de codebase van Grails 3 ook veel gebruik. Heel veel zaken die in oudere versies van Grails waren geïmplementeerd met de dynamische taal features van Groovy zijn nu gemaakt met traits. Dit betekent een betere compile time type checking en betere performance. De gecompileerde class files bevatten nu alle functionaliteit en die hoeft niet meer dynamisch in runtime te worden gedaan. Bijvoorbeeld a controller class in Grails heeft bijvoorbeeld de volgende traits: TagLibraryInvoker, AsyncController, RestResponder en Controller en hierdoor zijn de methoden render(), redirect() en getParams() beschikbaar. Deze traits kunnen we trouwens ook zelf gebruiken in onze code.
Als gebruikers van Grails schrijven we ook de code in de laatste versie van Groovy, dus kunnen we de nieuwste Groovy features gebruiken. Bijvoorbeeld static compilation en type checking is nu ook mogelijk. Dit is vooral handig, omdat je nu bij het compileren al veel fouten kan voorkomen die je vroeger alleen maar tegen kwam als je applicatie al draaide.
We hebben nu een aantal zaken gezien die anders zijn ten opzichte van de vorige versie van Grails. Maar Grails 3 biedt ook een aantal nieuwe zaken die we nog niet kenden van de vorige versies van Grails.
Interceptors
In Grails 3 kunnen we nu standalone interceptors schrijven die we kunnen gebruiken om standaard functionaliteit aan te roepen voor elke request. Denk bijvoorbeeld aan logging of authenticatie. We kunnen een interceptor maken met het Grails commando create-interceptor:
grails create-interceptor grails.sample.Sample
De code van de interceptor is dan:
package grails.sample
class SampleInterceptor {
boolean before() { true }
boolean after() { true }
void afterView() {
// no-op
}
}
Met de standaard configuratie zal deze interceptor gelden voor alle requests die de SampleController gebruiken, maar we kunnen dit wijzigen door een constructor toe voegen met daarin de matching regels voor de interceptor.
In oudere Grails versies was er een filter concept die een soortgelijke functionaliteit bood, maar interceptors zijn veel beter herbruikbaar.
Profiles
Als we in Grails het command create-app gebruiken, wordt een nieuwe directory structuur aangemaakt met de benodigde code om een web applicatie te maken. In Grails 3 zijn er nu zogenaamde application profiles. Dit zijn eigenlijk templates voor een Grails applicatie. Het standaard profile is voor het maken van een web applicatie, maar er zijn tot nu toe ook nog andere profiles:
- web, standaard profile voor een standaard web applicatie;
- plugin, voor standaard plugins;
- web-plugin, voor web applicatie plugins;
- web-micro, voor een minimale micro service.
Deze profiles zijn gedefinieerd in een Git repository en in de toekomst kunnen er ook nieuwe profiles worden toegevoegd. Het is ook mogelijk om zelf een profile te maken.
Het web-micro profile maakt het nu eindelijk mogelijk om kleinere applicaties te schrijven in Grails dan voorheen mogelijk was. Het commando grails create-app small –profile=web-micro levert maar 2 bestandjes op, een application.yaml en Application.groovy in tegenstelling tot een hele directory structuur in het standaard web profile.
YAML is met Grails 3 de standaard manier om de configuratie te beschrijven van de applicatie, zoals de data source die gebruikt moet worden en andere settings. Als het web-micro profile gebruikt is, dan zou je je code in Application.groovy kunnen schrijven om bijv. een micro service applicatie te maken.
@Grab("hibernate")
@Grab("h2")
import grails.persistence.Entity
@Entity
@Resource(uri="/examples")
class Example {
String name
}
Na het opstarten met de embedded Tomcat container zou je met een REST client met deze Grails applicatie op localhost:8080 kunnen verbinden en op pad /examples enige bestaande Example entiteiten kunnen ophalen of hier nieuwe naar toe kunnen posten.
Testen
Grails had altijd al goede support voor het testen van de applicatie code. Standaard wordt Spock ondersteund voor het schrijven van unit en integratie testen. Spock is een test framework dat automatisch al goede support heeft voor mocks en stubs en een hele duidelijke syntax voor het schrijven van tests. In Grails 3 is er ook standaard ondersteuning voor Spock/Geb testen. Geb is een framework voor functionele testen van een web applicatie. Grails maakt gebruik van Spring Boot om de applicatie eenmaal te starten, zodat functionele testen uitgevoerd kunnen worden.
Omdat een Grails applicatie nu een Spring Boot applicatie is, is het ook veel gemakkelijker geworden om testen uit te voeren vanuit een IDE. Er is niets speciaals nodig, want voor de IDE is het gewoon een Java of Groovy applicatie die gestart moet worden. En omdat Grails nu Gradle gebruikt, kunnen we ook gebruik maken van de Gradle’s test features, zoals het parallel uitvoeren van testen waardoor de build tijd weer korter wordt.
Events
In Grails 3 is een nieuwe Events API toegevoegd, gebaseerd op Reactor. Reactor is een framework voor reactive applicaties voor de JVM. Hierdoor hebben we meteen een snel en betrouwbaar mechanisme om events te gebruiken in een Grails applicatie. Alle controllers en services in een Grails applicatie implementeren een Events trait, waardoor het mogelijk is om events te versturen en te ontvangen. Deze trait kunnen we ook gebruiken in onze eigen code die geen controller of service is.
In de volgende code kan je een voorbeeld zien hoe we een event kunnen consumeren en versturen:
// on() methode uit Events trait
// om event te consumeren.
on('sampleEvent') {
// Code voor event handling.
}
// notify() en sendAndReceive()
// methoden uit Events trait om
// events te versturen
notify 'sampleEvent', [user: new User(name: 'Grails user')]
sendAndReceive 'sampleEvent', [message: 'Hello'], {
println it.message
}
Scaffolding
In de vorige versies van Grails was het zogenaamde dynamisch scaffolding een belangrijke en herkenbare feature. Hiermee is het voldoende om een domein class aan te maken en we krijgen meteen een web interface die gebruik maakt van de domein class om gegevens te tonen en op te slaan in een database. Op deze manier konden er razendsnel CRUD (Create-Read-Update-Delete) schermen gegenereerd worden voor je domain classes.
Stel dat we een domein class Person op de volgende manier hadden gedefinieerd (via create-domain-class sample.Person en vervolgens handmatig 2 properties en constraints toegevoegd):
class Person {
String name
Date birthDate
static constraints = {
name blank: false
birthDate nullable: true
}
}
In Grails 2 zou je create-scaffold-controller kunnen doen die een vrij lege PersonController genereerde met als enige statement static scaffold = true, waarbij een aantal acties en bijbehorende HTML views, zoals list, show, update etc., run-time uit de toenmalige scaffolding plugin kwam. Als we een wijziging maken in een domein class, dan werd meteen de interface aangepast.
In Grails 3 is de dynamisch scaffolding niet meer aanwezig, maar is het nu explicieter geworden. De web interface code moeten we nu maken met het Grails commando generate-all.
De opdracht generate-all sample.Person genereert in de grails-app/views/person directory een create.gsp, edit.gsp, index.gsp en show.gsp. De HTML code voor verschillende properties van de Person domein class werden in Grails 2 volledig uitgegenereerd in de GSPs, zoals HTML input elementen in het create- en update scherm. In Grails 3 wordt gedelegeerd naar de Fields plugin voor renderen van de juiste HTML. De gegenereerde code voor het invoerformulier is minimaal:
...
<g:form action="save">
<fieldset class="form">
<f:all bean="person"/>
</fieldset>
...
</g:form>
De f:all tag rendert nu de juiste HTML input elementen voor elke property (behalve een aantal uitzonderingen zoals id, version, dateCreated enz) van de domein class. Dit is het equivalent van:
<f:with bean="person">
<f:field property="name"/>
<f:field property="birthDate"/>
</f:with>
De showpagina gebruikt een andere tag genaamd f:display om de waarden correct te tonen. Dit gebeurt via een aantal conventies, zoals dat een HTML checkbox gerenderd wordt voor een booleaanse property. Wil je bijvoorbeeld wat afwijkends tonen, dan kun je het renderen een beetje aanpassen op basis van flink wat eigenschappen van de context, zoals controller naam, class naam, property naam, property type, etc.
Het enige wat je hoeft te doen, is in je applicatie of in een custom plugin (want die worden ook doorzocht) de juiste GSP snippet te definiëren onder grails-app/views, zodat deze gebruikt wordt in een specifiek geval in plaats van de conventie. Als we wat speciaals zouden willen doen met het presenteren van de name van een Person, dan kunnen we dit regelen in grails-app/views/_fields/person/name/_displayWrapper.gsp. Hierdoor is de code wel zo flexibel geworden dat een wijziging in de domein class of presentatie van een individueel veld niet meteen betekent dat de web interface code gewijzigd moet worden.
Plugins
Eén van de belangrijke eigenschappen van Grails is altijd de plugin support geweest. Goede voorbeelden zijn de eerdergenoemde scaffolding en fields plugins, die standaard worden meegeleverd. Als er extra functionaliteit voor je applicatie nodig is, dan was er vaak al een plugin voor geschreven. We hoeven de plugin dan alleen toe te voegen als dependency en we krijgen de functionaliteit van de plugin in onze applicatie. Bijvoorbeeld het toevoegen van AngularJS is niet meer dan het toevoegen van een plugin dependency.
Grails 3 plugins zijn nu beschikbaar via Bintray in plaats van via de Grails portal. De structuur van een plugin is wel veranderd ten opzichte van de vorige Grails versies. Het converteren van een oude plugin is vaak niet meer dan het opnieuw organiseren van de source code in de nieuwe directory structuur. Maar dit betekent wel dat plugin auteurs dit moeten doen. De plugins die door het Grails team worden geschreven en onderhouden zijn allemaal geschikt gemaakt voor Grails 3, maar andere plugins zijn soms wel en vaak ook niet geconverteerd.
Conclusie
Grails 3 is de grootste verandering van Grails sinds versie 1. Het platform is een stuk volwassener geworden en maakt nu gebruik van de laatste technologieën en frameworks. Door het gebruik van Gradle is ook het makkelijker om Grails te gebruiken in multi-module projecten. In combinatie met de Spring Boot basis is het makkelijker om de applicatie te distribueren en code te developen en uit te voeren in een IDE zonder Grails-specifieke tooling.
De verandering in de plugin structuur zorgt er wel voor dat bestaande plugins opnieuw configureerd moeten worden en dat is afhankelijk van de plugin auteurs.
Over het geheel heeft Grails 3 een betere modularisatie gekregen, minder dependencies, minder code en een betere performance. De integratie met Spring en de nieuwe application profiles bieden mooie kansen en alle mogelijkheden om met Grails je toekomstige web applicaties te maken.