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 Codeberg Repositories Mastodon Über mich home xmpp


Vor 5 Jahren hier im Blog

  • Multi-User-WebDAV, Docker, GitHub

    17.11.2019

    Nachdem ich mich in letzter Zeit verstärkt mit Docker und dem zugehörigen Ökosystem beschäftige, habe ich begonnen, verschiedenste Dienste in Containern zu testen um zu sehen, ob in manchen Fällen LXC oder KVM nicht doch die bessere Wahl wäre...

    Weiterlesen...

Neueste Artikel

  • Migration der Webseite und aller OpenSource Projekte

    In eigener Sache...

    Weiterlesen...
  • AutoHideToolbar für Java Swing

    Ich habe eine neue Java Swing Komponente erstellt: Es handelt sich um einen Wrapper für von JToolBar abgeleitete Klassen, die die Werkzeugleiste minimieren und sie nur dann einblenden, wenn der Mauszeiger über ihnen schwebt.

    Weiterlesen...
  • Integration von EBMap4D in die sQLshell

    Ich habe bereits in einem früheren Artikel über meine ersten Erfolge berichtet, der sQLshell auf Basis des bestehenden Codes aus dem Projekt EBMap4D eine bessere Integration für Geo-Daten zu spendieren und entsprechende Abfragen, bzw. deren Ergebnisse auf einer Kartenansicht zu visualisieren.

    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, muss 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 Codeberg-Repositories findet man hier.