10. September 2014 | 4 min lesezeit

Java Enterprise: Custom Resource Loading mit Java 8

Im dritten Teil unserer kleinen Serie zu Java 8 und Enterprise beschäftigen wir uns mit dem Thema Internationalisierung und Resource Loading. Hier gibt es in Java 8 eine interessante Erweiterung, die natürlich auch in Java EE verwendet werden kann.

Die letzten beiden Teile verpasst? Hier geht es zu Teil 1 und zu Teil 2.

Der Standardmechanismus in Java zum Laden von Ressourcen ist das ResourceBundle. Dieses kümmert sich auch um die Internationalisierung. Beim Laden eines ResourceBundles wird auf Basis eines definierten Algorithmus das korrekte Bundle für Sprache und Land ermittelt und geladen.

ResourceBundle in JSF

Um ein ResourceBundle in JSF zu nutzen, muss es entweder in der faces-config.xml eingetragen werden (Listing 1) oder als lokales Bundle über das Tag f:loadBundle in die XHTML-Seite eingebunden werden. An beiden Stellen muss jeweils ein Variablenname angegeben werden, über den dann innerhalb eines Expression-Language-Ausdrucks auf dieses Bundle zugegriffen werden kann. In unserem Beispiel wäre das über msg[‚myKey‘] möglich. Innerhalb von JSF kann zusätzlich über FacesApplication.getResourceBundle programmatisch auf das Bundle zugegriffen werden.

Listing 1

Ladeprozess anpassen

Neben dem Namen (in Listing 1 ist das messages) kann ein ResourceBundle noch Locale-spezifisch ausgeprägt sein. Der Bezeichner für das Locale wird dabei durch einen Unterstrich vom Namen getrennt (z. B. messages_de). Das Locale selbst kann auch wieder aus mehreren Teilen bestehen (siehe auch hier), die auch durch Unterstriche getrennt sind (z. B. messages_de_DE_northern). Das erste Suffix steht dabei für die Sprache (de), das zweite für das Land (DE) und alle weiteren stellen beliebige Varianten dar, die der Wichtigkeit nach sortiert sein sollten.

Der Standardalgorithmus zum Ermitteln eines ResourceBundles schaut zunächst nach, ob es eine Properties-Datei mit dem konfigurierten Namen und dem aktuellen Locale im Classpath gibt. In Listing 1 und dem Locale de_DE wäre das eine Datei namens messages_de_DE.properties im Ordner com/sample. Ist diese nicht vorhanden, wird überprüft, ob es eine gleichnamige Klasse gibt, die von ResourceBundle ableitet. Das wäre im Beispiel eine Klasse Messages_de_DE.class im Package com.sample. Gibt es beides nicht, wird versucht, eine sprachspezifische Ressource zu finden (messages_DE.properties bzw. Messages_DE.class). Den letzten Versuch unternimmt der Algorithmus dann komplett ohne Suffix (messages.properties bzw. Messages.class).

Bis Java 6 war es nicht möglich, den Mechanismus des Ladens von Ressourcen anzupassen. Wollte man das tun, um zum Beispiel das Laden von Ressourcen aus der Datenbank umzusetzen, blieb einem nichts anderes übrig, als pro Ressource besagte Klasse zu erstellen (Messages_de_DE.java) und den Mechanismus dort zu implementieren. Das Unterstützen mehrerer Locales war dann recht mühsam, auch wenn man durch geschickte Ableitungshierarchien den Implementierungsaufwand minimieren konnte. Das dynamische Hinzufügen von Locales war gar nicht möglich.

Daher wurde in Java 6 die Klasse ResourceBundle.Control eingeführt. Sie kann erweitert und der Ladeprozess dadurch nahezu beliebig angepasst werden. Zusätzlich können eigene Caching-Strategien eingebaut werden. Die Umsetzung der nicht seltenen Anforderung, Ressourcen aus der Datenbank zu laden, ist so leicht möglich. Um einen solchen angepassten Ladeprozess zu verwenden, muss das neue ResourceBundle.Control einfach dem Aufruf von ResourceBundle.getBundle übergeben werden.

Leider gilt das nur für die Fälle, in denen man sich das ResourceBundle programmatisch holt. In den Fällen, in denen das Framework das Laden der Ressourcen übernimmt (wie z. B. in JSF), ist das Ganze nicht so einfach. In Java 6 wurde nämlich versäumt, in den Standardmechanismus zum Laden von Ressourcen eine Möglichkeit einzubauen, ein eigenes ResourceBundle.Control zu übergeben. Alle Frameworks, die das Laden von ResourceBundle.getBundle ohne ein Control aufrufen, lassen sich also schwer anpassen. Zu diesen Frameworks gehört auch JSF. Möchte man also über JSF auf Ressourcen zugreifen, muss man leider auf das ResourceBundle.Control verzichten und auf den oben beschriebenen Mechanismus zurückgreifen, in dem man die Klasse ResourceBundle selbst implementiert. Das ist nicht schön und führt bei mehreren zu unterstützenden Locales zu viel ähnlichem Code. Außerdem lassen sich keine Locales dynamisch hinzufügen.

Lese mehr…


Keine Kommentare

Kontakt

OPEN KNOWLEDGE GmbH

Standort Oldenburg:
Poststraße 1, 26122 Oldenburg

Standort Essen:
II. Hagen 7, 45127 Essen