Groovy
Mehr Dynamik bei der Java-
      Entwicklung
Wer ich bin...
Wer ich bin...
    Mein eigener Chef

    (Extremer) Softwareentwickler

    (Agiler) Coach

    Testgetrieben

    http:/...
Java-Frust
Java-Frust
public class Person...
    public String getName() {
          return name;
    }
Java-Frust
public class Person...
    public String getName() {
          return name;
    }


public static List<Person> ...
Java-Frust
public class Person...
    public String getName() {
          return name;
    }


public static List<Person> ...
Java-Frust
public class Person implements Namable...
    public String getName() {
          return name;
    }


public s...
Java-Frust
  public class Person implements Namable...
      public String getName() {
            return name;
      }

p...
Java-Frust
  public class Person...
      public String getName() {
            return name;
      }

public class MyHelpe...
Java-Frust
  public class Person...
      public String getName() {
            return name;
      }

public class MyHelpe...
Typische Java Smells
public class MyHelper...
    public static <T extends Namable> List<T> sortByName(Set<T> namables) {
...
Typische Java Smells
public class MyHelper...
    public static <T extends Namable> List<T> sortByName(Set<T> namables) {
...
Typische Java Smells
public class MyHelper...
    public static <T extends Namable> List<T> sortByName(Set<T> namables) {
...
Typische Java Smells
public class MyHelper...
    public static <T extends Namable> List<T> sortByName(Set<T> namables) {
...
Typische Java Smells
public class MyHelper...
    public static <T extends Namable> List<T> sortByName(Set<T> namables) {
...
Die Rettung naht:
Dynamische Skriptsprachen



• Scripting
• Dynamik
Scripting
• Knappe und ausdrucksstarke Syntax
• Ausführung von Programmcode ohne
 (spürbare) Compilierung
 • Selbstständig...
Scripting
 • Knappe und ausdrucksstarke Syntax
 • Ausführung von Programmcode ohne
   (spürbare) Compilierung
   • Selbsts...
Scripting
 • Knappe und ausdrucksstarke Syntax
 • Ausführung von Programmcode ohne
   (spürbare) Compilierung
   • Selbsts...
Dynamik


• Dynamische Typisierung
• Closures
• Meta-Programmierung
Dynamische Typisierung
       aka „Duck Typing“
def sortByName(unsorted) {
    unsorted.sort {it.name}
}

def people = [
 ...
Closures (1)

 Programmlogik als vollwertiges Objekt

def sorter = { unsorted ->
    unsorted.sort {it.name}
}
def sorted ...
Closures (2)

• Iteration als typischer Anwendungsfall
Closures (2)

 • Iteration als typischer Anwendungsfall
def namen = [quot;Johannesquot;, quot;Frankquot;, quot;Dierkquot;]...
Closures (2)

    • Iteration als typischer Anwendungsfall
def namen = [quot;Johannesquot;, quot;Frankquot;, quot;Dierkquo...
Meta-Programmierung


• Erweiterung existierender Klassen
• Hinzufügen von Methoden zur Laufzeit
• Erweiterung / Veränderu...
Meta Object Protocol
„A metaobject protocol (MOP) is an interpreter
of the semantics of a program that is open and
       ...
Meta Object Protocol
    „A metaobject protocol (MOP) is an interpreter
    of the semantics of a program that is open and...
Vorteile / Nachteile
dynamischer Skriptsprachen
• Vorteile:
  • Weniger Code
  • Weniger Duplikation
  • Verständlichere A...
Vorteile / Nachteile
dynamischer Skriptsprachen
• Vorteile:
  • Weniger Code
  • Weniger Duplikation
  • Verständlichere A...
Welche Skriptsprachen
       gibt es?

• Verbreiteste Skriptsprachen:
  Perl, PHP, Python, Ruby, JavaScript

• Mehr als 20...
Groovy in der
Sprachlandschaft


      Text




             (c) Dierk König
Groovy
Groovy
• Volle Objekt-
  Orientierung ohne
  primitive Typen
Groovy
• Volle Objekt-
  Orientierung ohne
  primitive Typen
• Optionale statische
  Typisierung
Groovy
• Volle Objekt-
  Orientierung ohne
  primitive Typen
• Optionale statische
  Typisierung
• Closures
Groovy
• Volle Objekt-
  Orientierung ohne
  primitive Typen
• Optionale statische
  Typisierung
• Closures
• Listen und M...
Groovy
• Volle Objekt-         • Volle Integration
  Orientierung ohne       mit der Java-
  primitive Typen         Platt...
Groovy
• Volle Objekt-         • Volle Integration
  Orientierung ohne       mit der Java-
  primitive Typen         Platt...
Groovy - Vereinfachte
        Syntax
System.out.println(quot;Hello World!quot;); //Java style
println 'Hello, World!'


de...
Reguläre Ausdrücke
assert (quot;Hello World!quot; =~ /Hello/) // Find-Operator

assert (quot;Hello World!quot; ==~ /Hellob...
Listen, ...
def leer = []
def voll = [1, 2, 'JUGC']

assert voll + voll == voll * 2

assert voll[0]     == 1
assert voll[0...
... Maps und Ranges
def leer = [:]
def voll = [a: 1, b: 2]

assert voll['a'] == 1
assert voll.a    == 1

voll.a = 2
assert...
Groovy Beans & GPath
class Person {

    def name

    def kinder = []
}
def johannes = new Person(name: quot;Johannesquot...
Groovy Beans & GPath
 class Person {
 
    def name
 
    def kinder = []
 }
 def johannes = new Person(name: quot;Johanne...
Groovy Beans & GPath
 class Person {
 
    def name
 
    def kinder = []
 }
 def johannes = new Person(name: quot;Johanne...
Groovy -Closures
def to = quot;JUGSquot;
def say = { msg ->
    msg + quot;, $toquot;
}
assert say(quot;Halloquot;) == quo...
Java VM <->
  Groovy
Java VM <->
  Groovy
• Groovy-Klassen können beliebig auf
  Java-Klassen zugreifen
  • und umgekehrt!
Java VM <->
  Groovy
• Groovy-Klassen können beliebig auf
  Java-Klassen zugreifen
  • und umgekehrt!
• Es werden immer Kl...
Vorkompilierter
       Groovy-Code

• groovyc -> *.class files
• groovyc -jointCompilation
  behebt Henne-Ei-Problem

• Aus...
Dynamische Evaluation
    zur Laufzeit
Dynamische Evaluation
    zur Laufzeit
• Eval.x(users,
     quot;x.grep{ it.salary -> 100000 }.address.townquot;);
  // me...
Dynamische Evaluation
    zur Laufzeit
• Eval.x(users,
      quot;x.grep{ it.salary -> 100000 }.address.townquot;);
   // ...
Dynamische Evaluation
    zur Laufzeit
• Eval.x(users,
      quot;x.grep{ it.salary -> 100000 }.address.townquot;);
   // ...
Dynamische Evaluation
    zur Laufzeit
• Eval.x(users,
      quot;x.grep{ it.salary -> 100000 }.address.townquot;);
   // ...
Dynamische Evaluation
    zur Laufzeit
• Eval.x(users,
      quot;x.grep{ it.salary -> 100000 }.address.townquot;);
   // ...
Dynamische Evaluation
    zur Laufzeit
• Eval.x(users,
      quot;x.grep{ it.salary -> 100000 }.address.townquot;);
   // ...
Dynamik &
 Metaprogrammierung

• Dynamischer Methodenaufruf
  und Hooks

• Kategorien
• Methoden zur Laufzeit hinzufügen
Methodenaufrufe in Java
     und Groovy
In Java:                    In Groovy:
• Zur Übersetzungszeit      • Zur Ausführun...
Dynamischer Aufruf
class X   {          def x = new X()
    def   a = 1      def methodName, propName
    def   b = 2
    ...
methodMissing()
class PrintMissingMethods {
    def methodMissing(String name, args) {
        println quot;missing $name ...
Kategorien
class FooCategory {                       •   Kategorie: Klasse
    static def foo(List self, arg) {          m...
Methoden zur Laufzeit
        hinzufügen
String.metaClass.upperCaseCount = { ->      •   Sogenannte

    (delegate =~ /[A-...
Was gibt es noch?

• XML-Support eingebaut
• Builder-Konzept (z.B. SwingBuilder)
• Nahtlose Ant-Integration
• Testen leich...
Wie entwickle ich
  Groovy-Programme?
• groovysh
• groovyConsole
• IDE-Support
 • IDEA IntelliJ
 • Eclipse
 • NetBeans
Einsatzmuster für Scripting
    (von Dierk König)
• Alleskleber
• Weiches Herz
• Kluge Anpassung
• Endoskopische Operation...
Einsatzmuster:
         Alleskleber
• Applikationen aus bestehenden
  Komponenten zusammenbauen

• Java ist gut geeignet f...
Alleskleber Demo:
       RSS Reader


• Zusammenbau von XML Parser, Java
 Networking und Swing Widget
 Bibliothek, um eine...
Einsatzmuster:
        Weiches Herz
• Fachliche Modelle auslagern bei
  vorgegebenem Java-Applikationsgerüst

• Fachlichen...
Weiches Herz Beispiel:
  Bonusberechnung
umsatz = mitarbeiter.umsatz
switch(umsatz / 1000) {
    case 0..100: return umsat...
Weiches Herz Beispiel:
   Bonusberechnung
umsatz = mitarbeiter.umsatz
switch(umsatz / 1000) {
    case 0..100: return umsa...
Einsatzmuster:
     Kluge Anpassung
• Konfigurationen mit Ausführungs-Logik als
  Ersatz für XML-Konfigurationen
  • Mit Ref...
DSL-Beispiel (von Bernd Schiffer):
    Entfernungsberechnung
 assert 5001.m == 2000.m + 3.km + 1.m
DSL-Beispiel (von Bernd Schiffer):
    Entfernungsberechnung
 assert 5001.m == 2000.m + 3.km + 1.m

 class Meter {
 
     ...
DSL-Beispiel (von Bernd Schiffer):
    Entfernungsberechnung
 assert 5001.m == 2000.m + 3.km + 1.m

 class Meter {
 
     ...
Einsatzmuster:
Endoskopische Operation
• Minimal-invasive Eingriffe quot;in vivoquot;
• Viele Notwendigkeiten für Anpassun...
Endoskopische
Operation: im Servlet
Endoskopische
    Operation: im Servlet
Probleme mit der Datenbank Verbindung?
def ds = Config.dataSource
ds.connection = ...
Endoskopische
    Operation: im Servlet
Probleme mit der Datenbank Verbindung?
def ds = Config.dataSource
ds.connection = ...
Einsatzmuster:
 Grenzenlose Offenheit
• Jede Zeile Code wird änderbar
• Manchmal sind die vorgesehenen
  Variationspunkte ...
Einsatzmuster:
    Heinzelmännchen
• Repetitive Aufgaben automatisieren
• Automatisierter Build, kontinuierliche
  Integra...
Heinzelmännchen:
        Mail schicken
def users = [ [name:'Johannes', email:'jl@johanneslink.net'],
              [name:'...
Einsatzmuster: Prototyp
• Machbarkeitsstudien auf der
  Zielplattform

• quot;Spikesquot; für technologische oder
  algori...
Weitere Informationen


• http://groovy.codehaus.org/
• http://grails.codehaus.org/
• Dierk König et al: „Groovy in Action“
Zusammenfassung
• Die Programmiersprache Java hat
  Einschränkungen:
  • Anpassungen zur Laufzeit
  • Präzision im Ausdruc...
Fragen und
Anmerkungen?
http://www.slideshare.net/jlink/
  mehr-dynamik-mit-groovy/
Upcoming SlideShare
Loading in...5
×

Mehr Dynamik Mit Groovy

4,466

Published on

Problems with Java and how dynamic scripting languages (especially Groovy) tackle some of them. A short introduction to some aspects of Groovy is included.

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
4,466
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
0
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Transcript of "Mehr Dynamik Mit Groovy"

  1. 1. Groovy Mehr Dynamik bei der Java- Entwicklung
  2. 2. Wer ich bin...
  3. 3. Wer ich bin... Mein eigener Chef (Extremer) Softwareentwickler (Agiler) Coach Testgetrieben http://johanneslink.net
  4. 4. Java-Frust
  5. 5. Java-Frust public class Person... public String getName() { return name; }
  6. 6. Java-Frust public class Person... public String getName() { return name; } public static List<Person> sortByName(Set<Person> people) { List<Person> sortedResult = new ArrayList<Person>(people); Comparator<Person> nameComparator = new Comparator<Person>() { public int compare(Person o1, Person o2) { return o1.getName().compareTo(o2.getName()); } }; Collections.sort(sortedResult, nameComparator); return sortedResult; }
  7. 7. Java-Frust public class Person... public String getName() { return name; } public static List<Person> sortByName(Set<Person> people) { List<Person> sortedResult = new ArrayList<Person>(people); Comparator<Person> nameComparator = new Comparator<Person>() { public int compare(Person o1, Person o2) { return o1.getName().compareTo(o2.getName()); } }; Collections.sort(sortedResult, nameComparator); return sortedResult; } public class FinancialInstrument... public String getName() { return name; }
  8. 8. Java-Frust public class Person implements Namable... public String getName() { return name; } public static List<Person> sortByName(Set<Person> people) { List<Person> sortedResult = new ArrayList<Person>(people); Comparator<Person> nameComparator = new Comparator<Person>() { public int compare(Person o1, Person o2) { return o1.getName().compareTo(o2.getName()); } }; Collections.sort(sortedResult, nameComparator); return sortedResult; } public class FinancialInstrument implements Namable... public String getName() { return name; }
  9. 9. Java-Frust public class Person implements Namable... public String getName() { return name; } public class MyHelper... public static List<Person> Namable> List<T> sortByName(Set<T> namables) { public static <T extends sortByName(Set<Person> people) { List<Person> sortedResult = ArrayList<T>(namables); List<T> sortedResult = new new ArrayList<Person>(people); Comparator<Person> nameComparator = Comparator<T>() { Comparator<T> nameComparator = new new Comparator<Person>() { public int compare(Person T o2) { public int compare(T o1, o1, Person o2) { return o1.getName().compareTo(o2.getName()); return o1.getName().compareTo(o2.getName()); } } }; }; Collections.sort(sortedResult, nameComparator); Collections.sort(sortedResult, nameComparator); return sortedResult; return sortedResult; } } public class FinancialInstrument implements Namable... public String getName() { return name; }
  10. 10. Java-Frust public class Person... public String getName() { return name; } public class MyHelper... public static <T extends Namable> List<T> sortByName(Set<T> namables) { List<T> sortedResult = new ArrayList<T>(namables); Comparator<T> nameComparator = new Comparator<T>() { public int compare(T o1, T o2) { return o1.getName().compareTo(o2.getName()); } }; Collections.sort(sortedResult, nameComparator); return sortedResult; } public class FinancialInstrument... public String getName() { return name; }
  11. 11. Java-Frust public class Person... public String getName() { return name; } public class MyHelper... public static <T extends Namable> List<T> sortByName(Set<T> namables) { List<T> sortedResult = new ArrayList<T>(namables); Comparator<T> nameComparator = new Comparator<T>() { public int compare(T o1, T o2) { Collection sortByName return o1.getName().compareTo(o2.getName()); self sort: [:each | each name] }; } Collections.sort(sortedResult, nameComparator); return sortedResult; } public class FinancialInstrument... public String getName() { return name; }
  12. 12. Typische Java Smells public class MyHelper... public static <T extends Namable> List<T> sortByName(Set<T> namables) { List<T> sortedResult = new ArrayList<T>(namables); Comparator<T> nameComparator = new Comparator<T>() { public int compare(T o1, T o2) { return o1.getName().compareTo(o2.getName()); } }; Collections.sort(sortedResult, nameComparator); return sortedResult; }
  13. 13. Typische Java Smells public class MyHelper... public static <T extends Namable> List<T> sortByName(Set<T> namables) { List<T> sortedResult = new ArrayList<T>(namables); Comparator<T> nameComparator = new Comparator<T>() { public int compare(T o1, T o2) { return o1.getName().compareTo(o2.getName()); } }; Collections.sort(sortedResult, nameComparator); return sortedResult; }
  14. 14. Typische Java Smells public class MyHelper... public static <T extends Namable> List<T> sortByName(Set<T> namables) { List<T> sortedResult = new ArrayList<T>(namables); Comparator<T> nameComparator = new Comparator<T>() { public int compare(T o1, T o2) { return o1.getName().compareTo(o2.getName()); } }; Collections.sort(sortedResult, nameComparator); return sortedResult; }
  15. 15. Typische Java Smells public class MyHelper... public static <T extends Namable> List<T> sortByName(Set<T> namables) { List<T> sortedResult = new ArrayList<T>(namables); Comparator<T> nameComparator = new Comparator<T>() { public int compare(T o1, T o2) { return o1.getName().compareTo(o2.getName()); } }; Collections.sort(sortedResult, nameComparator); return sortedResult; }
  16. 16. Typische Java Smells public class MyHelper... public static <T extends Namable> List<T> sortByName(Set<T> namables) { List<T> sortedResult = new ArrayList<T>(namables); Comparator<T> nameComparator = new Comparator<T>() { public int compare(T o1, T o2) { return o1.getName().compareTo(o2.getName()); } }; Collections.sort(sortedResult, nameComparator); return sortedResult; } • Variables Verhalten erfordert eigene (anonyme) Klasse • Incomplete Library Smell • Statische Typisierung erzwingt viele gemeinsame Interfaces • Unvorhergesehenes Veränderung => Neukompilierung
  17. 17. Die Rettung naht: Dynamische Skriptsprachen • Scripting • Dynamik
  18. 18. Scripting • Knappe und ausdrucksstarke Syntax • Ausführung von Programmcode ohne (spürbare) Compilierung • Selbstständige Skripte • Aus einer Applikation heraus
  19. 19. Scripting • Knappe und ausdrucksstarke Syntax • Ausführung von Programmcode ohne (spürbare) Compilierung • Selbstständige Skripte • Aus einer Applikation heraus List<Person> people = new ArrayList<Person>(); people.add(new Person(quot;Dierkquot;)); ... List<Person> sorted = (List<Person>) Eval.x(people, quot;x.sort {it.name}quot; );
  20. 20. Scripting • Knappe und ausdrucksstarke Syntax • Ausführung von Programmcode ohne (spürbare) Compilierung • Selbstständige Skripte • Aus einer Applikation heraus List<Person> people = new ArrayList<Person>(); people.add(new Person(quot;Dierkquot;)); ... List<Person> sorted = (List<Person>) Eval.x(people, quot;x.sort {it.name}quot; );
  21. 21. Dynamik • Dynamische Typisierung • Closures • Meta-Programmierung
  22. 22. Dynamische Typisierung aka „Duck Typing“ def sortByName(unsorted) { unsorted.sort {it.name} } def people = [ new Student(quot;Johannesquot;), new Person(quot;Dierkquot;) ] def sorted = sortByName(people) assert sorted[0].name == quot;Dierkquot; assert sorted[1].name == quot;Johannesquot;
  23. 23. Closures (1) Programmlogik als vollwertiges Objekt def sorter = { unsorted -> unsorted.sort {it.name} } def sorted = sorter(people) //oder so: def sorted = sorter.call(people)
  24. 24. Closures (2) • Iteration als typischer Anwendungsfall
  25. 25. Closures (2) • Iteration als typischer Anwendungsfall def namen = [quot;Johannesquot;, quot;Frankquot;, quot;Dierkquot;] def auswahl = namen.findAll {name -> name.contains quot;nquot;} assert auswahl == [quot;Johannesquot;, quot;Frankquot;]
  26. 26. Closures (2) • Iteration als typischer Anwendungsfall def namen = [quot;Johannesquot;, quot;Frankquot;, quot;Dierkquot;] def auswahl = namen.findAll {name -> name.contains quot;nquot;} assert auswahl == [quot;Johannesquot;, quot;Frankquot;] List<String> auswahl = new ArrayList<String>(); for (String name : namen) { if (name.contains(quot;nquot;)) { auswahl.add(name); } } Äquivalenter Java Code
  27. 27. Meta-Programmierung • Erweiterung existierender Klassen • Hinzufügen von Methoden zur Laufzeit • Erweiterung / Veränderung der Sprache durch Verwendung eines „Meta Object Protocol“
  28. 28. Meta Object Protocol „A metaobject protocol (MOP) is an interpreter of the semantics of a program that is open and extensible“ (Wikipedia) class MyObject { def prop void setProperty(String name, value) { prop = value } def getProperty(String name) { prop } } def obj = new MyObject() obj.firstName = quot;Johannesquot; obj.lastName = quot;Linkquot; assert obj.firstName == quot;Linkquot;
  29. 29. Meta Object Protocol „A metaobject protocol (MOP) is an interpreter of the semantics of a program that is open and extensible“ (Wikipedia) Class.metaClass.'static'.create = { Object[] args -> delegate.metaClass.invokeConstructor(*args) } assert new ArrayList() == ArrayList.create() assert new HashMap() == HashMap.create() assert new Integer(42) == Integer.create(42) assert new Dimension(1,1) == Dimension.create(1,1)
  30. 30. Vorteile / Nachteile dynamischer Skriptsprachen • Vorteile: • Weniger Code • Weniger Duplikation • Verständlichere Abstraktionen • Mehr Deployment-Optionen
  31. 31. Vorteile / Nachteile dynamischer Skriptsprachen • Vorteile: • Weniger Code • Weniger Duplikation • Verständlichere Abstraktionen • Mehr Deployment-Optionen • Nachteile: • Erschwerte statische Codeanalyse • Schlechtere Performance
  32. 32. Welche Skriptsprachen gibt es? • Verbreiteste Skriptsprachen: Perl, PHP, Python, Ruby, JavaScript • Mehr als 200 verschiedene Sprachen allein auf der Java VM: Groovy, JRuby, Scala, Bistro ...
  33. 33. Groovy in der Sprachlandschaft Text (c) Dierk König
  34. 34. Groovy
  35. 35. Groovy • Volle Objekt- Orientierung ohne primitive Typen
  36. 36. Groovy • Volle Objekt- Orientierung ohne primitive Typen • Optionale statische Typisierung
  37. 37. Groovy • Volle Objekt- Orientierung ohne primitive Typen • Optionale statische Typisierung • Closures
  38. 38. Groovy • Volle Objekt- Orientierung ohne primitive Typen • Optionale statische Typisierung • Closures • Listen und Maps als Literale
  39. 39. Groovy • Volle Objekt- • Volle Integration Orientierung ohne mit der Java- primitive Typen Plattform • Optionale statische • Generics Typisierung • Annotations • Closures • Security-Model • Listen und Maps als Literale
  40. 40. Groovy • Volle Objekt- • Volle Integration Orientierung ohne mit der Java- primitive Typen Plattform • Optionale statische • Generics Typisierung • Annotations • Closures • Security-Model • Listen und Maps • Wird (immer) in als Literale echten Bytecode kompiliert
  41. 41. Groovy - Vereinfachte Syntax System.out.println(quot;Hello World!quot;); //Java style println 'Hello, World!' def vorname = 'Stefan' println quot;$vorname, ich hol' den Wagen.quot; String lang = quot;quot;quot;Du, ${vorname}, der Wagen steht eine Zeile weiter.quot;quot;quot; assert 0.5 == 1/2 def printSize(obj) { print obj?.size() } printSize(null) -> null
  42. 42. Reguläre Ausdrücke assert (quot;Hello World!quot; =~ /Hello/) // Find-Operator assert (quot;Hello World!quot; ==~ /Hellob.*/) // Match-Operator def pattern = ~/.*ll.*/ // java.util.regex.Pattern.compile(quot;.*ll.*quot;) assert [quot;halloquot;, quot;helloquot;, quot;holaquot;].grep(pattern) == [quot;halloquot;, quot;helloquot;] def coded = quot;Hallo, JUG Cologne!quot;.replaceAll(/w+/){ match -> match.size() } assert coded == quot;5, 3 7!quot;
  43. 43. Listen, ... def leer = [] def voll = [1, 2, 'JUGC'] assert voll + voll == voll * 2 assert voll[0] == 1 assert voll[0..1] == [1, 2] voll[0..1] = [0, 1, 2, 3] assert voll == [0, 1, 2, 3, 'JUGC'] assert voll[2..-1] == [2, 3, 'JUGC']
  44. 44. ... Maps und Ranges def leer = [:] def voll = [a: 1, b: 2] assert voll['a'] == 1 assert voll.a == 1 voll.a = 2 assert voll == [a: 2, b: 2] def inclusive = 'a'..'z' inclusive.each {c -> print c} def exclusive = 0..<10 for (i in exclusive) {print i}
  45. 45. Groovy Beans & GPath class Person { def name def kinder = [] } def johannes = new Person(name: quot;Johannesquot;) assert johannes.name == quot;Johannesquot;
  46. 46. Groovy Beans & GPath class Person { def name def kinder = [] } def johannes = new Person(name: quot;Johannesquot;) assert johannes.name == quot;Johannesquot; johannes.kinder += new Person(name: quot;Jannekquot;) johannes.kinder += new Person(name: quot;Niklasquot;) assert johannes.kinder.size() == 2 assert johannes.kinder[0].name == quot;Jannekquot;
  47. 47. Groovy Beans & GPath class Person { def name def kinder = [] } def johannes = new Person(name: quot;Johannesquot;) assert johannes.name == quot;Johannesquot; johannes.kinder += new Person(name: quot;Jannekquot;) johannes.kinder += new Person(name: quot;Niklasquot;) assert johannes.kinder.size() == 2 assert johannes.kinder[0].name == quot;Jannekquot; assert johannes.kinder.name == [quot;Jannekquot;, quot;Niklasquot;] assert johannes.kinder.kinder*.size() == [0, 0]
  48. 48. Groovy -Closures def to = quot;JUGSquot; def say = { msg -> msg + quot;, $toquot; } assert say(quot;Halloquot;) == quot;Hallo, JUGSquot; to = quot;JUG Colognequot; assert say(quot;Halloquot;) == quot;Hallo, JUG Colognequot; (1..10).each { println it } [a:1, b:2].each { key, value -> println quot;key: $key, value: $valuequot; }
  49. 49. Java VM <-> Groovy
  50. 50. Java VM <-> Groovy • Groovy-Klassen können beliebig auf Java-Klassen zugreifen • und umgekehrt!
  51. 51. Java VM <-> Groovy • Groovy-Klassen können beliebig auf Java-Klassen zugreifen • und umgekehrt! • Es werden immer Klassen im Bytecode erzeugt • Egal ob Scripts oder Klassen • Egal ob vorkompiliert oder zur Laufzeit
  52. 52. Vorkompilierter Groovy-Code • groovyc -> *.class files • groovyc -jointCompilation behebt Henne-Ei-Problem • Auslieferung meist als JAR • groovy-all-x.y.z.jar mitausliefern
  53. 53. Dynamische Evaluation zur Laufzeit
  54. 54. Dynamische Evaluation zur Laufzeit • Eval.x(users, quot;x.grep{ it.salary -> 100000 }.address.townquot;); // me, x(), xy(), xyz()
  55. 55. Dynamische Evaluation zur Laufzeit • Eval.x(users, quot;x.grep{ it.salary -> 100000 }.address.townquot;); // me, x(), xy(), xyz() • GroovyShell: parse, binding, evaluate (String|File|Url)
  56. 56. Dynamische Evaluation zur Laufzeit • Eval.x(users, quot;x.grep{ it.salary -> 100000 }.address.townquot;); // me, x(), xy(), xyz() • GroovyShell: parse, binding, evaluate (String|File|Url) • GroovyScriptEngine: für viele Sourcen und Pfadunterstützung
  57. 57. Dynamische Evaluation zur Laufzeit • Eval.x(users, quot;x.grep{ it.salary -> 100000 }.address.townquot;); // me, x(), xy(), xyz() • GroovyShell: parse, binding, evaluate (String|File|Url) • GroovyScriptEngine: für viele Sourcen und Pfadunterstützung • GroovyClassLoader (transparente Quellen, Security!)
  58. 58. Dynamische Evaluation zur Laufzeit • Eval.x(users, quot;x.grep{ it.salary -> 100000 }.address.townquot;); // me, x(), xy(), xyz() • GroovyShell: parse, binding, evaluate (String|File|Url) • GroovyScriptEngine: für viele Sourcen und Pfadunterstützung • GroovyClassLoader (transparente Quellen, Security!) • Bean Scripting Framework und JSR-223 (Java 6)
  59. 59. Dynamische Evaluation zur Laufzeit • Eval.x(users, quot;x.grep{ it.salary -> 100000 }.address.townquot;); // me, x(), xy(), xyz() • GroovyShell: parse, binding, evaluate (String|File|Url) • GroovyScriptEngine: für viele Sourcen und Pfadunterstützung • GroovyClassLoader (transparente Quellen, Security!) • Bean Scripting Framework und JSR-223 (Java 6) • Groovy Spring Beans
  60. 60. Dynamik & Metaprogrammierung • Dynamischer Methodenaufruf und Hooks • Kategorien • Methoden zur Laufzeit hinzufügen
  61. 61. Methodenaufrufe in Java und Groovy In Java: In Groovy: • Zur Übersetzungszeit • Zur Ausführungszeit wird festgelegt, welche wird dynamisch Methode ermittelt, auf welcher wie auf einen Vererbungshierarchie Methodenaufruf aufgerufen wird reagiert wird • Zur Ausführungszeit wird dynamisch ermittelt, wie auf einen Property- Zugriff reagiert wird
  62. 62. Dynamischer Aufruf class X { def x = new X() def a = 1 def methodName, propName def b = 2 def foo () { methodName = 'foo' 3 assert 3 == x.quot;$methodNamequot;() } } propName = 'a' assert 1 == x.quot;$propNamequot; propName = 'b' assert 2 == x.quot;$propNamequot;
  63. 63. methodMissing() class PrintMissingMethods { def methodMissing(String name, args) { println quot;missing $name with $argsquot; args.size() } } x = new PrintMissingMethods() assert 2 == x.foo(1,2) -> missing foo with {1, 2} assert 3 == x.bar('just', 'a', 'test') -> missing bar with {quot;justquot;, quot;aquot;, quot;testquot;}
  64. 64. Kategorien class FooCategory { • Kategorie: Klasse static def foo(List self, arg) { mit statischen self + [arg] Methoden } • Erstes Argument ist static def foo(String self, arg) { Empfänger der self + arg Methode } • Weitere Argumente } sind Parameter der Methode use(FooCategory) { assert [123].foo(456) == [123, 456] • Verwendung der assert '123'.foo('456') == '123456' Kategorie mittels } use(...) { ... }
  65. 65. Methoden zur Laufzeit hinzufügen String.metaClass.upperCaseCount = { -> • Sogenannte (delegate =~ /[A-Z]/).size() ExpandoMetaClass } • Methode definieren: assert 1 == quot;Onequot;.upperCaseCount() Property der assert 2 == quot;TWoquot;.upperCaseCount() Metaklasse auf eine assert 3 == quot;ThReEquot;.upperCaseCount() Closure setzen, fertig! Integer.metaClass.'static'. answerToEverything = { -> 42 } • Auch assert 42 == Integer.answerToEverything() Klassenmethoden können definiert werden ExpandoMetaClass.enableGlobally() Object.metaClass.tate = { -> 42 } • Auch Vererbung assert 42 == new X().tate() funktioniert
  66. 66. Was gibt es noch? • XML-Support eingebaut • Builder-Konzept (z.B. SwingBuilder) • Nahtlose Ant-Integration • Testen leicht gemacht • Web-Applikationen mit Grails (= Spring + Hibernate + Groovy) • ...
  67. 67. Wie entwickle ich Groovy-Programme? • groovysh • groovyConsole • IDE-Support • IDEA IntelliJ • Eclipse • NetBeans
  68. 68. Einsatzmuster für Scripting (von Dierk König) • Alleskleber • Weiches Herz • Kluge Anpassung • Endoskopische Operation • Grenzenlose Offenheit • Heinzelmännchen • Prototyp
  69. 69. Einsatzmuster: Alleskleber • Applikationen aus bestehenden Komponenten zusammenbauen • Java ist gut geeignet für stabile Infrastruktur: Middleware, Frameworks, Widget Sets, Services • Scripting ist gut geeignet für flexible View- und Controller-Schichten (z.B. Grails)
  70. 70. Alleskleber Demo: RSS Reader • Zusammenbau von XML Parser, Java Networking und Swing Widget Bibliothek, um einen Standard-RSS Feed darzustellen
  71. 71. Einsatzmuster: Weiches Herz • Fachliche Modelle auslagern bei vorgegebenem Java-Applikationsgerüst • Fachlichen Erkenntnisfortschritt ermöglichen: Entitäten, Beziehungen und Verhalten bleiben durch Scripting flexibel • Verhaltensänderung zur Laufzeit
  72. 72. Weiches Herz Beispiel: Bonusberechnung umsatz = mitarbeiter.umsatz switch(umsatz / 1000) { case 0..100: return umsatz * 0.04 case 100..200: return umsatz * 0.05 case {it > 200}: bonusClub.add(mitarbeiter) return umsatz * 0.06 }
  73. 73. Weiches Herz Beispiel: Bonusberechnung umsatz = mitarbeiter.umsatz switch(umsatz / 1000) { case 0..100: return umsatz * 0.04 case 100..200: return umsatz * 0.05 case {it > 200}: bonusClub.add(mitarbeiter) return umsatz * 0.06 } Binding binding = new Binding(); binding.setVariable(quot;mitarbeiterquot;, mitarbeiter); binding.setVariable(quot;bonusClubquot;, bonusClub); GroovyShell shell = new GroovyShell(binding); File script = new File(filename); BigDecimal bonus = (BigDecimal) shell.evaluate(script);
  74. 74. Einsatzmuster: Kluge Anpassung • Konfigurationen mit Ausführungs-Logik als Ersatz für XML-Konfigurationen • Mit Referenzen, Schleifen, Bedingungen, Vererbung, Ausführungslogik, Umgebungsermittlung, ... • Typischer Anwendungsfall für domänen- spezifische Sprachen (DSLs) • Veränderungen durch den Experten
  75. 75. DSL-Beispiel (von Bernd Schiffer): Entfernungsberechnung assert 5001.m == 2000.m + 3.km + 1.m
  76. 76. DSL-Beispiel (von Bernd Schiffer): Entfernungsberechnung assert 5001.m == 2000.m + 3.km + 1.m class Meter { def meter Meter(meter) { this.meter = meter } def plus(kilometer) { new Meter(meter + kilometer.meter) } boolean equals(other) { this.meter == other.meter } } class Kilometer { def meter Kilometer(kilometer) { meter = kilometer * 1000 } } class Distance { static def getM(distance) { new Meter(distance) } static def getKm(distance) { new Kilometer(distance) } }
  77. 77. DSL-Beispiel (von Bernd Schiffer): Entfernungsberechnung assert 5001.m == 2000.m + 3.km + 1.m class Meter { def meter assert werteAus('5002 m == 2000 m + 3 km + 2 m') Meter(meter) { this.meter = meter } def plus(kilometer) { def werteAus(String anweisung) { new Meter(meter + kilometer.meter) } Eval.me( boolean equals(other) { anweisung.replaceAll(quot; (m|km)quot;, { } this.meter == other.meter } alle, einheit -> quot;.${einheit}quot; class Kilometer { })) def meter Kilometer(kilometer) { } meter = kilometer * 1000 } } class Distance { static def getM(distance) { new Meter(distance) } static def getKm(distance) { new Kilometer(distance) } }
  78. 78. Einsatzmuster: Endoskopische Operation • Minimal-invasive Eingriffe quot;in vivoquot; • Viele Notwendigkeiten für Anpassungen ad-hoc Anfragen sind nicht vorhersehbar • Schlüsselloch für die Live Ausführung von Scripts schaffen, z.B. in einem speziellen Servlet • Unglaublich wertvoll für Produkt-Support, Fehleranalyse, Hot-Fixes, Notfälle
  79. 79. Endoskopische Operation: im Servlet
  80. 80. Endoskopische Operation: im Servlet Probleme mit der Datenbank Verbindung? def ds = Config.dataSource ds.connection = new DebugConnection(ds.connection)
  81. 81. Endoskopische Operation: im Servlet Probleme mit der Datenbank Verbindung? def ds = Config.dataSource ds.connection = new DebugConnection(ds.connection) Gefährliche Benutzer rauswerfen users = servletContext.getAttribute('users') bad = users.findAll { user -> user.cart.items.any { it.price < 0 } } servletContext.setAttribute('users', users - bad)
  82. 82. Einsatzmuster: Grenzenlose Offenheit • Jede Zeile Code wird änderbar • Manchmal sind die vorgesehenen Variationspunkte nicht ausreichend • Einfache Änderungen ohne langwieriges Setup für Kompilation und Deployment • Perl, PHP, Python, etc. machen es vor
  83. 83. Einsatzmuster: Heinzelmännchen • Repetitive Aufgaben automatisieren • Automatisierter Build, kontinuierliche Integration, Deployment, Installationen, Server-Überwachung, Reports, Statistiken, Erzeugen von Dokumentation, funktionale Tests uvm. • Anwendungen mit Ant, Maven und Co.
  84. 84. Heinzelmännchen: Mail schicken def users = [ [name:'Johannes', email:'jl@johanneslink.net'], [name:'Teilnehmer', email:'wer@wo.net']] def ant = new groovy.util.AntBuilder() for (user in users) { ant.mail(mailhost: 'smtp.googlemail.com', mailport: '465', ssl: 'true', user: quot;$mailUserquot;, password: quot;$passwordquot;, subject: 'Vortrag ist bald fertig') { from(address: 'johannes.link@googlemail.com') to(address: user.email) message( quot;quot;quot; Hallo ${user.name}, Der Vortrag ist fast fertig: ${new Date().toGMTString()} quot;quot;quot; ) } }
  85. 85. Einsatzmuster: Prototyp • Machbarkeitsstudien auf der Zielplattform • quot;Spikesquot; für technologische oder algorithmische Ideen mit besserer Ausdrucksmächtigkeit, schnellerem Feedback und besseren Analysemöglichkeiten • Wahlmöglichkeit für spätere (Teil-) Portierung nach Java / C#
  86. 86. Weitere Informationen • http://groovy.codehaus.org/ • http://grails.codehaus.org/ • Dierk König et al: „Groovy in Action“
  87. 87. Zusammenfassung • Die Programmiersprache Java hat Einschränkungen: • Anpassungen zur Laufzeit • Präzision im Ausdruck • Erweiterbarkeit der Sprache • Groovy als dynamische Skriptsprache ist in diesen Punkten flexibler und mächtiger • Groovys Ziel ist die best mögliche Integration in die Java-Plattform • Es existieren typische Einsatzmuster
  88. 88. Fragen und Anmerkungen? http://www.slideshare.net/jlink/ mehr-dynamik-mit-groovy/

×