Grails - Destaques...para quem já sabe Java
Douglas de Oliveira Mendes
Grails - DestaquesBaseado no livro "Programming Grails" de Burt
Beckwith
Groovy + Spring + Hibernate + "Convention over configuration" + ...
Esta apresentação é mais focada na diferença do código-fonte, mas saiba que Grails juntou muito bem frameworks bastante utilizados pela comunidade Java (especialmente Spring e Hibernate).
Graças ao dialeto Groovy e à prática de "convenção sobre configuração" o resultado é um código-fonte bem mais conciso.
Vamos ao que interessa...
"Reflection" fácil de usar
String methodName = …def value = person."$methodName"(1, 2)
String propertyName = …def otherValue = person."$propertyName"
Mapas são LinkedHashMap
...ao invés de java.util.HashMap para assim manter a ordem dos elementos.
def map = [red:1, blue:2]
Se precisar de outro tipo de mapa é só instanciar como é feito no Java.
Getters e setters
Basta acessar a propriedade diretamente. Ex.:
cliente.nome
O getter vai ser invocado quando estiver lendo o valor e o setter quando estiver atribuindo um novo valor.
Getters e setters
Não é necessário (mas é permitido e serão chamados se existirem) implementar métodos getters e setters. Ex.:
void setNome(String nome) {this.nome = nome.trim();
}
Debaixo do capô
AST BrowserJD-GUI
Para entender o código gerado.
Closure
Pedaço de código que pode ser atribuído a uma variável. Pode ser passado como parâmetro e invocado dentro de métodos.Lembra uma classe anônima porém sem precisar implementar uma Interface. Nota: eles podem acessar variáveis não "final" fora de seu escopo.
Closure
Ex.:
def hello = { println "hello" }hello()
Closure
É um jeito prático de implementar interfaces sem precisar definir todos os métodos (útil em testes por exemplo):
def conn = [close: { -> println "closed},setAutoCommit: { boolean autoCommit -> println "autoCommit:
$autoCommit" }] as java.sql.Connection
Closure
Trabalhando com parâmetros:
def add { int x, int y -> x + y }
getMaximumNumberofParameters()getParameterTypes()
Loops
int count = someCalculation()for (int i = 0; i < count; i++) {
…}
Loops
someCalculation().times {…
}
Loops
for (i in 0..someCalculation() - 1) {…
}
Comparando objetos
O sinal "==" funciona diferente do Java pois ele compara os valores.
Para saber se ambas as referências apontam para o mesmo objeto, utilizar:
foo.is(bar)
Invocação de método de acordo com tipo to parâmetro
void close(Connection c) {…
}
void close(Object o) {...
}
Invocação de método de acordo com tipo to parâmetro
No Java este código invocaria close(Object):Object connection = createConnection();close(connection);
No groovy seria chamado o close(Connection) porque seria resolvido em Runtime.
Groovy Strings
Multilinhas (com três aspas):def name = "Carl Sagan"def texto = """\Caro $name,
Não esqueça de alimentar os gatinhos."""
'this' funciona para acesso estático
ex.:
private static final Logger LOG = Logger.getLogger(this)
Metaprogramming
Adicionando um método:
List.metaClass.removeRight = {int index -> delegate.remove(delegate.size() - 1 - index)
}
Metaprogramming
É possível sobrescrever métodos como:- invokeMethod- getProperty- setProperty- methodMissing- propertyMissing
Metaprogramming
Ex. de sobrescrita do invokeMethod:
def methodMissing(String methodName, args) {println "papagaio - $methodName"
}
Operadores: ?.
Acesso null-safe (se "person" for null o valor atribuído será null ao invés de dar NullPointerException):
String name = person?.name
Operadores: ?:?: é operador "Elvis" que encurta ternários. Você já fez algo assim em Java?
Integer qtd = qtdParam ? qtdParam : 10
Com grails você pode fazer assim:
Integer qtd = qtdParam ?: 10
Operadores: *.
*. é o "spread". Se você quer todos os nomes de clientes de um array você pode fazer assim:
String[] nomes = clientes*.nome
Operadores: .@Como já vimos, ao acessar "cliente.nome" o método getNome (ou setNome se for atribuição) é chamado automaticamente.
Se desejar evitar por exemplo o getNome e acessar diretamente a propriedade, utilize o operador .@. Ex.:
cliente.@nome
Operadores: asFacilita escolha do tipo de estrutura de dados. Por ex. criar um Set ao invés de um List:
def things = ['a', 'b', 'b', 'c'] as Setassert things.getClass().simpleName == 'HashSet'assert things.size() == 3
Operadores: in
Similar a chamar o método "contains":
assert 1 in [1, 2, 5]
Operadores: .&
Permite tratar um método como um closure (podendo assim passar a referência do método como parâmetro). Ex.:
def add = new MathUtils().&addadd(x, y)
Operadores: sobrecarga
Basta implementar os respectivos métodos:a + b -> a.plus(b)a++ -> a.next()a << b -> a.leftShift(b)...
Groovy "demais"...def foo = bar(5, true) // o que é "foo"??
def fazAlgo() {...} // O que fazAlgo retorna? É void? Por que não declará-lo como void?
def fazAlgo = {} // Definir métodos como closure ao invés da declaração normal pode fazê-lo ficar de fora de interceptações como por exemplo quando o Spring está marcando os métodos como transacionais.
Linguagem dinâmica permite mais bugs...int hc = someObject.hashcode()
Se o método na verdade se chama hashCode só saberemos na hora que o código for executado, não quando for compilado. Testes deveriam nos prevenir destes casos.
As anotações @TypeChecked e @CompileStatic ajudam nestes casos e melhoram desempenho do código porém há perda de flexibilidade (por ex. metaprogramming).