====== Errata ====== //Trotz aller Sorgfalt beim Schreiben und beim Prüfen eines umfangreicheren Buchs ist es kaum möglich, kleine (und leider manchmal auch größere) Druckfehler oder sonstige Versehen völlig zu vermeiden. In manchen Fällen hat sich auch nur die Bedeutung einzelner Konstrukte in Groovy gegenüber der Version, die dem Buch zugrunde liegt, geändert. Schauen Sie gelegentlich einmal herein; besonders, wenn Ihnen einmal etwas sehr komisch im Text vorkommen sollte.// //Und falls Sie selbst einen Fehler im Buch finden, der hier noch nicht aufgeführt ist: Helfen Sie uns und den anderen Lesern, indem Sie ihn auf der [[http://www.oreilly.de/catalog/groovyger/fehlermeldung.html | Buchseite des Verlags]] melden.// ===== Zu Kapitel 1: Erste Schritte ===== **Seite 8**. Oberes Listing:\\ Statt ''System.properties.sort {...}'' muss es heißen: ''System.properties.entrySet().sort {...}''. Die Elemente einer ''Hashtable'' sind nicht direkt sortierbar, man muss sie daher zunächst mit Hilfe der ''entrySet()''-Methode in ein ''Set'' verwandeln, für das die Methode ''sort()'' definiert ist. ===== Zu Kapitel 2: Die Sprache Groovy ===== **Seite 18**. Kasten "Warum ist Groovy anders", erster Punkt der Aufzählung in der Mitte der Seite:\\ Statt ''%%"abc".toUpperCase()=="abc"%%'' heißt es richtig ''%%"abc".toUpperCase()=="ABC"%%''. **Seite 28**. Listing in der Mitte: Die Zeile groovy> println zahlen.[0] * zahlen.get[1] ist völlig missraten und sollte durch die folgende ersetzt werden: groovy> println zahlen[0] * zahlen[1] **Seite 40**. Unter //Statisches this// sollte das Listing folgendermaßen lauten: class EineKlasse { static main (args) { assert this == EineKlasse } } **Seite 41**. Unter //Generische Datentypen// sind in ''new ArrayList{}'' die geschweiften Klammern durch runde Klammern zu ersetzten: ''new ArrayList()''. **Seite 41**. Unter //Annotationen// fehlt der Hinweis, dass Array-Argumente zu Annotationen bei Groovy in eckigen Klammern stehen müssen und nicht in geschweiften Klammmern wie bei Java. **Seite 42**. Unter //Das typsichere ''Enum''// sollte erwähnt werden, dass, wenn ein Enum als ''switch''-Wert verwendet wird, die ''case''-Werte unter Groovy vollständig referenziert werden müssen. Angenommen, Sie haben folgenden ''Enum''-Typ definiert: enum E { ALPHA, BETA, GAMMA } Wenn die variable ''e'' einen ''E''-Wert hält, genügt es unter Java, als ''case''-Wert den Elementnamen anzugeben: switch (e) { case ALPHA: ... } Bei Groovy ist dagegen Folgendes nötig: switch (e) { case E.ALPHA: ... } Alternativ können Sie auch den ''Enum''-Typ einfach statisch importieren: import static E.* ===== Zu Kapitel 3: Objekte in Groovy ===== **Seite 50**. Im Listing //Beispiel 3-2// sollte die erste Zeile ganz am Ende stehen, um zu zeigen, dass in einem Groovy-Skript die ''import''-Anweisung irgendwo im Programm (außerhalb einer Klassen- oder Methodendefinition) stehen kann. **Seite 52**. Decompiler-Listing oben:\\ In der drittletzten Zeile müssen das ''public'' und ein geschweiftes Klammerpaar entfernt werden. Die Zeile sieht dann so aus: static {...} **Seite 64**. Oberes Listing:\\ Es fehlt die folgende zweite Zeile: Calendar calendar = new GregorianCalendar() **Seite 72**. Groovy-Listing in der Mitte:\\ Hier sollte in der vorletzten Zeile ''enabled:true'' stehen, damit es mit dem Java-Code oberhalb übereinstimmt. **Seite 74/75**. Tabelle 3-1 //Operatoren und Operatormethoden//, Abschnitt //Arithmetische Operatoren//:\\ Die Negation wird jetzt in einen eine Aufruf der Methode ''unaryMinus()'' übersetzt.\\ Der zum Modulo-Operator gehörende Ausdruck lautet nicht ''x / y'' sondern ''x % y''.\\ Abschnitt //Binäre Operatoren//:\\ Das Komplement wird jetzt in einen Aufruf der Methode ''bitwiseNegate()'' übersetzt.\\ Abschnitt //Sonstige Operatoren//:\\ Der Methodenaufruf zu ''x in y'' lautet ''x.isCase(y)''. Generell fehlt hier der Hinweis, dass die Operator-Aufrufe bei JDK- und Groovy-Standardklassen aus Performance-Gründen teilweise bereits durch die Groovy-Laufzeitumgebung implementiert werden. **Seite 76**. Listing //Beispiel 3-3//:\\ Folgende Zeile (etwa in der Mitte der Seite) normalwert = arg.normalwert * faktor ist folgendermaßen zu ändern: wert = arg.normalwert * faktor **Seite 79**. Abschnitt //Dereferenzieren von Listen//:\\ Die folgende Anweisung groovy> println bookmarks.getProtocol() funktioniert in der aktuellen Groovy-Version nicht mehr in dieser Form (wobei nicht ganz klar ist, ob es dies absichtlich so ist). Um sicher zu gehen, sollte man immer den Spread-Dot-Operator (''*.'') verwenden, um Methoden oder Properties bei allen Elementen einer Liste aufzurufen. groovy> println bookmarks*.getProtocol() groovy> println bookmarks*.protocol.unique() ===== Zu Kapitel 4: Neue Konzepte ===== **Seite 92**. Am Ende des vorletzten Absatzes der Seite muss es heißen: "...und sich als ''Comparator'' verkleidet." **Seite 94/95**. In dem Skript, das unten auf Seite 94 beginnt, sollte nach ''println this.class'' noch eine Zeile ''println owner.class'' folgen. Diese Anweisung führt dazu, dass ein zweites Mal ''class TestClosure1'' ausgegeben wird. **Seite 96**. Beispiel 4-3: Die drei Protokollausgaben beginnen jeweils mit ''log(...)'' (klein geschreibenes //l//). Wie ein Leser anmerkt, ist das Beispiel in der abgedruckten Form nicht besonders instruktiv, da man den gleichen Effekt auch mit einer normalen ''log()''-Methoden hätte. Sinnvollerweise sollte die Closure zur Auführung des Logging von außen gesetzt werden. **Seite 98**. Letzer Absatz, zweiter Satz: Richtig muss es heißen: "Indem wir es an die ''print()''-Methode einer Instanz des ''groovy.util.NodePrinter'' übergeben...". **Seite 99**. Zweiter Absatz, letzter Satz: Richtig muss es heißen: "Sie können nicht einfach ''it.bez'' schreiben...". **Seite 99**. Tabelle 4-1: In den drei letzten Zeilen der Tabelle ist unter "Beispiel" ''art'' durch ''n'' zu ersetzen. ===== Zu Kapitel 5: Wie Groovy das JDK erweitert ===== **Seite 119**. Tabelle 5-2: In der fünften Zeile muss das letzte Beispiel-Literal ''1e2f'' lauten. Der Wert ''1e2'' bezeichnet dagegen - anders als in der darauffolgenden Tabellenzeile angegeben - einen ''BigDecimal''-Wert, und zwar unabhängig davon, ob Sie ein 'G'/'g' dranhängen oder nicht. **Seite 127**. Im Beispiel oben auf der Seite sollte die erste Zeile lauten: groovy> text = new StringBuffer("YOGAVORGIRLS") Im letzten Textabsatz sollte der Satz "Das gilt auch für Strings, die in Schrägstrichen eingeschlossen werden" so ergänzt werden: "..., sofern es wie der Beginn eines GString-Platzhalters aussieht." **Seite 144**. Im Beispiel ganz unten muss es ''"Beispiel.txt"'' statt ''"Pangramm.txt"'' heißen. **Seite 169**. Der ''body''-Abschnitt im Beispiel oben auf der Seite sollte korrekt so aussehen: body { h1 "Die Hello-World-Seite" p "Die aktuelle Zeit ist: ${new Date()}" } Die darunter wiedergegebene HTML-Version ändert sich dann sinngemäß. Außerdem muss in dem Satz, der dem ersten Beispiel folgt, "Reader" durch "Writer" ersetzt werden. ===== Zu Kapitel 7: Dynamisches Programmieren ===== **Seite 185**. Das Beispiel oben auf der Seite soll zeigen, wie eine in einer Kategorienklasse definierte Methode eine klassenspezifische Methode überschreibt. Es funktioniert nicht mehr in dieser Form; auch wenn die ''DumpKategorie'' aktiv ist, wird nun in jedem Fall die Methode ''dump()'' von ''AndereKlasse'' aufgerufen. In der Groovy-Version 1.5 haben offenbar spezifische Methoden auch Vorrang vor Methoden, die in Kategorienklassen definiert sind. Damit entfällt die mögliche Gefahrenquelle, auf die in der Warnung im unteren Teil derselben Seite hingewiesen wird. **Seite 197**. Im ersten Beispiel oben fehlt ein ''$''-Zeichen in der zweiten Zeile. Es muss also zweimal lauten: ''${resultSet...}''. Das zweite Beispiel sollte komplett so lauten: kapsel = new ResultSetWrapper(resultSet) while (resultSet.next()) { println "$kapsel.vorname $kapsel.zuname" } **Seite 210**. Listing //Beispiel 7-4//:\\ Die erste Zeile muss jetzt folgendermaßen lauten: emc = new ExpandoMetaClass(String,true) Ohne den zweiten, auf ''true'' gesetzten Parameter wird die Metaklasse nicht registriert und bleibt damit wirkungslos. **Seite 210/211**. Der Satz "Insofern ist die ''ExpandoMetaClass'' etwas weniger gefährlich als die Kategorienklassen,..." gilt nicht mehr, wie oben zu Seite 185 erläutert. ===== Zu Kapitel 8: Groovy und Java integrieren ===== **Seite 218**. In der Testklasse ganz unten auf der Seite lautet die Zeile 6 korrekt so: Map properties = dyn.invoke(Map.class,"getProperties"); Alternativ kann man auch das erste Argument mit der Klasse weglassen, dann liefert die Methode aber eine ''Object''-Instanz, die entsprechend gecastet werden muss. **Seite 219**. Im Testskript ganz oben auf der Seite lautet die Zeile 5 korrekt so: String textVerkehrt = dynText.invoke(String.class,"reverse") In der Erweiterung der ''DynamicObject''-Klasse darunter sollte die Typisierung an dieser Stelle entfallen. Die ''iterator()''-Methode sieht dann so aus: public Iterator iterator() { return invoke(Iterator.class,"iterator") } Der letzte Zeile des Beispiels für den Aufruf der Methode lautet dann so: for (Object c : new DynamicObject(s)) { . . . } **Seite 229**. Abschnitt //Privilegierte Aktionen//: Im Beispiel oben soll der Name der Methode ''getUserName()'' lauten. ===== Zu Kapitel 9: Groovy im Entwicklungsprozess ===== **Seite 237**. Beispiel 9-1: Hier sind in zwei ''''-Tags die ''depends''-Attribute verwechselt worden. Statt ... muss es richtig heißen: ... **Seite 239**. Beispiel 9-2: In der letzten Zeile der Methode ''buildall()'' sind die Kommentarzeichen zu entfernen. Und die letzte Zeile der Methode ''runjava()'' sollte ''%%"GroovyKlasse"%%'' durch ''MAINCLASS'' ersetzt werden. In der Methode ''dist()'' schließlich wird nicht ''build()'', sondern ''buildall()'' aufgerufen. ---- //Vielen Dank an alle Leser, die durch ihre Aufmerksamkeit helfen, Fehler, Lücken und Unklarheiten im Buch zu beseitigen.//