ClassToXML

Kurzbeschreibung | Wieso, Weshalb, Warum? | Verwendung/Beispiel | Downloads | Changelog | Alternative

Kurzbeschreibung

ClassToXML ist eine Library mit der es möglich ist, simple Objekte direkt in ein XML-File zu schreiben und wieder zu laden.

Bei komplexeren Objekten möchte ich an dieser Stelle direkt auf die bessere Alternative verweisen.

Wieso, Weshalb, Warum?

Die Idee kam mir bei jShufflePic, als ich ein weiteres mal einen XML – Baum aufbauen wollte. Jedesmal der selbe verdammte Baum, nur mit anderen Blättern. Getreu den Motto DRY (don’t repeat yourself) habe ich mir also überlegt, ich hol die Axt und zerleg den Baum. Soll Java sich doch selbst darum kümmern (weil.. ich hab ein Beil→ off Topic aber passte gerade so schön mit der Axt ;)).

Es gibt sicherlich bereits Librarys die genau dies können und das wahrscheinlich auch schneller, schöner und besser als ich. Aber irgendwann kommt der Tag, an dem jeder Mal das Rad neu erfinden muss. Und ich sah in dieser Aufgabe eine kleine Herausforderung die trotzdem in kurzer Zeit zufriedenstellend gelöst werden kann. Zumal ich damit endlich (als ob ich darauf gewartet hätte) eine Möglichkeit zur Verwendung der Generics gefunden hatte.
Und das schöne an dieser Library ist, dass sie sehr klein und einfach zu benutzen ist. Für kleinere Speicheraufgaben, wie Programmeinstellungen ist das absolut ausreichend. Es sei denn es ist nicht nötig, dass die entstehenden Dateien  lesbar, z.B. in Form von XML-Dateien, sind. Dann wäre z.B. die Serialization die bessere Wahl.

Verwendung / Beispiel

Benutzt werden kann die Library in einem Projekt entweder in dem das Jar-File eingebunden wird oder direkt das Package dem Projekt hinzugefügt wird. Naja, oder man kopiert die EINE Datei einfach so in sein Projekt.

Zu erst wird ein Objekt der Klasse benötigt:

ClassToXML <TestClass> ctx = new ClassToXML<TestClass>("test.xml");

Wobei TestClass der Klasse entspricht, die später in die Datei test.xml gespeichert werden soll.

Der Aufbau der zu speichernden Klasse ist dabei leider nicht ganz egal.

Einschränkungen:

  • Klassenvariablen müssen public sein
  • Ein leerer Konstruktor der public ist muss vorhanden sein
  • Umlaute in Strings sind nicht gern gesehen und führen zu einer sch… schönen Exception

Unterstützte Datentypen sind bisher:

  • String
  • String[]
  • int
  • double
  • boolean
  • long

Angenommen TestClass schaut so aus:

public class TestClass {
   public String vorname;
   public String nachname;
   public int z1;
   public double d1;
   public String[] strarray = null;

  public TestClass() {
  }

  public TestClass(String str, String str2, int z1, double d1, String[] strarray) {
    this.vorname=str;
     this.nachname=str2;
     this.z1=z1;
     this.d1=d1;
     this.strarray=strarray;

  }

  public void setZ1(String str) {
    z1 = Integer.valueOf(str);
  }

} 

Und es wird das Objekt tc_w von TestClass erzeugt:

String[] strarray = {"eins","zwei"};
TestClass tc_w = new TestClass("str","str2",1,1.1,strarray);

So wird nun mit

ctx.write(tc_w);

das Objekt in die Datei test.xml geschrieben und schaut am Ende so aus:

<?xml version="1.0" encoding="UTF-8"?>
<TestClasss>
  <TestClass>
    <vorname value="str" />
    <nachname value="str2" />
    <z1 value="1" />
    <d1 value="1.1" />
    <strarray>
      <idx0 value="eins" />
      <idx1 value="zwei" />
    </strarray>
  </TestClass>
</TestClasss>

Um nun das Objekt von der Datei wieder in ein anderes Objekt tc_r einzulesen muss folgendermaßen vorgegangen werden:

TestClass tc_r = ctx.readS(TestClass.class);

Es wird die Funktion readS() benutzt. Das S soll für Single stehen, dazu gleich mehr. Wichtig bei dem Read aufruf ist, dass von der Klasse die eingelesen werden soll das Meta-Objekt (ich glaub so heisst es) mit übergeben werden muss.

Wer genau hingeschaut hat, dem ist bei dem XML Code aufgefallen, dass TestClass auf einmal drei “s” hat. Das kommt daher, dass es auch möglich ist ein ArrayList von Klassen abzuspeichern und deshalb einfach ein “s” an den Klassennamen gehangen wird.

Ein weiteres Beispiel mit der Klasse Pic die in jShufflePic verwendet wurde soll dies zeigen. Ich spare mir hier die Klassendefinition, da sie für das Beispiel egal ist.

Es wird nun eine ArrayList der Klasse Pic angelegt:

ArrayList<Pic> w = new ArrayList<Pic>();
		w.add(new Pic("c:\\test1", true, ""));
		w.add(new Pic("c:\\test2", true, ""));
		w.add(new Pic("c:\\test3", true, ""));
		w.add(new Pic("c:\\test4", true, ""));
		w.add(new Pic("c:\\test5", true, ""));
		w.add(new Pic("c:\\test6", true, ""));

		ArrayList<Pic> r = null;

		ClassToXML<Pic> ctx = new ClassToXML<Pic>("test2.xml");

		ctx.write(w);

Daraus wird in der test2.xml folgendes:

<?xml version="1.0" encoding="UTF-8"?>
<Pics>
  <Pic>
    <pfad value="c:\test1" />
    <horizontal value="true" />
    <timestamp value="" />
  </Pic>
  <Pic>
    <pfad value="c:\test2" />
    <horizontal value="true" />
    <timestamp value="" />
  </Pic>
  <Pic>
    <pfad value="c:\test3" />
    <horizontal value="true" />
    <timestamp value="" />
  </Pic>
  <Pic>
    <pfad value="c:\test4" />
    <horizontal value="true" />
    <timestamp value="" />
  </Pic>
  <Pic>
    <pfad value="c:\test5" />
    <horizontal value="true" />
    <timestamp value="" />
  </Pic>
  <Pic>
    <pfad value="c:\test6" />
    <horizontal value="true" />
    <timestamp value="" />
  </Pic>
</Pics>

Die nun über die Funktion read(), ohne S, wieder ausgelesen werden können:

ArrayList<Pic> r = ctx.read(Pic.class);


Zusätzlich zu dieser Library wird die JDOM Library benötigt!

Alternative

Ohne jetzt mein Kram hier schlecht machen zu wollen, so möchte ich doch trotzdem auf eine gute Alternative hinweisen. Die Serialization. Mit ihr ist es ebenfalls sehr einfach und auch in wenigen Zeilen möglich, ein Objekt in eine Datei zu schreiben und wieder zu laden. Auch wenn es sich dabei dann nicht um eine XML-Datei handelt.

Hängt man an meine TestClass noch ein “implements java.io.Serializable” dran, so kann wie folgt ein Objekt geschrieben und wieder gelesen werden:

try {

	///// Schreiben
	FileOutputStream fos = new FileOutputStream("foo.dat");
	ObjectOutputStream oos = new ObjectOutputStream(fos);
	oos.writeObject(tc_w);
	oos.close();
	fos.close();

	///// Einlesen
	FileInputStream fis = new FileInputStream("foo.dat");
	ObjectInputStream oin = new ObjectInputStream(fis);
	TestClass tc_rS = (TestClass) oin.readObject();
	oin.close();
	fis.close();

} catch (Throwable t) {
   t.printStackTrace();
}

Das klappt dann sogar, wenn die Klassenvariablen private sind.

Downloads

Changelog

veröffentlicht am: 8. März 2012

letzte Modifikation am: 9. September 2012

Hinterlasse eine Antwort