Groovy et Grails

Julien Marcil

julien@marcil.com - @Nr9

Java est un language très populaire.

TIOBE Programming Community Index for September 2013

Source: TIOBE Programming Community Index for September 2013

Java est un language très populaire.

TIOBE Programming Community Index for September 2013

Source: TIOBE Programming Community Index for September 2013

Source: http://langpop.corger.nl/

Groovy

Groovy

  • is an agile and dynamic language for the Java Virtual Machine.
  • builds upon the strengths of Java but has additional power features inspired by languages like Python, Ruby and Smalltalk.
  • makes modern programming features available to Java developers with almost-zero learning curve.
  • supports Domain-Specific Languages and other compact syntax so your code becomes easy to read and maintain.

Un programme Java typique


public class HelloWorld {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public String greet() {
        return "Hello " + name;
    }
    
    public static void main(String[] args) {
        HelloWorld helloWorld = new HelloWorld();
        helloWorld.setName("Groovy");
        System.out.println( helloWorld.greet() );
    }
}
					

Un programme Groovy valide


public class HelloWorld {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public String greet() {
        return "Hello " + name;
    }
    
    public static void main(String[] args) {
        HelloWorld helloWorld = new HelloWorld();
        helloWorld.setName("Groovy");
        System.out.println( helloWorld.greet() );
    }
}
					

Version plus Groovy!


class HelloWorld {
    def name
    def greet() { "Hello ${name}" }
}    

helloWorld = new HelloWorld(name: "Groovy")
println helloWorld.greet()
						

Ruby


class HelloWorld < Struct.new(:name)
    def greet 
    	"Hello #{name}"
    end
end

hello_world = HelloWorld.new("Ruby")
puts hello_world.greet
						

Interopérabilité complète

Interopérabilité

Syntaxe Groovy

La syntaxe Groovy est riche et flexible. Voici quelque examples.

GString

		
foxtype = 'quick'
foxcolor = ['b', 'r', 'o', 'w', 'n']
assert 'The quick brown fox' == "The $foxtype ${foxcolor.join()} fox"
						

Operator Overloading


a == b
										

a.equals(b) or a.compareTo(b) == 0
										

a != b
										

!a.equals(b)
										

a <=> b
										

a.compareTo(b)
										

a > b
										

a.compareTo(b) > 0
										

a >= b
										

a.compareTo(b) >= 0
										

a < b
										

a.compareTo(b) < 0
										

a <= b
										

a.compareTo(b) <= 0
										

List

Java

List<Number> numbers = new ArrayListt<>;
numbers.add(1);
numbers.add(2);
numbers.add(3);
										
Groovy

numbers = [1, 2, 3]
										

Map

Java

Map<String, String> family = new HashMap<>;
family.put("dad", "John");
family.put("mom", "Jane");
family.put("son", "John");
										
Groovy

family = [dad:"John" , mom:"Jane", son:"John"]
										

Iteration

Java

for (Number number : numbers)
{
    System.out.println(number);
}
										
Groovy

numbers.each { println it }
										

Type dynamique

		
def v = 3
v = 'avion'
v = false
v = new StringBuffer()
v = null
					

Closure

		
def f = { list, value -> list << value }
x = []
f(x, 1)
f(x, 2)
f(x, 3)
assert x == [1, 2, 3]
					

Meta programmation

		
def s = "Hello Groovy"
String.metaClass.shout = { delegate.toUpperCase() }
assert s.shout() == "HELLO GROOVY"
						

Meta programmation

		
class SingletonCalculator {
    private total = 0
    def add(a) { total += a }
}
						
		
class CalculatorMetaClass extends MetaClassImpl {
    private final static INSTANCE = new SingletonCalculator()
    CalculatorMetaClass() { super(SingletonCalculator) }
    def invokeConstructor(Object[] arguments) { return INSTANCE }
}

def registry = GroovySystem.metaClassRegistry
registry.setMetaClass(SingletonCalculator, new CalculatorMetaClass())
						
		
def calc = new SingletonCalculator()
						
Grails

Grails

  • Groovy Web Application Framework.
  • inpired by Dynamic Frameworks like Rails, Django and TurboGears.
  • based on the Don't Repeat Yourself (DRY) principle.
  • Convention over Configuration.

Basé sur les meilleurs frameworks Java

  • Spring Framework
    • Spring MVC
    • Spring Transaction
    • Spring MessageSource (i18n)
  • Hibenate
  • SiteMesh
  • embedded Tomcat

Structure

Projet Grails
  • grails-app
    • conf
    • controllers
    • domain
    • i18n
    • services
    • taglib
    • views
  • web-app
  • scripts
  • src
    • groovy
    • java
  • test
    • integration
    • unit

Domain Classes

		
class Author {
    static hasMany = [books: Book]
    String name
}
					
		
class Book {
    static belongsTo = [author: Author]
    String title
}
					

Domain Classes

		
class Book {
    static belongsTo = [author: Author]

    String title
    Date releaseDate
    String ISBN
    BigDecimal price

    static constraints = {
        title(blank: false, maxSize:100)
        isbn(blank: false, matches:"[0-9]13" minSize:13 maxSize:13, unique: true)
        price(nullable: true, min: 0.0, max: 9999.99, scale: 2)
    }

    static mapping = {
        table "books"
        price column: "sales_price"
    }

    def beforeInsert() { dateCreated = new Date() }
}
					

CRUD

	
// Create	
def a = new Author(name: "King")
a.save()
					
		
// Read	
def a = Author.get(1);
					
		
// Update	
def a = Author.get(1);
a.name = "Stephen King"
a.save()
					
		
// Delete	
def a = Author.get(1);
a.delete()
					

Dynamic Finder

		
Book.findByTitle("The Stand")

Book.findByTitleLike("Harry Pot%")

Book.findByReleaseDateBetween(firstDate, secondDate)

Book.findByReleaseDateGreaterThan(someDate)

Book.findByTitleLikeOrReleaseDateLessThan("%Something%", someDate)
					

Where Queries

		
def query = Person.where {
   firstName == "Julien"
}
Person julien = query.find()
					
		
def children = Book.findAll { age in 0..17 }
					

Critera

		
def criteria = Account.withCriteria {
    between("balance", 500, 1000)
    eq("branch", "London")
    or {
        like("holderFirstName", "Fred%")
        like("holderFirstName", "Barney%")
    }
    maxResults(10)
    order("holderLastName", "desc")
}
					

Services

		
class BookService {

    static transactional = true
    static scope = "singleton" //prototype, request, flash, 
                               //conversation, session, singleton

    def authorService // the AuthorService will be injected

    def updateSomething() {
         // Business Logic
    }

    @Transactional(readOnly = true)
    def listBooks() {
        Book.list()
    }
}
					

Controllers

		
class BookController {
    def list() {
        def map = [books: Book.list(params), total: Book.count()]
        render(view: "books", model: map)
    }

    def show() {
        [book: Book.get(params.id)]
    }
}
					

Controllers

		
class BookController {
    def json()
    {
        render Book.list(params) as JSON
    }

    def xml()
    {
        render Book.list(params) as XML
    }
}
					

GSP

		
<!DOCTYPE html>
<html>
    <head>
        <title>${book?.title}</title>
        <r:require module="jquery"/>
        <r:layoutResources/>
    </head>
    <body>
        
Title: ${book?.title}
Author: ${book?.author?.name}
<r:layoutResources/> </body> </html>

URL Mapping

		
class UrlMappings {

    static mappings = {
        "/$controller/$action?/$id?"{
            constraints {
                // apply constraints here
            }
        }

        "/"(view:"/index")
        "500"(view:'/error')
        "404"(view:'/404')
    }
}
					

Plugins

Spring Security LDAP Mongo
Quartz Resources Neo4J
jQuery Mail Rabbit MQ
Joda Zipped Resources Redis
Searchable Console ...

Démo!

Question?

Merci!