---
title: 'Dynamisch. Praktisch. Gut Mit dem BeanUtils Properties einfach beherrschen'
url: 'https://tutego.de/blog/javainsel/2013/09/dynamisch-praktisch-gut-mit-dem-beanutils-properties-einfach-beherrschen'
markdown: 'https://tutego.de/blog/javainsel/2013/09/dynamisch-praktisch-gut-mit-dem-beanutils-properties-einfach-beherrschen.md'
date: '2013-09-28'
description: 'Die Java-Beans sind ein allgegenwärtiges Gut. Zwar sind die Anforderungen minimal, aber für viele Bereiche wie grafische Oberflächen, JSPs, OR-Mappern sind sie nicht wegzudenken. Damit eine Bean zur Bean wird, muss eine Klasse öffentlich sein einen öffentlichen Standard-Konstruktur besitzen und öf…'
taxonomy:
  category:
    - 'Open Source'
    - Apache
---

# Dynamisch. Praktisch. Gut Mit dem BeanUtils Properties einfach beherrschen

![Illustration einer tropischen Insel mit Palmen und einem hohen Berg](https://tutego.de/blog/javainsel/user/themes/tutego/images/insel-cover.jpg)# Java Blog für Programmierer

[Java Blog für Programmierer](https://tutego.de/blog/javainsel/)

## Dynamisch. Praktisch. Gut Mit dem BeanUtils Properties einfach beherrschen

28.09.2013 · [Christian Ullenboom](https://tutego.de/blog/javainsel/author/admin/)

Die Java-Beans sind ein allgegenwärtiges Gut. Zwar sind die Anforderungen minimal, aber für viele Bereiche wie grafische Oberflächen, JSPs, OR-Mappern sind sie nicht wegzudenken. Damit eine Bean zur Bean wird, muss eine Klasse

- öffentlich sein
- einen öffentlichen Standard-Konstruktur besitzen und
- öffentliche Zugriffsfunktionen anbieten.

Nach dieser Vorgabe ist Folgendes eine gültige Bean:

```java
class Weihnachtsmann
{
  private String name;

  public String getName() {
    return name;
  }

  public void setName( String name ) {
    this.name = name;
  }
}
```

Die Zugriffsfunktionen kapseln die internen Eigenschaften und sind nach einem festen Muster aufgebaut. Für ein Attribut `String` name würden die beiden Methoden void `setName(String name)` und `String` `getName()` angelegt. Für boolean-Eigenschaften ist die Vorsilbe is- üblich. Wenn die Beans nicht nach dem Schema aufgebaut sind, kann eine zusätzliche BeanInfo-Beschreibung helfen.

Während auf der einen Seite die Bean als Datencontainer Einsatz findet, sind sie noch aus einen anderen Grund reizvoll: durch ihren festen Aufbau lässt sich leicht mit Reflection/Instrospection auf die Bean und ihre Eigenschaften zugreifen. Nicht umsonst beschreiben Bean grafische Komponenten, so dass ein GUI-Builder völlig automatisch die Eigenschaften auslesen kann und Manipulationen erlaubt. Ein Exemplar einer Bean lässt sich über ihren Namen einfach anlegen; mit einem bekannten `Class`-Objekt liefert `newInstance()` ein neues Exemplar.

```java
Class beanClass = Class.forName( "Weihnachtsmann" );
Object santa = beanClass.newInstance(); 
```

Für das Auslesen der Methodennamen definiert Java Introspection und für den Zugriff Reflection. Vor dem Zugriff auf die Bean-Properties sind jedoch die Präfixe get- und set- zu setzen und Datentypkonvertierungen durchzuführen.

Um den Umgang mit Bean-Eigenschaften zu vereinfachen, hat die Apache-Gruppe in ihren Commons-Paket die BeanUtils aufgenommen. Die aktuelle Version der BeanUtils ist 1.6.1 und ist beim Indianer-Server <http://jakarta.apache.org/commons/beanutils/> zuhause. BeanUtils setzt zwei weitere Pakete aus Commons voraus: `Collections` und Logging. Der prominenteste Nutzer der Bibliothek ist Struts.

### Bean-Eigenschaften lesen und setzen

Eine Bean-Property kennzeichnet ähnlich wie ein Servlet/JSP-Attribut zwei Merkmale: Einen Namen (immer ein `String`) mit einer Belegung (beliebiger Objekttyp). Um bei einer Bean eine Property zu setzen, müssen ihr Name und die neue Belegung natürlich bekannt sein, beim Lesen nur der Name. Auslesen und Setzen von Eigenschaften erlauben zwei statische Funktionen der Utility-Klasse `org.apache.commons.beanutils.PropertyUtils`: `PropertyUtils.getSimpleProperty(Object bean, String name)` und `PropertyUtils.setSimpleProperty( Object bean, String name, Object value)`. Um unserem `Weihnachtsmann` einen Namen zu geben — und diesen gleich wieder auszulesen — ist zu schreiben:

```java
PropertyUtils.setSimpleProperty( santa, "name", "Santa Clause" );
String name = (String) PropertyUtils.getSimpleProperty( santa, "name" );
```

Die Methoden sind jedoch nicht ohne ausführliche Fehlerbehandlung auszuführen; auftreten kann eine `IllegalAccessException`, `IllegalArgumentException` (eine `RuntimeException`), `InvocationTargetException` und `NoSuchMethodException`.

```java
Zu bedenken ist, dass eine Bean-Property ganz spezielle Methoden erzwingt. Das geht so weit, dass BeanUtils nur genau eine get-Methode erwartet. Gibt es neben der erforderlichen get-Methode eine weitere, so liefert BeanUtils beim Zugriff einen Fehler. Der Zugriff auf bounds einer java.awt.Component gelingt daher nicht, da neben der parameterlosen Variante von getBound() auch getBounds(Rectange) existiert — ein Aufruf ähnlich wie der Folgende funktioniert daher nicht und führt zu einer NoSuchMethodException: PropertyUtils.getSimpleProperty(new Label(), "bounds");
```

### PropertyUtils, BeanUtils und Konvertierungen

Neben der Klasse PropertyUtils, die bisher Verwendung fand, gibt es noch zusätzlich die Klasse BeanUtils. Sie erinnert von der Methodenvielfalt an PropertyUtils, doch sie führt für Datentypen mögliche Konvertierungen durch. Das Beispiel zum `Weihnachtsmann` soll erweitert werden, so dass er ein Attribute int alter besitzt. Der Versuch, das Attribut mit einem Wert vom Datentyp `String` über `PropertyUtils.setProperty()` zu setzen scheitert mit einer `IllegalArgumentException`. Ein int muss mit einem `Integer`-Objekt belegt werden. Wird jedoch anstelle der Klasse PropertyUtils die Klasse BeanUtils gesetzt, so funktioniert alles, denn BeanUtils führt die notwendigen Konvertierungen von `String` in int selbst aus.

```java
BeanUtils.setProperty( santa, "alter", "612" );
```

Ergibt sich bei der Konvertierung ein Fehler, so macht das nichts, denn dann wird die Zuweisung nicht durchgeführt. (Apropos Konvertierungen: Die Firma Lockheed, die die Raumsonde Mars Climate Orbiter in England konstruierte, nutze die englische Einheit Inch, die NASA in Amerika Zentimeter; beim Landeversuch crashte die Sonde 1999 auf den Mars.)

Die Konvertierung aus einem `String` für die unterschiedlichsten Datentypen nimmt BeanUtils automatisch vor. Im oberen Fall findet eine Konvertierung von `String` in ein `Integer` Objekt statt. Die Converter selbst sind Klassen, die die Schnittstelle `org.apache.commons.beanutils.Convert` implementieren und auf diese Weise von einem `String` in `BigDecimal`, `BigInteger`, boolean, `Boolean`, byte, Byte, char, Character, `Class`, Double, float, Float, int, `Integer`, long, Long, short, Short, `String`,

`java.util.Date`, `java.sql.Date`, `java.sql.Time`, `java.sql.Timestamp` und mehr konvertieren. Den passenden Konverter sucht `ConvertUtils.lookup()`. Falls also `BeanUtils.setProperty()` vor der Aufgabe steht, einen passenden Typ herauszufinden, so sucht es zuerst nach dem Typ (von alter wäre das int) und anschließend den passenden Konverter. Da `ConvertUtils.lookup(int.class)` den IntegerConverter liefert, darf er die Zeichenfolgen umwandeln. Diese Konvertierung ist die übliche Konvertierung mit `Integer.parseInt()`.

Falls die Standard-Konverter einen Typ nicht abdeckt, kann mit `register()` ein neuer Konverter eingehängt werden. Nicht nötig ist das für sprachabhängige Konvertierungen, denn hier bietet das Paket schon Hilfe an. So gibt es den IntegerConverter in der lokalisierten Fassung auch als IntegerLocaleConverter. Zum Nachschlagen dient aber nicht mehr ConvertUtils, sondern LocaleConvertUtils. Die Basisklassen für lokalisierte eigene Konvertiert ist LocaleConverter. Es gibt für alle normalen Konverter auch lokalisierte Konverter. Das lokalisierte Parsen scheint allerdings noch nicht so ganz ausgereift.

### Eine Liste aller Eigenschaften

Eine Belegung aller Eigenschaften liefert `BeanUtils.describe()` beziehungsweise `PropertyUtils.describe()`.

```java
Map description = BeanUtils.describe( new JButton() );
```

Der Assoziativspeicher unter dem Namen description enthält als Schlüssel alle Properties und als Werte die Belegungen der Eigenschaften.

```text
verifyInputWhenFocusTarget=true
displayedMnemonicIndex=-1
width=0
...
```

### Formular-Parameter übertragen

In JSPs erfreut eine Schreibweise den Entwickler, die alle Parameterwerte eines Requests in eine Bean überträgt. Das Tag <jsp:`setProperty`> wird dann mit dem Attribut property="\*" belegt.

```text

```

Diese Möglichkeit sieht zwar die JSP-Spezifikation vor, doch in Servlets fehlt diese Möglichkeit. Sie wird aber insbesondere für MVC-Frameworks interessant, in dem der Controller selbständig die Formulardaten in eine Bean überträgt. Das kann schnell nachimplementiert werden. Die Servlet-API bietet in ServletRequest die Funktion `getParameterNames()`, um mit einer Enumeration über die Parameter zu laufen. Für jeden der Parameter kann `setProperty()` auf einer passenden Bean aufgerufen werden.

```java
for ( Enumeration params = request.getParameterNames(); params.hasMoreElements(); ) {
  String name = (String) params.next();
  if ( name != null )
    BeanUtils.setProperty( bean, name, request.getParameterValues(name) );
}
```

`getParameterValues()` liefert ein Feld, was von der Bean auch verarbeitet werden muss. Sonst tut’s bei eindeutigen Parametern auch `getParameter()`.

### Werte einer `Map` in eine Bean kopieren

Aufgabe: Eine Ini-Datei enthält Schlüssel/Werte-Paare und alle Schlüssel sollen auf Eigenschaften einer Bean übertragen werden. Für Schlüssel soll es also entsprechende set- und get-Methoden geben. Eine einfache Aufgabe mit den passenden Klassen. Zum Laden der Paar-Datei findet Properties und die Objektfunktion `load()` Einsatz. Ein Properties-Objekt ist eine spezialisierte Hashtable — eine dumme Designentscheidung Begründung ? —, und alle Schlüssel lassen sich aufzählen. An dieser Stelle kommen wieder die BeanUtils ins Spiel. Die statische Funktion `setProperty()` sieht jeden Schlüssel als Property und überträgt den Wert auf die Bean.

Unter der Annahme, dass alle Eigenschaften in einer `Map` vorliegen, bietet BeanUtils eine feine Funktion: static void `populate(Object bean, Map properties)`. Die `Map` schreibt Schlüssel als `String` vor, die Werte sind beliebige Objekte. `populate()` iteriert über die Schlüssel von properties und initialisiert über viele `setProperty()`-Funktionen die Werte der Bean. Die Aufgabe löst sich somit in wenigen Zeilen Quellcode.

Die Funktion `populate()` ließe sich auch bei Formular-Parametern verwenden, wenn denn die Schlüssel/Werte-Paare in einer `Map` vorliegen würden. Doch das können sie so ohne weiteres nicht, denn ein Schlüssel darf durchaus mehrmals mit verschiedenen Werten vorkommen — eine `Map` kann das nicht unterstützen. Gilt, dass überladene Parameter nicht zu erwarten sind, können von Hand die Parameter in eine `Map` einsortiert werden, so dass doch wieder `populate()` nutzbar ist. Seit der Servlet 2.3 Spezifikation bietet HttpServletRequest die Methode `getParameterMap()`, was direkt eine `Map` liefert. Sie speichert die Werte jedoch immer als Felder; wenn der Schlüssel einmalig ist, dann ist das Feld nur ein Element groß.

### Indexierte Properties

Da ein `Weihnachtsmann` immer Rentiere besitzt, soll ihn eine zusätzliche Klasse Rentier für die Zugtiere bei der Arbeit unterstützen. Er soll in einem internen Feld zugtier die Tiere speichern und dafür auch zwei neue Zugriffsfunktionen definieren.

```java
class Weihnachtsmann
{
  private Rentier[] zugtier = new Rentier[8];
  public Rentier getZugtier( int index ) {
    return zugtier[index];
  }
  public void setZugtier( int index, Rentier zugtier ) {
    this.zugtier[index] = zugtier;
  }
}
```

Ist ein `Weihnachtsmann` aufgebaut und mit `setZugtier()` ganz klassisch ein Rentier zugewiesen kann im nächsten Schritt die Eigenschaft erfragt werden.

```java
Weihnachtsmann w = new Weihnachtsmann();
w.setZugtier( 0, new Rentier() );
Rentier z = (Rentier) PropertyUtils.getIndexedProperty( w, "zugtier", 0 );
```

Diese indexierten Eigenschaften lassen sich mit `getIndexedProperty()` erfragen und mit `setIndexedProperty()` setzen; die Signaturen sind `PropertyUtils.getIndexedProperty(Object bean, String name, int index)` und `PropertyUtils.setIndexedProperty(Object bean, String name, int index, Object value)`.

```java
Rentier rudolph = new Rentier();
PropertyUtils.setIndexedProperty( w, "zugtier", 1, rudolph );
```

Eine Alternative zu den Funktionen, die den Index als Parameter erwarten ist eine Schreibweise, die den Index in den Eigenschaftennamen kodiert. Die Schreibweise ist bekannt von `Arrays`: name\[index\].

```java
Rentier zt = (Rentier) PropertyUtils.getIndexedProperty( w, "zugtier[1]" )
```

### Mapped Properties

Für indexierte Properties ist es üblich, dass der Index eine positiver ganzzahliger Wert ist. Eine Erweiterung der Java-Beans gehen die BeanUtils mit den Mapped Properties, was indexierte Beans mit Schlüsseln sind — das Konzept erinnert an einen Assoziativspeicher. Genauso wie indexierte Properties mit eckigen Klammern einen Index aufnehmen, gibt es eine Abkürzung auch bei den abgebildeten Eigenschaften. Dabei wird der Schlüssel in runden Klammern hinter die Eigenschaft gesetzt. Die Signaturen sind `PropertyUtils.getMappedProperty(Object bean, String name)` mit den alternativen Parametern (`Object` bean, `String` name, `String` key), (`Object` bean, `String` name, `Object` value) und (`Object` bean, `String` name, `String` key, `Object` value).

Ein Beispiel: `System.getProperties()` liefert ein Properties mit den Systemeigenschaften. Die Objektmethode `getProperty()` liefert zu einem gegebenen Schlüssel den assoziierten Wert. BeanUtils lässt mit `getMappedProperty()` die abgebildeten Eigenschaften erfragen.

```java
Properties props = System.getProperties();
System.out.println( PropertyUtils.getMappedProperty( props, "property(user.name)" ) );
```

```java
Wo ist der Vorteil gegenüber props.get("user.name") ;
```

Der Schlüssel muss nicht in einfachen oder doppelten Anführungszeichen eingeschlossen werden, wie es etwa die Expression Language unter JSP 2.0 oder Velocity vorschreibt.

### Geschachtelte Properties

Um eine Liste aller Zeichensätze des Betriebssystems auszulesen, lässt sich über GraphicsEnvironment `getLocalGraphicsEnvironment()` aufrufen.

```java
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
```

Ausdruck Der Name des ersten Fonts erfragt

```java
String s = ge.getAllFonts()[0].getName();
```

Wie sieht das nun mit den BeanUtils aus? Sicherlich ist es denkbar, für den indexierten Property einmal `getIndexedProperty()` und für den Namen `setSimpleProperty()` aufzurufen, aber commons.beanutils kann es besser, und zwar mit `getNestedProperty()`.

```java
Object o = PropertyUtils.getNestedProperty( ge, "allFonts[0].name" );
```

Während mit `getNestedProperty()` eine Eigenschaft ausgelesen werden kann, lässt sie sich mit `setNestedProperty()` setzen. Die Signaturen für set- und get sind: `PropertyUtils.getNestedProperty(Object bean, String name)` und `PropertyUtils.setNestedProperty(Object bean, String name, Object value)`.

Nun sind drei Möglichkeiten bekannt, auf Bean-Eigenschaften zuzugreifen: Einfache Properties (`getSimpleProperty()`, `setSimpleProperty()`), indexierte Properties (`getIndexedProperty()`/setIndexedProperty()), mapped Properites und geschachtelte Properites (`getNestedProperty()`/setNestedProperty()). Um den Umgang zu vereinfachen, hilft die allgemeine Funktion `getProperty()`, die sich den passenden Typ heraussucht. Damit lässt sich alles mit nur einer Art von Funktion beschreiben: `PropertyUtils.getProperty(Object bean, String name)` und `PropertyUtils.setProperty(Object bean, String name, Object value)`.

### Kopien von Bean-Eigenschaften

Stehen zwei Beans gegenüber, die sich Properties teilen, so kopiert BeanUtils. `copyProperties()` die Eigenschaften. Die Klasse Point definiert genauso wie Rectangle das Property x und y. Die Belegungen der Eigenschaften lassen sich übertragen, so dass das Rectangle alles annimmt, was in Point definiert wird:

```java
Point p = new Point( 10, 20 );
Rectangle rec = new Rectangle(); 
BeanUtils.copyProperties( rec /* = */, p );
System.out.println( rec ); // java.awt.Rectangle[x=10,y=20,width=0,height=0]
```

Intern geht `copyProperties()` alle Eigenschaften vom Punkt durch, findet x, y und auch location. Für diese drei Eigenschaften werden die entsprechenden set-Methoden beim Rectangle-Objekt gesucht; sie werden nur für x und y gefunden, denn `setLocation()` ist überladen und so ungültig.

Ein Beispiel, unter dem Bean-Attribute zu kopiert sind, liefert Struts. Die Action Form Beans werden zwar allzu oft als Model eingesetzt und weiterverarbeitet, das ist aber falsch. Die Form Beans sind lediglich eine Hilfs-Struktur, die nur für die Formulardaten eine Berechtigung haben. Demnach sind sie auch nur in einem Struts-Durchlauf bekannt und werden nicht als Datencontainer weitergegeben. Trennt man allerdings Form-Bean von tatsächlicher Model-Bean (falls eine Model-Bean benötigt wird) sieht das Model sehr ähnlich der Form-Bean aus und entsteht leider doppelter Quellcode, insbesondere für die set- und get-Methoden. Weiterhin ist lästig, dass bei einer gültigen Formularbelegung alle Form-Eigenschaften auf die Model-Bean übertragen werden. Das artet aus zu einer Reihe von Aufrufen der Art

```java
modelBean.setXXX( formBean.getXXX() );
```

An diese Stellt helfen die BeanUtils und die praktische Funktion `copyProperties()`. Sie überträgt automatisch die Eigenschaften der Form-Bean in die Model-Bean.

```java
BeanUtils.copyProperties( modelBean, formBean );
```

### Bean-Objekte klonen

Auf `copyProperties()` aufbauend lassen sich Kopien von Beans anlegen lassen. Da das Kopieren auf Grund der Eigenschaften und set/get-Methoden geschieht, ist eine Implementierung der Schnittstelle Clonable nicht nötig. Mit der `clone()`-Methode teilt `cloneBean()` jedoch mit, dass die Kopie wieder eine flache und keine tiefe ist: static `Object` `cloneBean(Object bean)`.

### Dynamische Beans

Bisher waren es existierende Beans, die über wirkliche set- und get-Methoden verfügten. Mit den BeanUtils lassen sich jedoch auch "virtuelle" Beans erzeugen, also Beans, die mit den BeanUtils verwaltet werden können, aber keine passenden set- und get-Funktionen besitzen. Diese Spezial-Beans implementieren die Schnittstelle DynaBean und verwalten über diese Schnittstelle Schlüssel/Werte-Paare. Genauso wie eine Klasse den Bauplan für Objekte beschreibt, beschreibt die Schnittstelle DynaClass den Bauplan für DynaBean-Ojekte. Exemplare der virtuellen Beans führen zuerst über die DynaClass. Die BeanUtils bringen eine Basisimplementierung in Form der Klasse BasicDynaClass mit; ihre Eigenschaften werden als Array von DynaProperty-Objekten übergeben.

```java
DynaProperty[] dynaProp = new DynaProperty[] {
  new DynaProperty( "schenker", String[].class ),
  new DynaProperty( "bringer", Weihnachtsmann.class ),
  new DynaProperty( "volumen", int.class )
};

BasicDynaClass dynaClass = new BasicDynaClass( "geschenk", null, dynaProp ); 
```

Die BasicDynaClass beschreibt für ein Geschenk ein Feld von Schenkern (wie "Mama", "Papa"), den `Weihnachtsmann` und die Größe des Geschenks.

Nach der Beschreibung der Klasse bildet die Objektfunktion `newInstance()` ein Exemplar der dynamischen Bean:

```java
DynaBean paket = dynaClass.newInstance();
```

```java
Alternativ zu dieser Schreibweise lässt sich ein Exemplar BasicDynaBean bilden, der im Konstruktor die beschreibende Klasse annimmt: paket = new BasicDynaBean(dynaClass);
```

Diese DynaBean besitzt über die Schnittstelle Methoden zum Erfragen, Setzen oder Löschen von Attributbelegungen. Die Methode `set()` setzt zum Beispiel eine Eigenschaft.

```java
paket.set( "schenker", new String[1] );
paket.set( "bringer", new Weihnachtsmann() );
```

Die `set()`-Funktion ist überladen, um auch indexierte und abgebildete Eigenschaften zu unterstützten. Das gleiche gilt für die get-Funktion. Während bei den herkömmlichen Beans der Zugriff get<Property>() steht, so heißt der nun get("<Property>").

```java
System.out.println( paket.get("volumen") );
```

Da das BeanUtils-Paket bei den bekannten Funktionen wie `PropertyUtils.getProperty()` neben den "normalen" Beans auch die DynaBean unterstützen, müssen die über die Schnittstelle DynaBean vorgeschriebenen Funktionen nicht verwendet werden.

```java
PropertyUtils.setSimpleProperty( paket, "volumen", new Integer(123) );
Integer volumen = (Integer) PropertyUtils.getSimpleProperty( paket, "volumen" );
```

Da im Beispiel vorher schon das Feld der Schenker mit einem `String`-Array der Länge eins initialisiert wurde, lässt sich ein konkreten Element einfach mit der allgemeinen Funktion `setProperty()` setzen.

```java
PropertyUtils.setProperty( paket, "schenker[0]", "Ulli" );
System.out.println( PropertyUtils.getProperty(paket, "schenker[0]") ); // Ulli
```

### Mantel um existierende Beans

Die DynaBeans bietet einen einheitlichen Standard für einfache, indexierte oder abgebildeten Eigenschaften über `setXXX()` und `getXXX()`-Funktionen. Um auch existierende Beans als DynaBeans zu verwaltet, sind die Klasse WrapDynaBean und WrapDynaClass definiert. Eine WrapDynaBean legt sich um eine bekannten Bean, so dass diese sich als DynaBean verwalten lässt.

```java
Weihnachtsmann myWeih = new Weihnachtsmann();
DynaBean wrapper = new WrapDynaBean( myWeih );
wrapper.set( "name", "Schlittenheld" );
String nameW = (String) wrapper.get( "name" );
System.out.println( "Wrapper: " + nameW + ", Bean: " + myWeih.getName() );
wrapper.set( "alter", new Integer(891) );
int alterW = ((Integer) wrapper.get( "alter" )).intValue();
System.out.println( "Wrapper: " + alterW + ", Bean: " + myWeih.getAlter() );
```

### DynaBeans in Struts \*

In Struts führt die Implementierung der Form-Beans für die Abbildung der Formulardaten zu lästigen Aufwand. Die DynaBeans helfen, diesen Aufwand zu minimieren, da keine wirkliche Bean-Klasse mehr zu implementieren ist, sondern die "virtuelle" Bean Verwendung findet. In der struts-config.xml wird zunächst unter form-bean wie üblich die Bean eingetragen. Allerdings ist der Typ nun nicht der Form-Bean Typ, sondern DynaActionForm. In den folgenden Elementen der XML-Datei wird genau die schon bekannten DynaProperty für eine DynaClass eingetragen — nur nicht in Java, sondern in einer Konfigurationsdatei.

```text

```

Da Struts mit den HTML-Tags die DynaBeans berücksichtigt, muss an der View (JSP-Seite) keine Veränderung vorgenommen werden. Nur die Action muss eine Veränderung erfahren, da ja ohne DynaBeans das ActionForm aus der `execute()`-Funktion auf die konkrete Bean typangepasst würde, um die entsprechenden set- und get-Funktionen zu nutzen. Dieser Programmcode muss nun umgebaut werden. Statt dessen gibt Struts eine Klasse DynaActionForm vor, zu der eine Typanpassung vorgenommen wird. Über diese Klasse lässt sich mit get- und set-Funktionen die Bean nutzen.

```java
public ActionForward execute(
 ActionMapping mapping, ActionForm form,
 HttpServletRequest request,
 HttpServletResponse response )
  throws ServletException, IOException
{
  DynaActionForm weihForm = (DynaActionForm) form;
  String name = weihForm.get( "name" );
  ...
```

Nicht umsonst sieht der Zugriff auf die Attribute über DynaActionForm so aus wie schon im vorangehenden Beispiel beschrieben: DynaActionForm implementiert die Schnittstelle `org.apache.commons.beanutils.DynaBean`.

Die DynaActionForm ersetzt vollständig die Form-Bean, wobei eine Sache auf der Streckte bleibt: die Validierung. Für die Überprüfung der Formularbelegungen wurde in der Unterklasse von ActionForm die Methode `validate()` überschrieben. Bei den DynaBean gibt es aber keine eigene Bean-Klasse! Eine Lösung ist eine Validierung über das Validator-Framework (auch eine Jakarta Commons), also über eine XML-Datei, eine andere ist doch wieder eine Unterklasse. Diese spezielle Bean-Klasse leitet von der schon bekannten DynaActionForm ab und implementiert wie bekannt die `validate()`-Funktion. In struts-config.xml muss natürlich DynaActionForm wieder verschwinden und der Name der Unterklasse eingesetzt werden.

### DynaBeans für Datenbanken

Die DynaBeans finden auch an anderer Stelle Verwendung: bei Datenbanken. Ein DynaBeans-Objekt kann eine Zeile eines ResultSet repräsentieren. Um das zu erreichen, legt sich ein ResultSetDynaClass-Objekt um ein ergebnislieferndes ResultSet.

```java
ResultSetDynaClass rsdc = new ResultSetDynaClass( rs, true );
```

ResultSetDynaClass implementiert die Schnittstelle DynaClass. Das ist wichtig, denn DynaClass verwaltet die Beschreibung der Eigenschaften über DynaProperty-Objekte. Bei der ResultSetDynaClass werden die Namen der Spalten zu den Namen der Eigenschaften. Der Konstruktor von ResultSetDynaClass ist überladen und verträgt ein zusätzliches boolean, damit die Namen der Eigenschaften nicht exakt in Groß- und Kleinbuchstaben übereinstimmen müssen. Ist die Belegung `true`, so reichen alle Namen in Kleinbuchstaben. Wichtiger ist aber die Funktion `iterator()` von ResultSetDynaClass, die der Reihe nach die Zeilen als DynaBean liefert; die Beschreibung der Klassen-Informationen war ja wichtiges Teil in den DynaProperty-Objekten.

```java
for ( Iterator rows = rsdc.iterator(); rows.hasNext(); ) {
  DynaBean row = (DynaBean) rows.next();
  System.out.println( row.get("bla") );
}
```

Nach dem Durchlaufen kann das ResultSet geschlossen werden, das bedeutet, dass zur Zeit des Durchlaufens eine Verbindung zur Datenbank bestehen muss.

Die Frage ist nun, was ein ResultSetDynaClass bringt; zum Durchlaufen tut es auch das ResultSet. Ein Vorteil ist, dass die Daten, die über die DyaBean veröffentlicht werden, leicht auf andere Beans kopiert werden können; man erinnere sich an `BeanUtils.copyProperties(ziel, quelle)`. Oftmals müssen die Datenbankinhalte auf das Model einer Applikation übertragen werden, so dass ein ResultSetDynaClass dazu gut geeignet ist.

Eine Eigenschaft der Klasse BasicDynaBean (und BasicDynaClass) ist ihre Serialisierungs-Möglichkeit, da die Klasse die Schnittstelle `java.io.Serializable` implementiert, und somit persistent gemacht werden kann. Eine normale DynaBean implementiert diese Schnittstelle nicht, so dass man an dieser Stelle die Serialisierung nicht erzwingt. Aber natürlich kann eine andere Klasse DynaBean und Serializable gleichzeitig implementieren und das wäre sogar praktisch, denn könnte die Daten gleich abgespeichert werden. Wurde zum Beispiel eine BasicDynaBean angelegt, können Daten auf diese Bean übertragen werden und sie lässt sich später abspeichern. Es wäre doch praktisch, wenn auch die Zeilen vom ResultSetDynaClass serialisierbar wären. Dann wäre das Problem gelöst, wie sich Datenbankinhalte einfach übertragen lassen — O.K., ein RowSet ist auch eine Lösung. Die Antwort aus den BeanUtils ist die Klasse RowSetDynaClass, die Serializable implementiert. RowSetDynaClass liest aus einem ResultSet alle Zeilen aus und speichert sie, so dass sie serialisierbar werden.

```java
RowSetDynaClass rsdc = new RowSetDynaClass( rs );
```

Nach dieser Zeile kann das ResultSet rs schon geschlossen werden. Der Zugriff auf die Zeilen geschieht anschließend mit `getRows()`, was eine `java.util.List` mit den bekannten DynaBean-Objekten liefert. Mit dem serialisier-fähigen RowSetDynaClass lassen sich die Inhalte über RMI leicht transportieren, ohne dass viel Programmcode entwickelt werden muss.

### Links

- 
- 

Kategorien: [Open Source](https://tutego.de/blog/javainsel/category/open-source/), [Apache](https://tutego.de/blog/javainsel/category/apache/)

[← Alle Beiträge](https://tutego.de/blog/javainsel/)

---

## Navigation

- Previous: [Präsentation “Java 8 The Good Parts” auf der JavaOne 2013](https://tutego.de/blog/javainsel/2013/09/prsentation-java-8-the-good-parts-auf-der-javaone-2013.md)
- Next: [Daten speichern in Google App Engines Datastore](https://tutego.de/blog/javainsel/2013/09/daten-speichern-in-google-app-engines-datastore.md)
