# Best Practices für Data Binding ohne Hilfstools



## Marco13 (3. Mai 2007)

Hallo

Wenn man komplexe Objekte von Java in XML speichern will, gibt es dafür etliche Tools. Wenn man nun aber KEINE Tools verwenden will, sondern die Daten von Hand speichern will, wie macht man das am besten? Man kann es "irgendwie" machen, aber wenn es um XML-Strukturen mit Veschachtelungstiefen von 10 (oder so) geht, kann man da wohl schon einiges falsch machen. 

Ganz grob (!) und sinngemäß skizziert(!) könnte man verschiedene Ansätze verfolgen:

1. Man hat eine Klasse, die die XML-Verarbeitung regelt. Sie parst den kompletten XML-Baum, läuft im XML-Baum "runter", baut an den Blättern die "primitiven" Objekte, um diese dann zu immer größeren, komplexeren Objekten zusammengebaut werden, bis am Ende das riesige, komplexe Objekt erstellt werden kann, das der XML-Datei entspricht. Zum Schreiben von XML läuft das ganze analog. 

2. Für jede Klasse gibt es einen passenden XMLReader/Writer, der einen Knoten bekommt, und daraus das passende Objekt erstellt (oder umgekehrt). Jeder dieser XMLReader verwendet für die unter-Objekte kleinere XMLReader als "Building Blocks".

3. Jede Klasse hat (sinngemäß) einen no-args-Konstruktor, und zwei Methoden wie "readFromNode(Node n)" und "Node createNode()", die die XML-Verwaltung für die Klasse selbst regeln.

Für mich kommen eigentlich nur zwei davon in Frage, aber welche davon sich (bei denjenigen, die sich damit schon intensiver beschäftigt haben) "bewährt" haben, würde mich interessieren. (Ich zähle aber mal nicht meine subjektiven Pros/Cons auf, um die Antworten nicht zu sehr zu beeinflussen )

bye


----------



## Ullenboom (4. Mai 2007)

Hier finde ich das Collecting Parameter Pattern zur Reduzierung von temporären Objekten gut angebracht -- alle Knoten, die eine XML-Repräsentation liefern, schreiben diese in einen übergebene Behälter. Hierfür finde ich die Java 5 Schnittstelle java.lang.Appendable wie geschaffen:

```
class Customer
{
 ...
 void toXml( Appendable a ) {
  a.append( XML-Repräsentation erzeugen );
 }
```

Der Methode toXml() kann man nun so was wie StringBuilder, aber auch alle Writer rekursiv übergeben.

Beste Grüße

 Christian


----------



## AlArenal (5. Mai 2007)

Nun kann man vorzüglich diskutieren, ob es Aufgabe einer Datenklasse ist, die eigene De-/Serialsierung zu erledigen. Man baut ja auch keine Häuser mit eingebauter Abrissbirne....


----------



## Marco13 (6. Mai 2007)

@Ullenboom: Das wäre also im Prinzip die dritte Variante - allerdings stört mich daran genau das, was AlArenal auch angedeutet hat: Ich finde es eigentlich nicht schön, wenn eine Klasse solche Meschanismen selbst kennt (weil sie nichts mit dem abstraken Modell zu tun haben, für das die Klasse steht). Wo jetzt die Grenze verläuft, weiß ich auch nicht so genau (man könnte ja so dreist sein, die toString() Methode so zuüberschreiben, dass sie XML zurückgibt  :shock:   - von wegen: "Das gehört nicht in die Klasse" :wink: ). Insgesamt tendiere ich eigentlich eher zur zweiten Variante - aber DA stört mich, dass man u.U. Dinge NUR public machen muss, um sie zu XMLen/unXMLen, obwohl diese Sachen ansonsten garnicht public sein müßten... Hm... ???:L


----------



## SnooP (6. Mai 2007)

nein... - da gibts natürlich auch versch. Dinge... entweder man guckt per Reflection nach den get-Methoden in der Klasse und versteht sie als Bean... dann muss man halt dafür sorge tragen, dass alle zu persistierende Felder entsprechende get/set-Methoden bereitstellen oder...
Man kopiert ebenfalls per Reflection tatsächlich die Felder, die mit entsprechender Sicherheitseinstellung dann auch auf private/final-Felder zugreifen kann... - XStream geht z.B. auch so vor...
Damit bräuchtest du auch nicht für jede Klasse noch xml-reader/writer... das wäre mir persönlich zu umständlich, weil du bei der Erweiterung deiner Klassen dann auch da immer noch drauf achten musst.. - also eher schlecht.


----------



## Ullenboom (6. Mai 2007)

Den eigenen Klassen so was wie toXml()/fromXml() zu geben ist sicherlich das einfachste und "irgendwie" auch objektorientiert. Das Objekt "kann" was, nämlich eine XML-Repräsentation zu geben. Daher finde ich das so erst mal OK. Natürlich gibt es ein Hammer-Argument, was du schon genannt hast, was dagegen spricht: XML-Erzeuger-Code gehört nicht in eine normale Geschäftsklasse, weil das nicht ihrer Verantwortung ist. Wo also dahin? Hier kommt so etwas wie das Memento-Pattern ins Spiel, also die externe Abbildung auf eine andere Klasse zu verschieben. Da hast du schon die XML-Abbildungs-Klassen genannt. Aber eine Klasse pro Knoten finde ich da sehr aufwändig. Das zu automatisieren wären hübsch und Techniken wie Reflection hat SnooP schon genannt. Eine simple Idee zum Selbermachen wäre folgende:

class XmlEncoder
{
   String toXml( Class nodeClass )
   {
     if ( nodeClass.equals(Customer.class) )
       return XML-Serialisierung vom Customer.
   }
}

Ist der XmlEncoder im gleichen Paket, so reichen dann paketsichtbare Eigenschaften bei den Geschäftsklassen. Wobei hier auch SnooP recht hat: Getter sind nicht verkehrt.

Vielleicht möchtest du dich doch mit JAXB oder XStream anfreunden  Ich arbeite gerne mit beiden (seit Java 6 aber mehr mit JAXB 2.) 

Grüße

 Christian


----------



## kleiner_held (6. Mai 2007)

Ich habe auch schon mehrmals die 3te Variante verwendet, da sie erst mal sehr einfach und auch übersichtlich ist. Wenigstens so lange, wie der Umfang der entsprechenden Methoden noch in einem überschaubaren Rahmen bleibt. Gerade wenn man sowieso schon eine baumartige Modellstruktur mit einem Root-Objekt hat, läßt sich das ganz gut umsetzen. Auch wenn dieses Design zugegebenermaßen nicht perfekt ist.

Von Reflection halte ich allerdings in dem Zusammenhang gar nichts, da man dann einfach keine stabile Schnittstelle hinbekommt. Gerade wenn man den Mechanismus für eine Speicherfunktion nutzt, sollte man versuchen das XML Format über verschiedene Programmversionen konsistent zu halten. Ist das durch größere Änderungen nicht mehr möglich, kann man immer noch eine neue Version seiner Schnittstelle verfassen, aber man hat wenigstens volle Kontrolle darüber wann sich die XML-Struktur ändert. Bei Verwendung von Reflection läuft man andauernd Gefahr, das sich durch kleinere Änderungen im Modell plötzlich unbeabsichtigt die Schnittstelle geändert hat, nur weil man eine neue protected Membervariable oder ein Bean-Property hinzugefügt hat.


----------



## Marco13 (6. Mai 2007)

@Ullenboom: Der XMLEncode sieht jetzt aber eher wie die erste Variante aus ???:L  (das war aber die, die für mich nicht in Frage käme - zu viel "Macht" in einer Klasse, sehr unübersichtlich). 

Reflection fällt schonmal in allen Fällen weg (das gilt auch für Tools, die intern Reflection verwenden) : Das ganze wird am Ende obfuscated, und damit ist Reflection leider nichtmehr anwendbar. 

Vermutlich wird es auf eine Mischung der letzten beiden rauslaufen. Eigentlich hätte ich gerne ein einheitliches, konsistentes Konzept für alles, aber offenbar gibt's die eierlegene Wollmilchsau in diesem Sinne nicht. Vermutlich werden "komplexe" Klassen ihre eigenen toXML/fromXML-Methoden anbieten, mehrere kleine Klassen (die sinngemäß zusammengehören oder ähnlich sind) können mit einem XMLEncode/Decoder abgehandlet werden (um nicht 1000e neue Klassen erzeugen zu müssen) und die elementarsten Sachen (Strings, ints, Arrays) werden (wie jetzt schon) von einer XML-Utility-Klasse behandlet. Man kann die einzelnen XMLEncoder/Decoder-Klassen bzw. die fromXML/toXML-Methoden ja so bauen, dass man relativ leicht zwischen beiden Welten wechseln kann.

Erstmal danke für alle bisherigen Tipps und Anregungen. Weitere Kommentare sind aber immer erwüscht


----------



## SnooP (7. Mai 2007)

wollt ihr wirklich eure public-Methoden obfuscaten? Ich kenn das, dass man die halt offen lässt... dadurch könnte man dann wunderbar per Reflection auf die getter und setter einer Klasse zugreifen und das Speichern/Populaten darüber erledigen...


----------



## Marco13 (7. Mai 2007)

Es wird ALLES obfuscated, außer den Klassen/Methoden, die für das Ansprechen des Porgrammes von außen benötigt werden (und das sind nur ganze wenige, im Vergleich zur Menge ALLER public Klassen/Methoden).


----------



## AlArenal (7. Mai 2007)

Buäh, da halte ich ja wenig bis gar nichts von. Da ist doch dann alles, was an Stacktraces und Logging-Infos geworfen wird für die Tonne, oder nicht?


----------



## Marco13 (7. Mai 2007)

Wenn ein Kunde einen Stacktrace zu Gesicht bekommt, ist eh irgendwas im Argen - egal, ob obfuscated oder nicht :wink: Irgendwie muss das ganze ja gegen reverse engineering geschützt werden (und dass das "Geheimnisprinzip" nicht eigehalten wurde, bemängele ich selbst schon die ganze Zeit, aber ... du weißt da vielleicht, wie das ist... :roll: )


----------



## SnooP (8. Mai 2007)

nunja... ich würde als Kunde ehrlich gesagt überhaupt nix kaufen, wo ich nicht auch den sourcecode zu bekomme  - wenn die Firma weg ist, ist dann auch für alle Zeiten mein System in Stein gemeißelt...

der Stacktrace ist ja trotzdem für's logging interessant... sprich man muss dem Kunden ja den Fehler nicht direkt vor augen führen - mail an support, ablegen in die db oder in nen log-file reicht ja schonn und man hat erheblich mehr Informationen als die Meldung vom Kunden "das geht irgendwie nicht!".


----------



## AlArenal (8. Mai 2007)

Schutz vor Reverse Engineering gibts bei uns nicht. Das war eine ganz bewusste Entscheidung von mir. Wenn ein Kunde für mehrere Teuros ne Software, für viele weitere Teuros Schulung und für noch mehr Teuros Anpassungen bekommt, dann tue ich es mir nicht an auf mein liebgewonnenes Logging zu verzichten und dumm dazustehen, wnn es irgendwo hakt, weil ich schwer bis gar nicht nachvollziehen kann was los ist. Da müsste ich schon sehr paranoid sein... 

Das ist auch eine Sache von gegenseitigem Vertrauen. Ich bin doch nicht bei Microsoft 

Wenn es dann klemmt lassen wir uns, wie SnooP bereits anmerkte, die Logs zuschicken.  Die Clients (Java) und mein Teil der Serveranbindung (PHP) haben ihre Logfiles, die vom jeweiligen User / Admin leicht an uns versandt werden können und mir neben den Fehlerbeschreibungen des Kunden in unserem Bug Tracking System wertvolle Zusatzinfos geben, ohne die ich wie schon gesagt meist einfach nur mit der Achsel zucken könnte.

Was sagt der Kunde wohl, wenn ich ihm sage, dass ich den Fehler nicht reproduzieren und daher auch nicht abstellen kann? Doof, oder?


----------



## Marco13 (8. Mai 2007)

Ich finde das auch ... suboptimal ... wir verkaufen das Produkt zwar nicht direkt an den Endkunden, aber natürlich wird das Probleme geben, wenn DOCH mal ein Stacktrace auftaucht, und darin dann Zeilen wie
c.a.f.s.for (Unknown Source)
c.a.f.t.while (Unknown Source)
vorkommen ... Derenige, der diese Entscheidung getroffen hat, war mit an Sicherheit grenzender Wahrscheinlichkeit kein Programmierer, sondern jemand "wichtiges". (Ihr wißt schon - diese Leute im Pinguin-Kostüm). Naja. Das hat mit dem DataBinding und XML jetzt aber schon nichtmehr so viel zu tun.


----------

