Umzug von JDK8 -> JDK 16:

White_Fox

Top Contributor
Mahlzeit allerseits

Ich bin gerade dabei, mein Projekt von Oracle JDK8 auf Open JDK16 umzubauen. Kurz: Unter JDK8 läuft es ohne Warnung, sobald ich das JDK16 benutze bekomme ich einen Fehler den ich nicht so recht verstehe:

java.lang.reflect.InaccessibleObjectException: Unable to make field private static final long java.util.HashMap.serialVersionUID accessible: module java.base does not "opens java.util" to unnamed module @238989fa
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:357)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:177)
at java.base/java.lang.reflect.Field.setAccessible(Field.java:171)
at objectprocessor.ObjectAssembler.fillMembervariables(ObjectAssembler.java:203)
 

White_Fox

Top Contributor
Dieser verdammte Editor...grml...

Jedenfalls: Die angemeckerte Zeile in objectprocessor.ObjectAssembler.fillMembervariables(ObjectAssembler.java:203) lautet:
Java:
Field f;

//...

f.setAccessible(true);

Warum geht das in JDK16 anscheinend nicht mehr?
 
K

kneitzel

Gast
Du kannst mal probieren, beim Start den folgenden Parameter mit anzugeben:
--add-opens java.base/java.util=ALL-UNNAMED
 

White_Fox

Top Contributor
@kneitzel Danke, das scheint zu funktionieren...jetzt wirft mein Programm aber andere Fehler. Ich weiß zwar was die heißen, aber weiß der Teufel warum jetzt eine NPE kommt weil ich eine Datei einlesen will...

Ist dieser Streß beim Wechsel einer Javaversion eigentlich normal?


Aber das hängt mit dem Module System zusammen:
Ja, das hab ich mir schon gedacht. In der Javadoc zu besagter Methode steht irgendwas davon, daß diese nicht modulübergreifend für private Felder benutzt werden kann oder so.
Aber ich habe noch gar kein Modul erstellt und demzufolge sollte alles automatisch in ein Modul geschmissen werden, wenn ich das richtig verstanden habe.
 
K

kneitzel

Gast
Also so Probleme können beim Wechsel der JDK Version immer kommen. Wir haben nur ein JDK 8 auf OpenJDK 8 Wechsel gemacht und waren am staunen, was da so an Effekten aufgetreten ist :)

Wenn du Details bringst, dann kann man drüber schauen. Wenn es Zugriff auf Resourcen waren (Also Datei aus jar Datei lesen), dann kann da das Modul System Ursache sein. Aber ansonsten sehe ich da erst einmal keinen Punkt, der mir bei Deiner Beschreibung direkt in den Sinn kommt.
 

White_Fox

Top Contributor
Zum Beispiel habe ich folgende Klasse:

Java:
public class SettingsMap extends HashMap<String, UserSettings> implements Documentable{

    private FileDocumentdata documentdata;

    public SettingsMap() {
        this.documentdata = new FileDocumentdata();
    }
   
    @Override
    public FileDocumentdata file() {
        return documentdata;
    }

    @Override
    public void prepareForSerialization() {
        //Do nothing here
    }
}

Diese Klasse hält die Benutzereinstellung verschiedener Benutzer, und ein paar Dateiinformationen (letzter Dateipfad, letzter Hash, und ähnliches). Letztere werden in documentdata gespeichert.

Jetzt passiert folgendes: Beim ersten Programmstart gibt es diese Datei noch nicht, also wird sie erstellt. Aber wenn ich auf die Datei zugreifen will ist documentdata null. Vorher hat das mit Java 8 funktioniert. Die Map ist übrigens auch leer, da müßte aber mindestens ein Datensatz drin sein.

Edit:
Es scheint an meiner ObjectProcessorklasse zu liegen...dieses umständliche Riesending, wo ich damals einen Haufen Fragen über Reflexion gestellt habe. Zumindest läuft deren Unittest nicht durch und wirft in fast jedem Test Fehler. Mal sehen woran es liegt.
 
Zuletzt bearbeitet:

White_Fox

Top Contributor
Ich hätte mal noch eine Frage @kneitzel : Was macht der Parameter --add-opens java.base/java.util=ALL-UNNAMED eigentlich genau?
Soweit ich das sehe, wird ein Teil der Java-Standardbibliothek in einem unbenannten Modul geöffnet.

Aber was passiert da genau?
 

White_Fox

Top Contributor
Hm...ich denke ich habe die Stelle gefunden an der es hakt.

Kurz etwas zur Funktionsweise meines Programms: Ich habe eine Klasse, die Objekte analysiert und alle Informationen über ein Objekt extrahiert - im Wesentlichen dient dies dazu, ein Objekt in lauter Bytes zu zerlegen und das Objekt später wieder zu haben. Im Wesentlichen habe ich damit eine Serialisierung gebaut. (Und ja, das hatte seine Gründe daß ich das gemacht habe.)

Jetzt bereitet mir der Deserialisierungsprozess Ärger. Die Deserialisierung funktioniert - kurz gesagt - folgendermaßen:
1. Objekte instanzieren (also das Objekt das eigentlich serialisiert wurde, sowie alle Objekte in Membervariablen, und Objekte in deren Membervariablen, usw.)
2. Alle Memberfelder aller Objekte durchpflügen und auf die entsprechenden Werte setzen. Also primitive Datentypen oder eben wieder andere Objekte, die zuvor instanziert wurden.

Die Säge klemmt jetzt in Schritt 2, und es hat was mit dem Zugriff auf private Memberfelder zu tun. Der Code für den Feldzugriff sieht wie folgt aus:
Java:
for (MemberfieldDescriptor member : members) {
    
    //...
    
    f.setAccessible(true);
    if (!isFieldAccessible(f, instance)) {
        continue;
    }
    f.set(instance, value);
}
Das Problem ist, das mir die Prüfung isFieldAccessible() nun immer ein Nein ausgibt - vorher war die Prüfung noch unproblematisch. Die Prüfung sollte ursprünglich mal Probleme mit gesondert gesicherten Feldern abfangen, aber jetzt ist sie mir zum Verhängnis geworden.

Wenn ich die Prüfung auskommentiere, laufen wieder fast alle Tests durch - außer ein Test bei dem ich meinen ObjectProcessor speziell an einer HashMap teste. Dieser Test kommt direkt mit einer java.lang.IllegalAccessException: Can not set static final long field java.util.HashMap.serialVersionUID to java.lang.Long zurück.

Hat da jemand eine Idee?
 

mihe7

Top Contributor
Ist dieser Streß beim Wechsel einer Javaversion eigentlich normal?

Hey, das ist kein Stress, das nennt man heute Produktivität:
https://www.oracle.com/de/corporate/features/understanding-java-9-modules.html hat gesagt.:
"Modularity—the result of Project Jigsaw—helps developers at all levels be more productive as they build, maintain, and evolve software systems, especially large systems."
ROFL.
 

White_Fox

Top Contributor
Ok, ich denke ich habe so etwas Ähnliches wie eine erste Antwort dank dem Link von kneitzel:

Prior to Java 9, deep reflection was allowed on members of all types-JDK internals and your types.
To deliver on the backward compatibility, Java 9 allows deep reflection on members of JDK internal types from the code in unnamed modules.
Upon the first such illegal access, the runtime issues a warning.
Such illegal access to JDK internal types will be disallowed in a future version.
If such applications are modularized in Java 9, the code using illegal reflective access to JDK internals needs to be fixed.

Also: Deep Reflection nur noch in unbenannten Modulen. Na toll...

Aber dann verstehe ich die IllegalAccessException immer noch nicht...wieso kommt die bei der HashMap? Und sonst gehts? Muß ich die Standardbibliothek auch noch irgendwie in ein unbenanntes Modul kriegen (und wenn ja: wie?)?
 

LimDul

Top Contributor
Ich erinnere mich da an einen Vortrag von der Javaland dieses Jahr, der die Umstellung eines größeren Projekt auf Module beschrieb. Vom Hölzchen aufs Stöckchen aufs .... War durchaus Arbeit mit viel Googlen :)
 

White_Fox

Top Contributor
Ja...ich vermute fast, daß der Name Jigsaw intern wohl ein Spottname war, den irgendein Marketingstratege falsch oder gar nicht verstanden hat. Jedenfalls scheint er die Folgen für bestehende Projekte recht gut zu beschreiben.

Wenn das bei so einem kleinen Projekt wie meinem schon so ein Aufriss wird, ich will gar nicht wissen was das mit ernsthaft großen Projekten macht. Wenn ich da an die TableView aus JavaFX denke will ich gar nicht wissen, wo Reflexion noch überall für welche abenteuerlichen Zwecke benutzt wurde.

Kein Wunder, daß Java 8 so lange unterstützt wird/wurde.
 

mrBrown

Super-Moderator
Mitarbeiter
Je nach Projekt kann die Migration alles sein von nur Dependencies updaten bis zu Dinge komplett umschreiben. Das hängt im wesentlichen davon ab, wie viele Implementationsdetails und nicht-öffentliche Dinge man benutzt.

Wenn man komplett gegen öffentliche APIs programmiert, hat man so gut wie keine Probleme – wenn man dagegen auf interne Dinge zugreift, ist eine Migration schwierig bis gar nicht möglich. Da ist aber weniger das Modulsystem dran schuld, sondern dass man sich auf interne Dinge und darauf, dass sie sich niemals ändern, verlässt. Durch das Modul-System bzw die strengen Restriktionen ab 16 werden die Probleme halt aufgezeigt – und sowas wie die serialVersionUID ändern war schon immer ein Problem, auch wenn es vorher möglich war.


Aber dann verstehe ich die IllegalAccessException immer noch nicht...wieso kommt die bei der HashMap? Und sonst gehts? Muß ich die Standardbibliothek auch noch irgendwie in ein unbenanntes Modul kriegen (und wenn ja: wie?)?
In ein umbenanntes Modul bekommt man das nicht, statt den Fehler irgendwie durch Tricks zu umgehen ist auch eher der falsche Weg – neben dem eindeutigen "du darfst nicht drauf zugreifen" ist das auch ein implizites "selbst wenn Zugriff möglich wäre, könnte sie die interne API jederzeit ändern, auch in einem Patch-Update".

Ganz unabhängig von dem konkreten Problem: eine HashMap so wiederherzustellen wird unweigerlich irgendwann in die Hose gehen. Hashes sind über Instanzen hinweg nicht stabil, dass kann also durchaus passieren, dass eine gespeicherte HashMap nach dem Wiederherstellen zwar gefüllt, aber nicht mehr benutzbar ist. Sichtbar sein dürfte das z.B., wenn man Enums als Keys benutzt.

Der "richtige" Weg wäre dabei eher, die HashMap nur über ihre öffentliche API zu serialisieren.
 

White_Fox

Top Contributor
Ganz unabhängig von dem konkreten Problem: eine HashMap so wiederherzustellen wird unweigerlich irgendwann in die Hose gehen. Hashes sind über Instanzen hinweg nicht stabil, dass kann also durchaus passieren, dass eine gespeicherte HashMap nach dem Wiederherstellen zwar gefüllt, aber nicht mehr benutzbar ist. Sichtbar sein dürfte das z.B., wenn man Enums als Keys benutzt.
Ich weiß - genau dieses Problem hatte ich damit schon, aber das bekomme ich noch gelöst. Bisher hab ich das noch nicht gemacht, weil es noch nicht so dringend war...aber das scheint sich wohl gerade zu ändern. Hm...
 

White_Fox

Top Contributor
Ich weiß. Aber die zugeörigen Objekte in eine frische HashMap zu stopfen sollte ansich nicht weiter schwierig werden. (Oder?)

Und die Inplementierung eines solchen Mechanismus wird nicht schwierig...macht einfach nur Arbeit. Ich wollte eine Möglichkeit schaffen, um Objekte manuell instanzieren zu können - das kann ich dafür nutzen.
 

White_Fox

Top Contributor
Ah...sehr gut, Strings bekommen diese Sonderbehandlung bereits. Und Klassen wie Integer, Long, usw. auch. Glück gehabt. :)

(Aber die anderen JDK-Klassen...nehme ich mir dann vor, wenn es notwendig wird. Sonst werd ich mein Leben lang eine Serialierungsbibliothek warten.)

Edit:
Aber wieso liefert die Prüfung isAccessible() false, wenn ich das Feld offenbar doch bearbeiten kann?
 

White_Fox

Top Contributor
Und weiter gehts...das Problem mit meiner eigenen Klasse hab ich vorläufig gelöst, jetzt macht mir controlsfx denselben Ärger.

Also: neue controlsfx-Version ins Projekt holen. Jetzt gibt es da leider keinen fertigen Bau, sondern ich muß das Gradleprojekt selber bauen - und das will noch nicht.
Wenn ich in der Powershell zum Ordner mit dem controlsfx-Projekt navigiere und den Build mit "gradle init --debug" starte, bricht er mit einer Fehlermeldung ab (Netbeans kommt auch nur mit einer Fehlermeldung zurück).
Die Fehlermeldung deutet darauf hin, daß er mit einem Mavenplugin nicht zurandekommt.
Caused by: org.gradle.api.plugins.UnknownPluginException: Plugin with id 'maven' not found.

Bei einem anderen Buildversuch hat er die gradle.build angemeckert un Zeile 29 verwiesen.
Code:
subprojects {

    apply plugin: 'java'
    apply plugin: 'maven'                        <-- Das ist Zeile 29
    apply plugin: 'org.openjfx.javafxplugin'
    apply from  : '../mavenPublish.gradle'

Hat jemand eine Idee, wie ich das repariert bekomme?
 

White_Fox

Top Contributor
Nein, tatsächlich hab ich hier OpenJDK 16 zu laufen. Und ein "java -version" in der Powershell zeigt auch, das es vernünftig installiert zu sein scheint.

Danke, ich probiere es mal mit Maven.
 

mrBrown

Super-Moderator
Mitarbeiter
Nein, tatsächlich hab ich hier OpenJDK 16 zu laufen. Und ein "java -version" in der Powershell zeigt auch, das es vernünftig installiert zu sein scheint.
Meinte damit, dass du es mal unter Java 15 oder früher versuchen solltest, dass du 16 nutzt hab ich mir schon gedacht :)

16 zum kompilieren benutzen, wenn das Projekt gar nicht 16 nutzt, ist ja eigentlich überflüssig.
 

White_Fox

Top Contributor
Naja, ich will ja auch z.B. die neuen JavaFX-Bibliotheken benutzen. Ich habe neulich festgestellt, daß in denen, die ich aktuell benutze, ein paar Fehlerchen schlummern die in den späteren nicht mehr vorhanden sind. Ich habe zwar nich probiert die mit Java 8 zu kompilieren, aber ich denke so oder so ist Java 8 so langsam ausgereizt. Irgendwo habe ich vor längerer Zeit schonmal den Hinweis bei irgendeienr Bibliothek gesehen, daß Java 8 zwar noch unterstützt, aber nur noch kompatibel gehalten wird und wesentliche Fehlerkorrekturen oder Updates nur noch für die höheren Javaversionen stattfinden.

Und ein paar Dinge aus den neueren Javaversionen sind schon nett, z.B. das var-Schlüsselwort. Das würde die ein oder andere Zeile weitaus kürzer halten und ich bin durchaus neugierig, was da noch für nette neue Werkzeuge sind die ich noch nicht kenne. Da muß doch in all den neuen Javaversionen noch was dazugekommen sein...oder nicht?
 

mrBrown

Super-Moderator
Mitarbeiter
Du vermischt da glaub ich ein paar Dinge:

Und ein paar Dinge aus den neueren Javaversionen sind schon nett, z.B. das var-Schlüsselwort. Das würde die ein oder andere Zeile weitaus kürzer halten und [...]
Dafür muss nur dein eigenes Projekt mit Java 16 kompiliert werden, nicht alle Dependenies.

ich will ja auch z.B. die neuen JavaFX-Bibliotheken benutzen.
JavaFX 16 läuft auch noch mit Java 11, dabei gilt nicht JavaFX-Version == Java-Version.

Gleiches gilt für ControlsFX, das dürfte auch noch mit entweder Java 11 oder 8 kompilierbar sein, und du kannst es trotzdem problemlos in einer Java-Version > 11 nutzen.
 

White_Fox

Top Contributor
Mal eine Frage...weiß jemand wie ich Abhängigkeiten wie
com.sun.javafx.scene.control.behavior.BehaviorBase;
in ein Projekt reinbekomme bzw. diese auflöse?

ControlsFX scheint mit JavaFX 13 zu arbeiten, aber dafür finde ich nix Gebautes, außerdem ist JavaFX es ein Gradleprojekt und das scheint wiederum ein ähnliches Problem wie ControlsFX zu haben (weshalb ich das ja als neues Projekt nachbaue).
Aber weder mit JavaFX11 noch mit JavaFX16 bekomme ich die Abhängigkeiten aufgelöst. Hat jemand eine Idee?
 

mrBrown

Super-Moderator
Mitarbeiter
Mal eine Frage...weiß jemand wie ich Abhängigkeiten wie
com.sun.javafx.scene.control.behavior.BehaviorBase;
in ein Projekt reinbekomme bzw. diese auflöse?

Bekommst du zur Laufzeit einen Fehler, dass die Klasse nicht gefunden wird? Oder noch zur Compile-Zeit?

ControlsFX scheint mit JavaFX 13 zu arbeiten, aber dafür finde ich nix Gebautes
https://mvnrepository.com/artifact/org.openjfx/javafx/13 ?


außerdem ist JavaFX es ein Gradleprojekt und das scheint wiederum ein ähnliches Problem wie ControlsFX zu haben
Wenn du die selbst bauen musst einfach Java 11 nehmen, die Projekte nutzen sowieso nur Java 11, das geht da also völlig problemlos.
 

White_Fox

Top Contributor
Der Fehler kommt schon während der Kompilierzeit.

Ich hab das erstmal als einfaches netbeanseigenes Ant-Projekt aufziehen wollen...aber danke für den Link, vielleicht krieg ich das auch mit Maven zurechtgefummelt.

Edit:
Oder ich nehme einfach Java11...dann bleibt nur noch das Problem mit diesem com.sun.javafx-Zeugs zu lösen. Im Mavenrepo gibt es das nämlich anscheinend nicht mehr.
 
Zuletzt bearbeitet:

White_Fox

Top Contributor
Hehe...mein Projekt läuft wieder.

Ich hab mir dreisterweise einfach den Bau von controlsfx aus deren Mavenrepo heruntergeladen und mir den restlichen Affenzirkus gespart. Warum einfach wenn es auch kompliziert geht...

Danke für eure Hilfe bisher. :)
 

Neue Themen


Oben