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

  • Mandelbrot-Sets mittels Shadern berechnen

    17.05.2019

    Nachdem ich in den letzten verregneten Tagen auf Youtube in den Videos von Numberphile versunken bin, hat mich eines davon angestachelt, mich selbst mit dem Mandelbrotset zu beschäftigen. Als ich dann noch Code fand, der behauptete, das auf einer Graphikkarte mittels Shadern berechnen zu können, war es um mich geschehen...

    Weiterlesen...

Neueste Artikel

  • Erste Vor-Version eines Gis-Plugin für die sQLshell

    Wie bereits in einem früheren Artikel erwähnt plane ich, demnächst ein Plugin für die sQLshell anzubieten, das eine Visualisierung von Daten mit räumlichem Bezug im Stil eines Geoinformationssystems erlaubt.

    Weiterlesen...
  • bad-certificates Version 2.1.0

    Das bereits vorgestellte Projekt zur automatisierten Erzeugung von Zertifikaten mit allen möglichen Fehlern hat eine Erweiterung erfahren und verfügt über ein Partnerprojekt - beide sind nunmehr in der Version 2.1.0 freigegeben

    Weiterlesen...
  • SQLite als Geodatenbank

    Wie bereits in einem früheren Artikel beschrieben treibe ich derzeit Anstrengungen voran, die sQLshell attraktiver für Nutzer zu machen, die mit Geodatenbanken arbeiten.

    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.