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:
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...
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...
Vorhaben 2020
03.01.2020
Genau wie letztes Jahr habe ich auch dieses Jahr wieder ein "Listche" verfasst, um mir all die interessanten Vorhaben zu notieren, die ich mit mittlerem zeitlichen Horizont anzugehen gedenke.
Weiterlesen...Android Basteln C und C++ Chaos Datenbanken Docker dWb+ ESP Wifi Garten Geo Go GUI Gui Hardware Java Jupyter Komponenten Links Linux Markdown Markup Music Numerik OpenSource PKI-X.509-CA Python QBrowser Rants Raspi Revisited Security Software-Test sQLshell TeleGrafana Verschiedenes Video Virtualisierung Windows Upcoming...
In eigener Sache...
Weiterlesen...Nach dem ersten Teil von mir als interessant eingestufter Vorträge des Chaos Communication Congress 2024 hier nun die Nachlese
Weiterlesen...Nach dem So - wie auch im letzten Jahr: Meine Empfehlungen für Vorträge vom Chaos Communication Congress 2024 - vulgo: 38c3:
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.