JavaBeans, XML und Java Version 17 - oh, my!

vorhergehende Artikel in: Java Komponenten
28.06.2023

Ich habe neulich eine meiner alten Anwendungen hervorgeholt und zwei sehr alte Tickets schließen wollen - das eine zwei und das andere sogr drei Jahre alt. Da niemand außer mir darauf wartete, war dieses hohe Alter der Tickets nicht weiter schlimm. Das Schlimme kam aus einer völlig unerwarteten Richtung...

Java hat bereits seit Ewigkeiten Unterstützung eingebaut, um beliebige Objektgraphen nach XML zu serialisieren und aus XML wieder zurück zu deserialisieren. Handelt es sich bei den Objekten im Graph um JavaBeans (vollständiger innerer Zustand durch Getter/Setter für Properties beschrieben und parameterloser public Konstruktor in einer public Klasse) muss man michts weiter tun - einfach die Wurzel des Objektgraphen an den XMLEncoder übergeben und fertig.

Da die Welt um uns herum nicht so einfach gestrickt ist, sind nicht alle Objekte JavaBeans - daher existieren PersistenceDelegate, die es erlauben, die Serialisierung so zu beschreiben, dass auch Klassen, die beispielsweise keinen parameterlosen Konstruktor aufweisen trotzdem vom XMLEncoder serialisiert werden können. Beim Deserialisieren ist kein gesonderter Aufwand nötig - XMLEncoder und PersistenceDelegate, zusammen erzeugen immer ein solches XML, das vom XMLDecoder sofort verstanden werden kann.

Bis hierher klingt die Theorie recht schön. Und dann kam Java17 und das Modulsystem machte alles kaputt...

Eins meiner Tickets besagte, dass ich dem Konfigurationsobjekt eine weitere Property vom Typ java.io.File hinzufügen solle. Bisher enthielt dieses bereits vier davon, wobei diese aber jeweils Verzeichnisse waren - keine Dateien. Diese neue Property sollte aber eine Datei enthalten. Für diese Konfiguration existierte eine graphische Nutzeroberfläche, sodass die Verzeichnisse mit einem eigens konfigurierten JFileChooser ausgewählt wurden, der nur die Auswahl von Verzeichnissen zuließ. Dies funktionierte bisher jahrelang hervorragend. Nachdem ich die neue Property hinzugefügt hatte und in der GUI dafür gesorgt hatte, dass es möglich war, diese auch hier mittels eines JFileChooser zu setzen (hier konnte man natürlich auch normale Dateien auswählen) stellte ich fest, dass die XML-Serialisierung nicht mehr funktionierte: Der Code dafür bemängelte, dass er nicht wüsste, wie er Instanzen der Klasse ShellFolder serialisiern solle.

Es stellt sich heraus, dass der JFileChooser, wenn eine Datei ausgewählt wird und anschließend getSelectedFile() aufgerufen wird keine Instanz der Klasse File, sondern eine der Klasse ShellFolder aus dem Package sun.awt.shell zurückliefert. Diese Klasse ist eine mittelbare Kindklasse von File.

Also versuchte ich, für den ShellFolder ein geeignetes PersistenceDelegate zu erstellen - das wiederum schlug mit der Fehlermeldung fehl, dass java: package sun.awt.shell is not visible (package sun.awt.shell is declared in module java.desktop, which does not export it) - ganz großes Kino! Ich behalf mir zunächst damit, dass ich sämtliche Setter in meinen Beans wie folgt änderte, wenn der Typ der zugehörigen Property File war:

@Property
public void setFileProp(File fileProp)
{
	File old = getFileProp();
	this.fileProp = new java.io.File(fileProp.toURI());
	send("fileProp", old, getFileProp());
}

und überall, wo ich bisher einen JFileChooser einsetzte, nunmehr folgende davon abgeleitete Klasse verwende:

import javax.swing.filechooser.FileSystemView;
import java.io.File;

public class FileChooser extends javax.swing.JFileChooser { public FileChooser() { super(); }

public FileChooser(String currentDirectoryPath) { super(currentDirectoryPath); }

public FileChooser(File currentDirectory) { super(currentDirectory); }

public FileChooser(FileSystemView fsv) { super(fsv); }

public FileChooser(File currentDirectory, FileSystemView fsv) { super(currentDirectory, fsv); }

public FileChooser(String currentDirectoryPath, FileSystemView fsv) { super(currentDirectoryPath, fsv); }

@Override public File getSelectedFile() { java.io.File rv=super.getSelectedFile(); if(rv!=null) if(java.io.File.class!=rv.getClass()) rv=new java.io.File(rv.toURI()); return rv; } }

Damit, dachte ich, sei alles ausgestanden - doch ich wurde eines Besseren belehrt: die sQLshell serialisiert ihre Konfiguratin ebenfalls mithilfe des XMLEncoder und hier sieht man die Fehlermeldung java.lang.NoSuchMethodException: =ZoneInfo.getRawOffset(); - auch hier versuchte ich nun, einen PersistenceDelegate zu erstellen - und wurde mit der ähnlichen Fehlermeldung konfrontiert: java: package sun.awt.shell is not visible (package sun.awt.shell is declared in module java.desktop, which does not export it) - auch hier also spuckte mich das Modulsystem von Java (17) an.

Die "Lösung" für all das ist das gute alte --add-exports. Ich halte das für keine gute Lösung... Außerdem habe ich sie hier bei mir noch nicht zum Funktionieren gebracht. Also wieder mal vielen Dank für nichts. Früher, in der guten alten Zeit hätte ich wenigstens noch Larry Ellison verfluchen können aber selbst diese Genugtuung wurde mir genommen...

Artikel, die hierher verlinken

XML-Serialisierung und Java-Generics

Es ist verwunderlich, dass ich in den letzten Wochen mehrfach über Probleme mit der Serialisierung von Objektgraphen in XML in Java stolpere - aber es ist passiert...

Alle Artikel rss Wochenübersicht Monatsübersicht Github Repositories Gitlab Repositories Mastodon Über mich home xmpp


Vor 5 Jahren hier im Blog

  • Certstream, InfluxDB, Grafana und Netflix

    16.04.2019

    Nachdem ich vor kurzem über mein erstes Spielen mit dem certstream berichtete, habe ich weitere Experimente gemacht und die Daten zur besseren Auswertung in eine InfluxDB gepackt, um sie mit Grafana untersuchen zu können.

    Weiterlesen...

Neueste Artikel

  • Die sQLshell ist nun cloudnative!

    Die sQLshell hat eine weitere Integration erfahren - obwohl ich eigentlich selber nicht viel dazu tun musste: Es existiert ein Projekt/Produkt namens steampipe, dessen Slogan ist select * from cloud; - Im Prinzip eine Wrapperschicht um diverse (laut Eigenwerbung mehr als 140) (cloud) data sources.

    Weiterlesen...
  • LinkCollections 2024 III

    Nach der letzten losen Zusammenstellung (für mich) interessanter Links aus den Tiefen des Internet von 2024 folgt hier gleich die nächste:

    Weiterlesen...
  • Funktionen mit mehreren Rückgabewerten in Java

    Da ich seit nunmehr einem Jahr bei meinem neeun Arbeitgeber beschäftigt und damit seit ungefähr derselben Zeit für Geld mit Python arbeite, haben sich gewisse Antipathien gegenüber Python vertieft (ich kann mit typlosen Sprachen einfach nicht umgehen) - aber auch einige meiner Gründe, Python zu lieben sind ebenso stärker geworden. Einer davon ist der Fakt, dass eine Methode in Python mehr als einen Wert zurückgeben kann.

    Weiterlesen...

Manche nennen es Blog, manche Web-Seite - ich schreibe hier hin und wieder über meine Erlebnisse, Rückschläge und Erleuchtungen bei meinen Hobbies.

Wer daran teilhaben und eventuell sogar davon profitieren möchte, muß damit leben, daß ich hin und wieder kleine Ausflüge in Bereiche mache, die nichts mit IT, Administration oder Softwareentwicklung zu tun haben.

Ich wünsche allen Lesern viel Spaß und hin und wieder einen kleinen AHA!-Effekt...

PS: Meine öffentlichen GitHub-Repositories findet man hier - meine öffentlichen GitLab-Repositories finden sich dagegen hier.