Tauchen Sie ein in die faszinierende Welt der Java Beans, einem Eckpfeiler der komponentenbasierten Softwareentwicklung, und entdecken Sie, wie diese wiederverwendbaren Bausteine Ihre Programmierprojekte revolutionieren können. Dieses Buch führt Sie Schritt für Schritt durch die Konzepte und Techniken, die für die Erstellung und Nutzung von Java Beans unerlässlich sind. Angefangen bei den Grundlagen, wie Event Handling und Properties (einschließlich Indexed, Bound und Constrained Properties), erkunden Sie die fortgeschrittenen Aspekte der Introspection, Customization und Persistence. Verstehen Sie, wie Sie Eigenschaften manipulieren, Ereignisse behandeln und Ihre Beans für visuelle Entwicklungsumgebungen anpassen können. Erfahren Sie, wie die Serialization und Externalization Mechanismen genutzt werden, um den Zustand Ihrer Komponenten über Laufzeiten hinweg zu bewahren und Versionsprobleme elegant zu lösen. Ein besonderes Augenmerk liegt auf dem Packaging, das Ihnen zeigt, wie Sie Ihre Beans in JAR-Dateien verpacken und mit Manifest-Dateien für eine reibungslose Verteilung und Wiederverwendung vorbereiten. Zahlreiche Beispiele und praxisnahe Anleitungen, inklusive der Nutzung des Beans Development Kit (BDK), ermöglichen es Ihnen, das Gelernte direkt anzuwenden und eigene, komplexe Anwendungen zu erstellen. Ob Sie nun ein erfahrener Java-Entwickler sind oder gerade erst mit der Programmierung beginnen, dieses Buch bietet Ihnen das fundamentale Wissen und die praktischen Fähigkeiten, um das volle Potenzial der Java Beans Architektur auszuschöpfen und Ihre Softwareentwicklung auf ein neues Level zu heben. Lassen Sie sich von den Möglichkeiten inspirieren, die Ihnen die visuelle Programmierung mit Komponenten bietet, und entdecken Sie, wie Sie durch Standardisierung und Wiederverwendbarkeit Zeit sparen, die Wartbarkeit Ihrer Software verbessern und innovative Lösungen entwickeln können. Die Reise durch die Welt der Java Beans beginnt hier – werden Sie zum Architekten Ihrer eigenen Softwareträume und erschaffen Sie Anwendungen, die nicht nur funktionieren, sondern begeistern. Entdecken Sie die Effizienz und Flexibilität, die Java Beans in Ihre Entwicklungsprozesse bringen, und meistern Sie die Herausforderungen der modernen Softwareentwicklung mit Bravour. Werden Sie Teil einer Community von Entwicklern, die auf die Leistungsfähigkeit und Eleganz der Java Beans setzen, und gestalten Sie die Zukunft der Softwareentwicklung aktiv mit.
Inhaltsverzeichnis
1 Einleitung
2 Java Beans
3 Was macht Java Beans aus?
3.1 Eventhandling
3.2 Properties
3.2.1 Zugriff auf Eigenschaften
3.2.2 Indexed properties
3.2.3 Bound properties
3.2.4 Constrained properties
3.3 Introspection
3.3.1 Reflecion
3.3.2 Beanlnfo Schnittstelle
3.4 Customization
3.4.1 Property Editor
3.4.2 Customizer
3.5 Persistence
3.5.1 Serialization
3.5.2 Versionsproblematik und Kompatibilítaet
3.5.3 Externalization
3.5.4 Instanzierung von Serialisierten Beans
3.6 Packaging
3.6.1 Das Manifest
3.6.2 Erzeugen eines JAR Archives
A Appendix
A.l Beans Development Kit
A.2 Programmbeispiele
A.2.1 Gebundene Eigenschaften:
A.2.2 Eingeschraenkte Eigenschaften: Thermometer.java,
Constrainer.java, Terra.java
A.2.3 Serialisierung
A.2.4 Eigenschaftseditoren
1 Einleitung
Dieses Papier ist Grundlage fuer eine Praesentation im Zuge eines Seminars bei Herrn Prof. Schmidt an der Fachhochschule Wedel[1]. Die Aufgabe besteht darin eine Einfuehrung in Java-Beans zu geben und es mit Hilfe von Beispielen zu erlaeutern. Bei Fragen oder Anregungen wenden sie sich gerne an mich. Wenn sie dieses Dokument in einem anderen Format benoetigen - mail genuegt.
2 Java Beans
Das JavaBeans Application Programming Interface (API) ermoeglicht es Komponenten Software in Java zu implementieren. Komponenten sind selbstenthaltene, wiederverwendbare Softwareeinheiten die visuell als Komponenten zusammengesetzt werden koennen. So koennen dann neue Komponenten, Applets, Programme oder auch Servlets in visuellen Programmierwerkzeugen enstehen. JavaBean Komponenten werden kurz als Beans bezeichnet.
Beans bzw. Kompoenenten im weiteren Sinne bieten ihre Funktionalitaet, z.B. Methoden und Ereignisse, Programmierwerkzeugen (Builder) fuer die visuelle manipulation an. Die Funktionalitaet eines Beans wird anhand von bestimmten Entwurfsmustern (patterns) erkannt die auf Namenskonventionen beruhen. Jeder Programmiererwerkzeug ist damit in der Lage jene Muster zu erkennen und kann das Bean dann mit der kompletten oeffentlichen Funkio- nalitaet fuer die visuelle Bearbeitung dem Entwickler zur Verfuegung stellen. So ein Builder kann das Bean dann in seine Palette bzw. in die Toolbox aufnehmen. Das heisst jedoch nicht, das jedes Bean eine visuelle Repraesentation haben muss. Anschliesend steht das Bean dann dem Programmierer als Komponente zur Verfuegung. Der Vorteil liegt darin, dass ueber die Standardisierung der Schnittstellen, jedes beliebige JavaBeans-Werkzeug mit einem Bean umgehen kann, und ein Entwickler wiederum dieses Bean in seine Softwareprodukte einsetzen kann, ohne im Idealfall eine Zeile Code zu schreiben. Das Bedeutet vor allem hohe Entwicklungsgeschwindigkeit, hohe Wiederverwendbarkeit, einfachere Wartbarkeit der erzeugten Software.
Beans sind einfach zu erstellen und somit klein - sogenannte: lightweight Komponenten, dass heisst es ist nicht noetig diverse vererbte Ladungen “herumzuschleppen” (Engländer 1997, p6). Das bedeutet ein Bean muss nicht alle nur erdenklichen Funktionen erstmal implementieren um zu einem Bean zu werden. Ein Bean ist somit Grundsaetzlich einfach und laesst sich dann hinreichend komplex gestalten, anders als bei anderen Modellen in denen Grundsaetzlich eine gewissse Komplexitaet implementiert werden muss, um ueberhaupt eine Komponente darzustellen.
3 Was macht Java Beans aus?
In diesem Kapitel wird auf die einzelnen Konzepte von Java Beans eingegangen. Grundsaetzlich soll hier noch angemerkt sein ,dass Beans nur reines Java nutzen und keine neuen Mechanismen gebraucht werden, um Beans zu registrieren oder aehnliches. Jenes f'uert dazu das Beans alle Vorteile und Nachteile von Java unterliegen, d.h. z.B. Portabilitaet, was fuer wiederverwendbare Software sicher eine Entscheidene Rolle spielen sollte, ist mit Java als Sprache implizit vorhanden, das gleiche gilt auch fuer alle anderen Konzepte von Java, wie z.B. Sicherheit und Robustheit.
Im folgenden werden nun Grundlegende Prinzipien von Beans weiter beleuchtet. Das sind im einzelnen: Properties, Introspection, Customization und Persistence, abschliessend geht es dann um das Packaging welches das Bean in eine Form bring welches sich zur Weitergabe eignet. Ein Java Konzept sei an dieser Stelle noch eingefuegt: die Ereignisbehandlung. Damit Instanzen miteinander kommunizieren koennen, wird das Event-Modell von Java eingesetzt. An dieser Stelle wird nur kurz und grob auf das Event modeli eingegangen. Grundsaetzlich ist zu sagen, dass Beans starken Gebrauch von dem Konzept machen, was primaer daran liegt, das es sich im visuelle Komponenten handelt, die im Allgemeinen mit Events gekoppelt werden.
3.1 Eventhandling
Ein Ereignis (Event) zeichnet sich dadurch aus, dass es auftret en kann aber nicht muss. Events werden von der Klasse java.util.EventObject abgeleitet. Dieses Ereignis Instanzen enthalten dann alle fuer das Event wichtige Informationen, wie z.B. im Falle eines Mausevents, die alktuelle Maus Koordinaten. Moechte ein Bean oder jeden andere Objekt von einen Event kenntnis erlangen muss es sich bei der Eventquelle mit einen sogenannten Listener registrieren. Die Quelle pflegt also einen Zuhoererstamm. Tritt nun ein bestimmtes Event ein wird das Objekt alle entsprechenden Zuhoerer davon mit auf'ruf einer Methode in Kenntnissetzen. Das genau diese Methoden jedoch von den Zuhoerern innerhalb des Listener zur Verfuegung steht, ist es dem Zuhoerer moeglich individuell auf das Event zu reagieren und es ggf. auch ignorieren.
3.2 Properties
Eigenschaften (properties) sind im weiteren Sinne benannte Attribute oder Charakteristika von modellierten Realobjekten. Sie definieren den Zustand oder das Verhalten eines Objektes oder hier Beans. Eigenschaften werden über ihren Namen referenziert und können von einem beliebigen Datentyp sein (z.B. int, class, interface). Im normalfall gehören die Eigenschaften zu dem Persistenten Teil eines Objektes (siehe 3.5). Eigenschaften können im Bean Konzept mit Hilfe von visuellen Editoren manipuliert werden.
3.2.1 Zugriff auf Eigenschaften
Eigenschaften werden mit Hilfe von Zugriffniethoden gelesen und geschrieben. Prinzipiell sind nur Lesen, nur Schreiben und Lesen/Schreiben Eigenschaften denkbar. Die Methoden, die das Lesen bzw. Schreiben realisieren sollten einem Standart design für Eigenschaften folgen. Sie können demnach auch zu prüfende Ausnahmen (checked exceptions) auslösen. Standart Signaturen für Zugriffsniethoden sehen wie folgt aus.
public void set<PropertyName>(<PropertyType> value); public <PropertyType> get<PropertyName>();
Für nur Lesen oder nur Schreiben würde man demnach einfach die entsprechende Methode weglassen bzw. sie nicht veröffentlichen. Im Sonderf'all von Boolschen Eigenschaften ist die folgende Verkürzung denkbar.
public boolean is<PropertyName>();
3.2.2 Indexed properties
Bisher wurde mit einer Eigenschaft immer genau ein Wert abgehandelt. Nun ist es jedoch oft wünschenswert mehrere Werte zusammen behandeln zu können ohne diverse Namen vergeben zu müssen. Die indizierten Eigenschaften (indexed properties) ermöglichen genau dies. Über einen Namen angesprochene Eigenschaften werden so, ähnlich wie bei Arrays, indiziert angesprochen. Um nun sowohl auf einzelne Werte als auch auf die gesamte geordnete Sammlung zugreifen zu können werden die folgenden Methoden benötigt:
public void set<PropertyName>(<PropertyType>[] value);
public <PropertyType> [] get<PropertyName>();
public void set<PropertyName>(int index, <PropertyType> value);
public <PropertyType> get<PropertyName>(int index);
An dieser Stelle macht es häufig Sinn eine throws Klausel für den indizierten Zugriff zu definieren um ggf. eine java.lang.ArraylndexOutOfBoundsException Ausnahme zu erzeugen.
3.2.3 Bound properties
Gebundene Eigenschaften (bound properties) sind Eigenschaften die eine Art Benachrichtigungsdienst für etwaige Änderungen der Eigenschaft implementieren. Es ist somit möglich andere Komponenten bzw. Objekte bei Änderung eines Wertes zu benachrichtigen. Die “interessierten” Komponenten müssen sich zu diesem Zweck registrieren. Dazu bedient man sich dem Listener Konzept von Java (siehe 3.1). Das Bean, welches gebundene Eigenschaften zur Verfügung stellt, muß somit Methoden für die Registrierung zur Verfügung stellen.
Zu diesem Zweck sind einige Schnittstellen und Implementierungen zusaetzlich im Bean Konzept aufgenommen worden und sind im Einzelnen:
public void addPropertyChangeListener(PropertyChangeListener p);
public void removePropertyChangeListener(PropertyChangeListener p);
Die Methode propertyChangeO muss dann vom java, beans. PropertyChangeListener implementiert werden, welche dann mit Hilfe eines java.beans.PropertyChangeEvent das Event bearbeiten kann. Genau diese Funktionalitaet ist in der Klasse java.beans.PropertyChangeSupport abgebildet und vereinfacht die Umsetzung endweder durch Beerbung der Klasse oder durch eine Vlemb er vari able die relevanten Signaturen sind die folgenden:
public synchronized void addPropertyChangeListener (
PropertyChangeListener listener); public synchronized void removePropertyChangeListener(
PropertyChangeListener listener); public void firePropertyChange(PropertyChangeEvent evt);
Siehe A.2.1 fuer ein Beispiel zu den gebundene Eigenschaften.
3.2.4 Constrained properties
Eigenschaften, die es einem externen Programniteil ermoeglichen, eine Aende- rung abzulehnen, heissen eingeschraenkte Eigenschaften (constrained properties). D.h. nicht nur das Bean, welches die Eigenschaft zur Verfuegung stellt, kann den neuen Wert auf Gueltigkeit testen (siehe A.2.2), sondern es ist auch moeglich registrierte “Zuhoerer” vor der Aenderung nach “Einwaenden” zu befragen. Dies wird mir Hilfe eines sogenannten Vetos abgebildet. Die Signatur von nicht eingeschraenkten Eigenschaften wird wie folgt, um die Moeglichkeit einer Veto-Ausnahme erweitert:
public <PropertyType> get<PropertyName>(); public void set<PropertyName>(<PropertyType> value) throws java.beans.PropertyVetoException;
Objekte die an dieser Gueltigkeitspruefung mitwirken wollen, muessen die java.beans.VetoableChangeListener Schnittstelle implementieren. Diese Schnittstelle enthaelt eine Methode vetoableChangeO die ebenfalls ein java.beans.PropertyChangeEvent (wie bei gebundenen Eigenschaften) ueber- geben bekommt und ggf. eine java.beans.PropertyVetoExeption ausloest. Beans die eingeschraenkte Eigenschaften anbieten muessen demnach auch die Registrierungsniet ho den zur Verfuegung stellen:
public void addVetoableChangeListener(VetoableChangeListener p); public void removeVetoableChangeListener(VetoableChangeListener p);
Die Ereignisquelle muss die Ausnahme bearbeiten. Auch fuer diese Fun- tionalitaet wird eine Klasse im java.beans Packet zur Verfuegung gestellt VetoableChangeSupport. Siehe A.2.2 fuer ein Beispiel zu eingeschraenkten Eigenschaften.
3.3 Introspection
Komponenten die in visuellen Entwicklungsumgebungen verwandt werden sollen, muessen Informationen ueber ihre Funktionalitaet zur Verfuegung stellen. Beans muessen also ihre Eigenschaften, Methoden und Events veroeffentlichen.
Auf diese Weise wird es dann dem User bzw. der Entwicklungsumgebung (IDE) moeglidi das Verhalten, sowie die Erscheinung der Komponente zu beeinflussen. Eine IDE kann z.B. die BeanBox (siehe A.l) sein jedoch auch ein konmierzie- les Produkt wie z.B. JBuilder von Borland. Fuer diese Veroeflentlichung stehen nun zwei generelle Prinzipien zur Verfuegung: Reflection, Beanlnf'o-Klassen oder eine Kombination der beiden.
3.3.1 Reflecion
Haelt der Entwickler sich an die vorgesehenen Entwurfsmuster in der Namensgebung ist es mit Hilfe der Reflectionsmechanismusses von Java (package java.lang.reflect) moeglich Informationen ueber die Komponente zu ermitteln. Nun mag der Fall jedoch eintreten, dass ein Entwickler gewollt von der Implementierung nach Namenskonvention absehen moechte oder die Komponente ist zu Komplex um sie mit Hilfe von Reflektion zu “erkunden”. In diesem Fall muss die Beanlnf'o Schnittstelle zum Einsatz kommen.
3.3.2 Beanlnfo Schnittstelle
Durch implement er ung der Beanlnfo Schnittstelle (java.beans.Beanlnfo) wird explizit Information zum Bean zur Verfuegung gestellt. Jedes Leistungsmerkmal (feature) wird mit einem FeatureDecriptor beschrieben. Eine Klasse welche die Schnittstelle implementiert muss sich an die Namenskonvention: <zu beschreibenes Bean>BeanInfo z.B. fuer das Bean: meinBean wuerde die Beanlnf'o-Klasse dann: meinBeanBeanlnfo heissen. Ein Nachteil, der sich unmittelbat aus dieser Trennung in zwei Klassen (Bean und Beanlnfo) ergibt, ist die Problematische Wartung von zwei Klassen, die logisch jedoch zusammenge- hoeren. Darueberhinaus besteht an dieser Stelle keine andere Bindung der beiden Klassen, als die Namenskonvention. In der Beanlnfo Schnittstelle sind acht Methoden definiert, die in einer Helferklasse (java.beans.SimpleBeanlnfo) bereits implementiert sind, um dem Entwickler die Arbeit ein wenig zu vereinfachen. In dier Implementierung geben alle Methoden null Referenzen zurueck, was in einer Anwendung die Reflektion zum Einsatz bringen wuerde.
3.3.2.1 java.beans.FeatureDescriptor ist eine Klasse die Ob
jekte beschreibt die von den Methoden getBeanDescriptorQ, getPropertyDescriptorQ, getMethodDescriptor() und
getEventSetDescriptor zurueckgeliefert werden und in der Basisinf'or- mationen wie Name der Klasse, Displayname und Expertenmodi beschrieben sind. Im folgenden werden die einzelnen Deskriptoren beschrieben.
3.3.2.2 java.beans.BeanDescriptor wird von getBeanDescriptor () geliefert und beschreibt das Bean generell wie z.B. Displaynamen und stellt ggf die Verbindung mit einem Customizer (siehe 3.4.2) her.
3.3.2.3 java.beans.PropertyDescriptor wird von
getPropertyDescriptorQ geliefert und beschreibt oeffentliehe Eigenschaften des Beans, wie den Namen der Eigenschaften, deren get- und set-Methoden und die zugrundeliegenden Klassen sowie den etwaigen Eigenschaften Editor.
3.3.2.4 java.beans.MethodDescriptor wird von
getMethodDescriptorO geliefert und beschreibt oeffentliche Methoden des Beans. Um die Parameter uebergeben zu koennen nimmt man ein java.beans.ParameterDescriptor zur Hilfe bzw ein Array von Parametern.
3.3.2.5 java.beans.EventDescriptor wird von getEventDescriptor()
geliefert und beschreibt Ereignisse die von dem Bean ausgeloest werden koennen. Auch hier nicht man sich ein Array zur Hilfe um mehrere Ereigniss abbilden zukoennen. In der Klasse werden dann Quellklasse, Event name, Listenertype und Listenermethodenname festgelegt.
Mit Hilfe der Methode java, awt. Image getIcon(int iconKind) kann das dem Bean zugewiesene Icon abgefragt werden, welches dann von einer IDE verwendet werden kann.
3.3.2.6 getAdditionaIBeanInfo() liefert relevante Beanlnfo Objekte die zur Beschreibung eines Beans benoetigt werden, dies ist dann der Fall, wenn eine Klassenhierachie von Beans entstanden ist und die dazugehoerigen Beanlnfo Klassen jeweils nur einen Teil des Beans beschreiben.
3.3.2.7 Die java.beans.Introspector Klasse kann Beanlnfo Objekte zu bestimmten Klassen zur Verfuegung stellen (getBeanlnfoCclass beanclass)), was benoetigt wird, da grundsaetlich keine Beanlnfo Klasse etwas von der Existenz der anderen weiss.
3.3.2.8 Design- und Laufzeit kann fuer ein Bean unterschieden werden, d.h. das Bean verhaelt sich unterschiedlich in dem jeweiligen Mode. Die IDE kann die setDesignTimeO Methoden auf einer java.beans.Beans Klasse auf- ruf'en um den Mode umzuschalten. Z.Z. kann ein Bean jedoch nicht auf den Wechsel reagieren, da bisher keine EventListener registrier werden koennen.
3.4 Customization
Eine der wichtigsten Punkte in der visuellen Programmierung mit Komponenten ist die Moeglichkeit Aenderungen von Eigenschaften einfach zu gestalten. Dazu werden im Allgemeinen sogenannte Eigenschaf'tsblaetter (property sheets) verwandt. Diese Benutzerschnittstelle werden mit Hilfe von Eigenschaftseditoren (property editor) implementiert. Oftmals werden im ersten Anlauf Standarteditoren eingesetzt, es kann jedoch fuer komplexere Beans Sinnvoll sein eigene zu schreiben.
3.4.1 Property Editor
Ein Eigenschafts Editor ist eine Klasse, die zum manipulieren von einer speziellen Eigenschaft zur Verfuegung gestellt wird. Alle Eigenschafts Editoren muessen die java.beans.PropertyEditor Schnittstelle implementieren. Diese Schnittstelle definiert grundlegende Funktionen wie z.B. den Zugriff auf die Eigenschaft unter Einsatz einer Textrepraesentation. Die Verbindung zwischen Editor und Eigenschaft wird per Beanlnf'o hergestellt (siehe 3.3.2.3). Man kann dann mit der Methode PropertyDescriptor .setPropertyEditorClass (Class propertyEditorClass) die Klasse festlegen. Siehe A.2.4 fuer ein Beispiel eines einfachen Editor fuer eine Boolsche Eigenschaft.
3.4.2 Customizer
Ein customizer (Anpassungselement) ist eine Schnittstelle um ein ganzes Bean und nicht nur eine Eigenschaft fuer den Benutzer anpassbar zu machen. Customizer sind nicht auf die oeffentlichen Eigenschaften des Beans beschraenkt, sondern auch andere Parameter eines Beans koennen auf dieser Weise konfigurieren. Customizre sollte zum Einsatz kommen, wenn Beans sehr komplex und schwer ueberschaubar werden. Ein Customizer hat grundsaetlich alle moeglichkeit en einer GUI (Graphical User Interface) und kann auch als Dialog implementiert werden und somit wizard fungieren. Wer Customizer einsetzen will muss in jeden Fall auch eine Beanslnf'o Klasse implementieren, da die Verbindung zwischen Customizer und Bean aehnlich wie bei den Eigenschaftseditoren, in der Beanlnfo Klasse hergestellt werden (siehe 3.3.2.2). Alle Customizer muessen die java.beans .Customizer Schnittstelle implementieren, die primaer Methoden fuer die Registrierung von Zuhoerern definiert und eine Methode namens setObject(Object bean) ohne Rueckgabewert zur Verfuegung stellt. Letztere spezifiziert das zugehoerige Bean, welches mit dem Customizer angepasst werden soll. Darueberhinaus muss der Customizer java.awt.Component implementieren und einen Konstruktor ohne Parameter haben. Nun kann man sich leicht vorstellen, dass dieser Customizer alle nur erdenklichen Aktionen auf dem Bean durchfuehren kann und auch solche Parameter aendern, die nicht bestandteil des Vero effent liehen Teils des Beans sind, da der Customizer ueber eine Referenz auf das Bean verfliegt.
3.5 Persistence
Die meisten Komponenten pflegen ueber die Programmlogik hinaus Informationen, die Erscheinung und Verhalten der Komponente beschreiben. Einige dieser Informationen befinden sich in den Objekt Eigenschaften (siehe 3.2) wie z.B. Schriftart, oder Farbe der Komponente. Ueber die veroeffentlichen Eigenschaften hinweg koennen dies auch interne Eigenschaften sein. Wenn Eigenschaften das Erscheinungsbild bzw. das Verhalten beeinflussen und auch wahrend des Programmlaufes auch veraendert werden koennen, muss es eine Moeglichkeit geben, diese Informationen ueber die Laufzeit hinweg zu erhalten - sprich es persistent zu machen.
3.5.1 Serialization
Die Java Beans Architektur bedient sich dazu des Java Objekt Serialisierungs- mechanismusses. Um in Java Klassen mit diesem Mechanismusses zu behandeln, muss die Schnittstelle j ava. io. Serialization implementiert werden. Die Schnittstelle ist lediglich ein Marker und enthaelt keiner Methoden. Standart- maessig werden alle “non-static” und “non-transient” Elemente der Komponente serialisiert. Moechte man auch diese Elemente sichern muss der Programmierer es in jeden Fall selbst umsetzen. Im Abschnitt A.2.3 befindet sich ein kleines Beispiel.
3.5.2 Versionsproblematik und Kompatibilitaet
Wenn Serialisierung zur Anwendung kommt, entsteht unmittelbar die Problematik der Version einer Klasse, welche Grundlage fuer ein serialisiertes Objekt war, welches nun deserialisiert werden soll. Solange keine neuen Informationen zu Grunde gelegt werden und nur Methoden veraendert oder hinzugefuegt werden wird dies nicht zu einem Problem fuehren. Die Versionkontrolle wird jedoch in jedem Falle bei Veraenderter Klassendefinition Inkompatibilít act annehmen und bei dem Versuch des deserialisirens eine java.io.InvalidClassException ausloesen. Wenn man bereit ist die Inkompatiblitaeten selber zu behandeln oder es bewusst machen moechte, laesst sich dies von Hand innerhalb der Methode readObjectO umsetzen. Kompatible Änderungen, wie z.B. Hinzu- f'uegen einer Methoden wuerde wie oben beschrieben eine Exception ausloesen. Um die Java Virtual Machine (JVM) nun zu ueberreden, dass die Aende- rung gewollt ist, muss man ein Stream Unique Identifier (SUID) zum Einsatz kommen, der die erste kompatible Klasse kennzeichnet. Mit Hilfe des Programmes seri alver (Teil des JDKs) lassen sich solche SUID erzeugen, welche dann mit Hilfe einer Konstante (z.b. static final long serialVersionUID = 8984554447612061263L;)in den kompatiblen Quellcode eingesetzt werden. Somit wird die JVM keine Exception mehr ausloesen.
3.5.3 Externalization
Objekte, die die Schnittstelle java.io.Externalization implementieren koennen ebenfalls persistent gespeichert und wieder herhgestellt werden. Waehrend des Serialisationsprozess wird vorerst auf die Schnittstelle java. io.Serializable gepruef't und wenn nicht vorhanden auf die Schnittstelle java, io .Externalizable. Klassen welche diese Schnittstelle implementieren muessen sich anders wie bei serializable komplett um die abarbeitung der Speicherung kuemmern und ggf. auch selber die Klassenhierachie abarbeiten. Beim Serialisieren wird die Methode writeExternalQ aufgerufen und analog beim lesen die Methode readExternalQ. Wichtig an dieser Stelle ist, dass es keine default Routinen fuer diese Vorgaenge gibt.
3.5.4 Instanzierung von Serialisierten Beans
Um nun serialisierte Beans zu instanzieren wird die statische Methode instantiate0 der Klasse java.beans.Beans benutzt. Diese Methode be kommt zwei Parameter: ein Klassenlader (wird im Regelfall auf null ge- setzt)und einen String welcher das Beans spezifiziert. Findet die Methode eine Datei die den gleichen Namen wie das Bean, mit der Endung .ser, hat wird es geladen - wird keine Datei gefunden wird ein neues Objekt erstellt mit Hilfe des Standart Konstruktors.
3.6 Packaging
Java Beans werden gepackt und verteilt in JAR Files. Diese Technik macht es Moeglich alle Dateien, die zu einer Bean gehören, wie z.B. die Klassen-Dateien, serialisierte Objekte, Bilder, Help-Files und andere Resource-Dateien in einer Datei auszuliefern. Ein JAR File ist ein Archiv im ZIP-Format, welches optional eine sogenannte Manifest-Datei beinhaltet, die Beschreibungen über den Inhalt des Archivs enthält. Alle JAR Files die Beans enthalten, müssen eine solche Manifest-Datei beinhalten. In einem JAR File können eine oder mehrere Beans enthalten sein. Welche Dateien Beans sind und welche nicht werden innerhalb des der Manifestdatei beschrieben.
3.6.1 Das Manifest
Die Manifest-Datei enthält Informationen über bestimmte Teile des Archivs. Die einzelnen Sektionen werden durch Leerzeilen getrennt. Jede Sektion enthält einen oder mehrere Header in dem Format <tag>: <value>. Sektionen die Informationen über Dateien des Archivs beinhalten, haben ein <tag> Name, mit dem relativen Dateinamen als <value> Dateien die Beans darstellen, haben zusätzlich noch einen Header mit Java-Bean als <tag> und True als <value>. Eine Manifest-Datei könnte also z.B. folgenden Inhalt haben:
Name : elektrowurst/de/seminar/Wurst.dass Java-Bean: True
Header mit dem <tag> Depends-On zeigen Abhängigkeiten der Datei an. Als <value> wird eine Liste von Dateien des Archivs angegeben, zu denen Abhängigkeiten bestehen. Das können zusätzliche Klassen oder Ressourcen sein. Fehlt das Depends-On <tag>, so sind Abhängigkeiten unbekannt. Ist es hingegen vorhanden, muß es alle Abhängigkeiten anzeigen. Das <tag> ohne <value> zeigt an, daß keine Abhängigkeiten bestehen. Das folgende Manifest definiert ein Bean a.b, deren Abhängigkeiten unbekannt sind ein Bean x.y mit Abhängigkeiten zu x/a.gif, x/b.gif und der Klasse elektrowurst.de.Wurst und ein Bean SuperWurst ohne Abhängigkeiten
Name: a/b.ser Java-Bean: True
Name: x/y.class
Java-Bean: True
Depends-On: x/a.gif x/b.gif
Depends-On: elektrowurst/de/Wurst.dass
Name : SuperWurst. dass Java-Bean: True Depends-On:
Die Manifest Sektion für einen JAR Eintrag kann optional das Design-Time-Only <tag> benutzen, um zu zeigen, daß dieser Eintrag lediglich zur Design-Zeit benötigt wird. Dies könnte von Buildern dazu benutzt werden, diese Dateien in neuen Beans oder Applikationen nicht mit in das Paket zu tun. Folgendes Beispiel definiert ein Bean elektrowurst. de. Mega Wurst und sagt, dafi die dazugehörige elektrowurst.de.MegaWurstBeanlnfo.class lediglich zur Design-Zeit benötigt wird.
Name : elektrowurst/de/MegaWurst. dass Java-Bean: True
Name : elektrwurst/de/MegaWurstBeanlnfо.dass Design-Time_Only: True
Natuerlich koennen auch Dokumentationen zu den Beans in HTML in das JAR File eingefügt werden.
3.6.2 Erzeugen eines JAR Archives
Um nun ein Beans ausliefern zu koennen ist hier ein Beispiel fuer ein Bean Ultra Wurst aufgezeigt.
$ jar cfm UltraWurstBean.jar UltraWurst.mf UltraWurst.dass es sind ggf. noch mehrere Klassen hinzuzufuegen.
A Appendix
A.l Beans Development Kit
Der BeanDevelopmentKit (BDK) ist eine visuelle Entwicklungsumgebung, die das Erstellen eigener Software erleichtert. Durch die Wiederverwendung bereits geschriebener Beans und die optische Darstellung wichtiger Informationen können Anwendungen erzeugt werden, ohne programmieren zu müssen. Statt dessen ist es möglich, allein durch Drag&Drop-Operationen zu arbeiten. Um übersichtlich zu bleiben, ist der BDK in drei separate Fenster unterteilt. Beim Starten erscheint auf der linken Seite die ToolBox, auf der rechten Seite das PropertySheet und in der Mitte die eigentliche Arbeitsfläche, die BeanBox.
In der ToolBox werden fertige Beans bereit gestellt, die wir mit der Maus in die BeanBox ziehen können. Dort können wir diese Beans verändern. Für diesen Schritt tritt das PropertySheet in Aktion. Mit Hilfe der Reflexion filtert die Introspektion die Eigenschaften der Bean heraus und stellt sie im PropertySheet zur Verfügung. Dieses ist also ein Eigenschaftsblatt, das die Bean beschreibt. Umfangreiche Eigenschaftsblätter werden Customizer genannt. Erfahrene Programmierer werden an dieser Stelle sicherlich die Nähe zu Wizards erkennen. Mögliche Eigenschaften sind “Hintergrundfarbe”, “Vordergrundfarbe”, “Schrift” und “Text”, die im PropertySheet jeweils durch einen eigenen PropertyEditor angezeigt und manipuliert werden. Um eigene spezielle PropertyEditoren zu erstellen muß auf die Klasse PropertyEditorManager und das Interface PropertyEditor zurückgegriffen werden. Arbeitet man mit mehreren Beans, so wird die Bean im PropertySheet beschrieben, die in der BeanBox schraffiert umrandet ist. Zu Anfang mag es irritierend sein, daß das PropertySheet Eigenschaften anzeigt, obwohl wir doch noch gar keine Bean aus der ToolBox importiert haben. Die einfache Lösung ist, daß die BeanBox selber wieder eine Bean ist und somit ihre Eigenschaften angezeigt werden.
Die Stärke des BDK liegt aber in der Möglichkeit, mehrere Beans zu einer neuen Anwendung zusammenzufügen. Dazu importieren wir die Beans in die BeanBox und klicken eine Bean an. Über das Menü in der Kopfleiste wählen wir das Ereignis, das diese Bean aussenden soll, aus. Jetzt markieren wir die Ereignisabhörerbean und wählen im Fenster “EventTargetDialog” die Schnittstelle. Das Fenster wird automatisch durch Reflexion der öffentlichen Methoden generiert.
A.2 Programmbeispiele
A.2.1 Gebundene Eigenschaften: Temperatur.java
import java.beans.PropertyChangeSupport; public class Temperatur{
protected PropertyChangeSupport boundSupport;
// die aktuelle Temperatur protected double aktTemp = 25.0;
// Standartkonstruktor public Temperatur(){
boundSupport = new PropertyChangeSupport(this);
>
// Konstruktor
public Temperatur (double startTempH // aufrufen des Standartkonstruktors thisO ;
aktTemp=startTemp;
>
// Zugriffsmethode für Aktuelle Temperatur public double getAktuelleTemperatur(){ return aktTemp;
> protected void notifyTemperaturChange(){
//deligieren des Eventabschusses,
boundSupport.firePropertyChange("Aktuelle Temperatur",
null, new Double(aktTemp));
>
>
A.2.2 Eingeschraenkte Eigenschaften: Thermometer.java, Constrai- ner.java, Terra.java
Thermometer.java
import java.beans.*;
public dass Thermometer implements PropertyChangeListener{
// Einschraenkung der Werte protected double minTemp = 18.0; protected double maxTemp = 30.0; final static double MIN = 10; final static double MAX = 35;
// die aktuelle Temperatur protected Temperatur aktTemp;
protected VetoableChangeSupport constraintHandler;
public Thermometer(){ this(25.0);
>
public Thermometer(double temperatur){ aktTemp = new Temperatur(temperatur); constraintHandler = new VetoableChangeSupport(this);
>
// implementierung des PropertyChangeListener interfaces public void propertyChange(PropertyChangeEvent evt){
// hier muesste noch implementiert werden
>
// implementierung des VetoableChangeSupport
public void addVetoableChangeListener(VetoableChangeListener 1){
// weiterreichen an den Handler constraintHandler.addVetoableChangeListener(l);
>
public void removeVetoableChangeListener(VetoableChangeListener 1){
// weiterreichen an den Handler
constraintHandler.removeVetoableChangeListener(l);
// Zugriffsmethoden für die min und max Werte public double getMinimumTemperatur(){ return minTemp;
>
public double getMaximumTemperatur(){ return maxTemp;
>
public void setMinimumTemperatur(double value)
throws PropertyVetoException{
// intern einmal testen, ob der neue Wert // ok ist und ggf. veto ausloesen if (value>MAX || value<MIN ){
throw new PropertyVetoException("Wert liegt ausserhalb des zulaessigen Bereiches(10-35)",
new PropertyChangeEvent(this,"MinimumTemperature", new Double(minTemp), new Double(value)));
>
// ansonsten weiterreichen an Haendler (extern) constraintHandler.fireVetoableChangeC'MinimumTemperatur", new Double(minTemp), new Double(value));
// wenn keine Exception fliegt geht die Aenderung in Ordnung minTemp = value;
>
public void setMaximumTemperatur(double value) throws
PropertyVetoException{
// intern testen, ob der neue Wert ok ist und ggf. veto ausloesen if (value>MAX || value<MIN ){
throw new PropertyVetoException("Wert liegt ausserhalb des zulaessigen Bereiches(10-35)",
new PropertyChangeEvent(this,"MinimumTemperature", new Double(minTemp),
new Double(value)));
// ansonsten weiterreichen an Haendler constraintHandler.fireVetoableChangeC'MaximumTemperatur", new Double(maxTemp), new Double(value));
// wenn keine Exception fliegt geht die Aenderung in Ordnung maxTemp = value;
>
>
Constrainer.j ava import java.beans.*;
public class Constrainer implements VetoableChangeListener{
// implementieren des interface: VetoableChangeListener public void vetoableChange(PropertyChangeEvent evt)
throws PropertyVetoException{
// die Limitierung wird getestet, liegt der Wert // auch wirklich im Bereich (11 bis 33)
double value = ((Double)evt.getNewValue()).doubleValue0 ; if (value>33 I I value<ll){
throw new PropertyVetoExceptionO'VETO von Constrainer: Wert "
+value+" abgelehnt ",evt);
}else{
System.out.printin("Wert : "+value+" von Constrainer angenommen");
>
>
>
A.2.3 Serialisierung
Storage.java
import java.io.*; import java.awt.*; import java.awt.event.*;
public class Storage extends Button{ protected String dateiname; protected boolean mode; public static final boolean save = true; public static final boolean restore = false;
public Storage(){ mode = save;
dateiname = new String("Storage.tmp"); setLabel("Wurst");
addActionListener (new MyListenerQ) ;
>
class MyListener implements ActionListener{
//ueberschreiben
public void actionPerformed(ActionEvent e){ if (mode) saveO; else restore ();
>
>
// ne paar Zugriffmethoden
public String getDateinameO{return dateiname;} public void setDateiname(String sHdateiname = s;} public boolean getModeO{return mode;} public void setMode(boolean b){mode=b;}
private void save(){ try{
FileOutputStream fos = new FileOutputStream(dateiname); ObjectOutputStream s = new ObjectOutputStream(fos); s.writeObject(getLabelQ) ;
s.flush О ;
}catch (Exception eKSystem.out.println(e) ;>
private void restore О{ try{
FilelnputStream fis = new FilelnputStream(dateiname); Obj ectInputStream s = new ObjectInputStream(fis); setLabel((String)s.readObj ect());
}catch (Exception eKSystem.out.println(e) ;>
>
>
A.2.4 Eigenschaftseditoren RunningEditor.j ava
import java.beans.PropertyEditorSupport;
public class RunningEditor extends PropertyEditorSupport{ // der Aktuelle Zustand der Eigenschaft protected boolean bRunning;
// setzen des zu editierenden Objektes public void setValue(Object o){
// Ermitteln des aktuellen Wertes bRunning = ((Boolean)o).booleanValue();
>
// Zugriffsmethode fuer den aktuellen Wert public Object getValue(){
return new Boolean(bRunning);
>
// Liefert den Wert als Text public String getAsText(){ if (bRunning){ return "YES";
}else{
return "NO";
>
>
// setzen des Wertes als Text public void setAsText(String s){ if (s.equals("YES")){ bRunning = true;
}else{
bRunning = false;
>
// Aenderung kommunizieren firePropertyChangeü ;
>
Literatur
Beth, S. (2000), ‘Javabeans 101’, Java Developer Connection .
*http:/7developer .java.sun.com
Englander, R. (1997), Developing Java Beans, 1st edn, O’Reilly & Associates, Inc.
Flanagan, D. (1997), Java in a Nutshell, 2cd edn, O’Reilly & Associates, Inc.
Quinn, A. (2000), ‘The java tutorial/javabeans’.
*http://java.sun.com/docs/books/tutorial/javabeans/index.html
[...]
Häufig gestellte Fragen
Was ist das JavaBeans API?
Das JavaBeans Application Programming Interface (API) ermöglicht die Implementierung von Komponentensoftware in Java. Komponenten sind selbstenthaltene, wiederverwendbare Softwareeinheiten, die visuell zu neuen Komponenten, Applets, Programmen oder Servlets in visuellen Programmierwerkzeugen zusammengesetzt werden können. JavaBeans-Komponenten werden kurz als Beans bezeichnet.
Was macht Java Beans aus?
Java Beans nutzen reines Java und benötigen keine neuen Mechanismen zur Registrierung. Sie profitieren von den Vorteilen von Java, wie z.B. Portabilität, Sicherheit und Robustheit. Grundlegende Prinzipien von Beans sind Properties, Introspection, Customization und Persistence. Die Ereignisbehandlung ist ein wichtiges Java-Konzept für die Kommunikation zwischen Instanzen.
Was sind Properties (Eigenschaften) in Java Beans?
Eigenschaften sind benannte Attribute oder Charakteristika von modellierten Realobjekten. Sie definieren den Zustand oder das Verhalten eines Objektes (Beans). Eigenschaften können über ihren Namen referenziert werden und von einem beliebigen Datentyp sein. Im Allgemeinen gehören die Eigenschaften zum persistenten Teil eines Objektes.
Wie greift man auf Eigenschaften zu?
Eigenschaften werden mit Hilfe von Zugriffsmethoden gelesen und geschrieben. Es gibt Lese-, Schreib- und Lese/Schreib-Eigenschaften. Standard-Signaturen für Zugriffsmethoden sind public void set<PropertyName>(<PropertyType> value);
und public <PropertyType> get<PropertyName>();
Für Boolesche Eigenschaften kann public boolean is<PropertyName>();
verwendet werden.
Was sind Indexed Properties (indizierte Eigenschaften)?
Indizierte Eigenschaften ermöglichen die Behandlung mehrerer Werte unter einem Namen, ähnlich wie bei Arrays. Zugriff auf einzelne Werte und die gesamte geordnete Sammlung erfolgt über Methoden wie public void set<PropertyName>(<PropertyType>[] value);
, public <PropertyType> [] get<PropertyName>();
, public void set<PropertyName>(int index, <PropertyType> value);
und public <PropertyType> get<PropertyName>(int index);
.
Was sind Bound Properties (gebundene Eigenschaften)?
Gebundene Eigenschaften implementieren eine Art Benachrichtigungsdienst für Änderungen der Eigenschaft. Andere Komponenten oder Objekte können bei Änderung eines Wertes benachrichtigt werden. "Interessierte" Komponenten müssen sich zu diesem Zweck registrieren. Methoden für die Registrierung sind public void addPropertyChangeListener(PropertyChangeListener p);
und public void removePropertyChangeListener(PropertyChangeListener p);
.
Was sind Constrained Properties (eingeschränkte Eigenschaften)?
Eigenschaften, die es einem externen Programmteil ermöglichen, eine Änderung abzulehnen, heißen eingeschränkte Eigenschaften. D.h. nicht nur das Bean, welches die Eigenschaft zur Verfügung stellt, kann den neuen Wert auf Gültigkeit testen, sondern es ist auch möglich registrierte "Zuhörer" vor der Änderung nach "Einwänden" zu befragen. Dies wird mit Hilfe eines sogenannten Vetos abgebildet. Objekte, die an dieser Gültigkeitsprüfung mitwirken wollen, muessen die java.beans.VetoableChangeListener
Schnittstelle implementieren.
Was ist Introspection?
Komponenten, die in visuellen Entwicklungsumgebungen verwandt werden sollen, müssen Informationen über ihre Funktionalität zur Verfügung stellen. Beans müssen also ihre Eigenschaften, Methoden und Events veröffentlichen. Dies kann über Reflection oder die Beanlnfo Schnittstelle erfolgen.
Was ist die Beanlnfo Schnittstelle?
Durch Implementierung der Beanlnfo Schnittstelle (java.beans.Beanlnfo
) wird explizit Information zum Bean zur Verfügung gestellt. Jedes Leistungsmerkmal (feature) wird mit einem FeatureDescriptor beschrieben. Eine Klasse, welche die Schnittstelle implementiert muss sich an die Namenskonvention: <zu beschreibendes Bean>BeanInfo halten.
Was ist Customization (Anpassung)?
Ein wichtiger Punkt in der visuellen Programmierung ist die Möglichkeit, Änderungen von Eigenschaften einfach zu gestalten. Dazu werden im Allgemeinen sogenannte Eigenschaftsblätter (property sheets) verwandt. Diese Benutzerschnittstelle werden mit Hilfe von Eigenschaftseditoren (property editor) implementiert. Oftmals werden im ersten Anlauf Standarteditoren eingesetzt, es kann jedoch fuer komplexere Beans Sinnvoll sein eigene zu schreiben.
Was ist ein Property Editor (Eigenschafts Editor)?
Ein Eigenschafts Editor ist eine Klasse, die zum manipulieren von einer speziellen Eigenschaft zur Verfuegung gestellt wird. Alle Eigenschafts Editoren muessen die java.beans.PropertyEditor Schnittstelle implementieren. Die Verbindung zwischen Editor und Eigenschaft wird per Beanlnf'o hergestellt.
Was ist ein Customizer (Anpassungselement)?
Ein Customizer ist eine Schnittstelle um ein ganzes Bean und nicht nur eine Eigenschaft fuer den Benutzer anpassbar zu machen. Customizer sind nicht auf die oeffentlichen Eigenschaften des Beans beschraenkt. Wer Customizer einsetzen will muss in jeden Fall auch eine Beanslnf'o Klasse implementieren, da die Verbindung zwischen Customizer und Bean aehnlich wie bei den Eigenschaftseditoren, in der Beanlnfo Klasse hergestellt werden.
Was ist Persistence (Persistenz)?
Die meisten Komponenten pflegen Informationen, die Erscheinung und Verhalten der Komponente beschreiben. Wenn Eigenschaften das Erscheinungsbild bzw. das Verhalten beeinflussen und auch wahrend des Programmlaufes auch veraendert werden koennen, muss es eine Moeglichkeit geben, diese Informationen ueber die Laufzeit hinweg zu erhalten - sprich es persistent zu machen.
Wie wird Persistenz in Java Beans erreicht?
Die Java Beans Architektur bedient sich dazu des Java Objekt Serialisierungs- mechanismusses. Um in Java Klassen mit diesem Mechanismusses zu behandeln, muss die Schnittstelle java.io.Serialization
implementiert werden.
Was ist Externalization?
Objekte, die die Schnittstelle java.io.Externalization
implementieren koennen ebenfalls persistent gespeichert und wieder herhgestellt werden. Klassen welche diese Schnittstelle implementieren muessen sich anders wie bei serializable komplett um die abarbeitung der Speicherung kuemmern und ggf. auch selber die Klassenhierachie abarbeiten.
Was ist Packaging (Verpackung) von Java Beans?
Java Beans werden gepackt und verteilt in JAR Files. Diese Technik macht es Moeglich alle Dateien, die zu einer Bean gehören, wie z.B. die Klassen-Dateien, serialisierte Objekte, Bilder, Help-Files und andere Resource-Dateien in einer Datei auszuliefern. Alle JAR Files die Beans enthalten, müssen eine solche Manifest-Datei beinhalten. In einem JAR File können eine oder mehrere Beans enthalten sein. Welche Dateien Beans sind und welche nicht werden innerhalb des der Manifestdatei beschrieben.
Was ist die Manifest-Datei?
Die Manifest-Datei enthält Informationen über bestimmte Teile des Archivs. Jede Sektion enthält einen oder mehrere Header in dem Format <tag>: <value>. Dateien die Beans darstellen, haben zusätzlich noch einen Header mit Java-Bean
als <tag> und True
als <value>.
- Arbeit zitieren
- Axel Faltin (Autor:in), 2001, Komponenten Konzept von Java, Java-Beans, München, GRIN Verlag, https://www.hausarbeiten.de/document/98801