Velocity: EscapeTool einrichten und verwenden

UTF8-kodierte, getrimmte Ausgaben sind ja gut und schön, aber evt. möchte man diese auch escapen 🙂 Dazu gibt es das EscapeTool. Das ist ganz cool, bietet es doch Tools für HTML, URLs, JS, … Die “Doku” ist allerdings ein wenig dürftig, deshalb kurz dazu:

Den Download findet man hier. Ich habe die velocity-tools-2.0.zip genommen; daraus benötigt man aber nur lib/velocity-tools-2.0.jar. Das kommt in den Classpath, klar.

Aktivieren und in Templates injizieren (oder wie das da heißt) tut man das so:

Und verwendet schließlich so:

Dabei ist das “!” in “$!{esc” wichtig, denn wenn $myString null ist, wird html() nicht gefunden – html() ist für String-Parameter definiert, nicht für null^^

Velocity: Vorsicht beim trimmen des Outputs

Velocity ist eine tolle Sache. Viel toller als der Internet Explorer jedenfalls. Der IE < 9 beispielsweise crasht, wenn ein Ajax-Response zu groß ist. Zugegeben: Der fragliche Response war auch wirklich groß, so 6 MB oder mehr. Er besteht aber zum Glück größtenteils aus Whitespaces, die daraus resultierten, dass zig Velocity-Templates (jedes mit zig Schleifen) zusammengemerged wurden – und Velocity erhält Whitespace. Man könnte “einfach” alle Whitespaces aus den Templates nehmen, und hätte vermutlich viel gewonnen. Allerdings könnte dann niemand mehr die Templates warten (weil lesen), und das wäre wiederrum nicht so toll.

Deshalb die Idee, den Velocity-Output zu “säubern” (zu trimmen, zu stripen, …). Gesagt getan: Eine Funktion, die die entsprechenden Chars löscht, könnte beispielsweise so aussehen:

Die Rekursion ist deshalb nötig, weil ␣␣␣␣ sonst nur zu ␣␣ statt zu ␣ werden.

Das funktionert auch ganz gut. Blöd, wenn man ein SAP hinter seiner Webseite hat, denn SAP kennt IDs, die zum Beispiel so aussehen: “01101NA50021435513400011␣␣2012081499991231␣␣␣␣␣␣␣␣␣␣000”. Die stehen bei uns in data-Attributen, und müssen so erhalten bleiben. Deshalb musste eine Lösung her, die Whitespaces filtert, aber NICHT in data-Attributen (genauer gesagt heißen die Attribute data-entry-json).

Die Velocity-Jungs empfehlen für das “Whitespace Gobbling” JTidy, aber das funktioniert nicht (out of the box); die Whitespaces in data-entry-json-Attributen bleiben erhalten.

Besser ist der HtmlCompressor, der das zwar auch nicht out of the box kann, der aber die Möglichkeit bietet, eigene Patterns zu definieren, die erhalten bleiben sollen. Laut Doku ist das für bestimmte Tags, aber man kann auch freiere Patterns angeben:

Das obige Pattern sucht nach Tags, die “data-entry-json” enthalten, und sagt dem HtmlCompressor, diese Tags zu erhalten.

Rein statische Klassen in Velocity

Eine solche Java-Klasse:

möchte man vielleicht auch in Velocity verfügbar haben. Nun funktioniert

schon mal nicht – $MyValues ist kein konkretes Objekt (und ohne eine Art Import wäre die Klasse eh nicht verfügbar). Eine Instanz möchte man aber auch nicht erzeugen:

, denn damit wäre MyValues.myString immer “Hello, you world!” (da neu initialisiert), und wer weiß, vielleicht wurde das ja mal überschrieben? Im Java-Code würde man hier ja auch nicht auf Instanzen arbeiten, sondern auf der Klasse.

Und tatsächlich kann man Velocity auch nur die Klasse übergeben, und zwar genau so, wie man es erwartet:

Im Grunde ist das nicht mal überraschend, aber ich finde das grad gut 🙂 In Velocity sieht das dann so aus:

, und das gibt immer den aktuellen Wert aus! Mit statischen Methoden funktioniert das übrigens auch – und: Ja, man könnte auch einen Singleton verwenden. Ich find’ das trotzdem gut.

Java/Velocity, XML/JSON: UTF-8 [UPDATE]

Wer Velocity auf ‘nem Tomcat laufen hat, stolpert vielleicht mal über das Problem, dass das Character Encoding falsch gesetzt ist. Sprich, dass Umlaute falsch gerendert werden.

Nun könnte man vermuten, dass das am String selbst liegt. Tut es nicht: In Java sind Strings UTF-16.

Dann könnte man den Fehler in Velocity suchen. Etwa könnte man die Templates explizit als UTF-8 öffnen:

Das hat bei mir nicht geholfen. Allerdings kann man Velocity das Default-, Input- und Output-Encoding vorgeben:

Das scheint schon mal was zu bewirken. Allerdings wird einem hier auffallen, dass die meisten (wenn nicht alle) Umlaute nicht im Template liegen, sondern dort nur reingeschrieben werden. In unserem Fall wurden zum Beispiel zum Teil Daten eines Webservice, zum Teil aber auch lokal gespeicherte XMLs verwendet. Die XMLs müssen UTF-8-kodiert gespeichert worden sein:

Und sie müssen vor allem auch UTF-8-kodiert gelesen werden:

Update

Kommen die XML-Daten (hier als ZIP) aus der Schnittstelle, müssen sie als UTF-8 in einen String konvertiert werden:

So. Last but not least müssen die Daten, die serverintern jetzt in UTF-8 vorliegen sollten, auch als solches an den Browser ausgegeben werden. Während normalerweise der Writer des Response ausreicht, um den OutputStream dieses Response zu handlen:

, muss man diesen für UTF-8 manchmal mit einem Writer mit explizit gesetztem UTF-8 ersetzen (Danke an Ralf!):

Achtung: Für JSON-Response musste ich dagegen das Encoding des Response selbst setzen:

Vermutlich ist das ein wenig kompliziert gemacht (ich meine, hey, das muss einfacher gehen!), aber so scheint es hier zu funktionieren. HTH

Update

Für Spring gilt es außerdem, dieses Setting zu beachten: