Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Es gibt keine One-Size-fits-All-Lösung, um Code von Java 8 zu Java 11 zu übertragen. Bei einer nicht trivialen Anwendung kann der Wechsel von Java 8 zu Java 11 eine erhebliche Menge an Arbeit sein. Mögliche Probleme sind die entfernte API, veraltete Pakete, die Verwendung der internen API, Änderungen an Klassenladeprogramme und Änderungen an der Garbage Collection.
Im Allgemeinen bestehen die Ansätze darin, auf Java 11 ohne erneutes Kompilieren auszuführen oder zuerst mit JDK 11 zu kompilieren. Wenn das Ziel darin besteht, eine Anwendung so schnell wie möglich zu starten, ist es häufig der beste Ansatz, auf Java 11 auszuführen. Für eine Bibliothek soll ein Artefakt veröffentlicht werden, das mit JDK 11 kompiliert und getestet wird.
Der Umstieg auf Java 11 lohnt sich. Seit Java 8 wurden neue Features hinzugefügt und Verbesserungen vorgenommen. Diese Features und Verbesserungen verbessern den Start, die Leistung, die Speicherauslastung und bieten eine bessere Integration in Container. Und es gibt Ergänzungen und Änderungen an der API, die die Produktivität der Entwickler verbessern.
Dieses Dokument berührt Tools zum Überprüfen von Code. Außerdem werden Probleme behandelt, die möglicherweise auftreten, und Empfehlungen für die Lösung. Sie sollten auch andere Leitfäden lesen, z. B. den Oracle JDK-Migrationsleitfaden. Wie man vorhandenen Code modular gestalten kann, wird hier nicht behandelt.
Die Toolbox
Java 11 verfügt über zwei Tools, jdeprscan und jdeps, die nützlich sind, um potenzielle Probleme zu ergründen. Diese Tools können auf vorhandene Klassen- oder Jardateien ausgeführt werden. Sie können den Übergangsaufwand bewerten, ohne neu kompilieren zu müssen.
jdeprscan sucht nach der Verwendung veralteter oder entfernter API. Die Verwendung der veralteten API ist kein Blockierungsproblem, sondern etwas, das untersucht werden soll. Gibt es eine aktualisierte Jar-Datei? Müssen Sie ein Problem protokollieren, um die Verwendung veralteter API zu beheben? Die Verwendung der entfernten API ist ein Blockierungsproblem, das behoben werden muss, bevor Sie versuchen, auf Java 11 auszuführen.
jdeps, eine Java-Klassenabhängigkeitsanalyse. Bei Verwendung mit der --jdk-internals
Option teilt jdeps Ihnen mit, welche Klasse von der internen API abhängt. Sie können weiterhin interne API in Java 11 verwenden, aber das Ersetzen der Verwendung sollte eine Priorität sein. Die OpenJDK-Wiki-Seite Java Dependency Analysis Tool hat empfohlene Alternativen für einige häufig verwendete interne JDK-APIs.
Es gibt jdeps und jdeprscan Plugins für Gradle und Maven. Es wird empfohlen, diese Tools zu Ihren Buildskripts hinzuzufügen.
Werkzeug | Gradle-Plug-In | Maven-Plug-In |
---|---|---|
jdeps | jdeps-gradle-plugin | Apache Maven JDeps Plugin |
jdeprscan | jdeprscan-gradle-plugin | Apache Maven JDeprScan Plugin |
Der Java-Compiler selbst, Javac, ist ein weiteres Tool in Ihrer Toolbox. Die Warnungen und Fehler, die Sie von jdeprscan erhalten, und jdeps kommen aus dem Compiler. Der Vorteil der Verwendung von jdeprscan und jdeps besteht darin, dass Sie diese Tools über vorhandene Jars und Klassendateien ausführen können, einschließlich Drittanbieterbibliotheken.
Was jdeprscan und jdeps nicht tun können, ist vor der Nutzung der Reflexion zum Zugriff auf eine gekapselte API zu warnen. Der reflektierende Zugriff wird zur Laufzeit überprüft. Letztendlich müssen Sie den Code auf Java 11 ausführen, um sicher zu wissen.
Die Nutzung von jdeprscan
Die einfachste Möglichkeit, jdeprscan zu verwenden, besteht darin, ihm eine Jar-Datei aus einem vorhandenen Build zu geben. Sie können ihm auch ein Verzeichnis, z. B. das Compilerausgabeverzeichnis oder einen einzelnen Klassennamen, zuweisen. Verwenden Sie die --release 11
Option, um die vollständigste Liste der veralteten API abzurufen. Wenn Sie priorisieren möchten, welche veraltete API Sie angehen sollten, setzen Sie die Einstellung zurück auf --release 8
. DIE API, die in Java 8 veraltet war, wird wahrscheinlich früher entfernt als die API, die in letzter Zeit veraltet ist.
jdeprscan --release 11 my-application.jar
Das jdeprscan-Tool generiert eine Fehlermeldung, wenn beim Beheben einer abhängigen Klasse Probleme auftreten.
Beispiel: error: cannot find class org/apache/logging/log4j/Logger
. Das Hinzufügen abhängiger Klassen zum --class-path
oder das Verwenden des Anwendungsklassenpfads wird empfohlen, aber das Tool setzt den Scan ohne dies fort.
Das Argument lautet "--class-path". Es funktionieren keine anderen Variationen des Klassenpfadarguments.
jdeprscan --release 11 --class-path log4j-api-2.13.0.jar my-application.jar
error: cannot find class sun/misc/BASE64Encoder
class com/company/Util uses deprecated method java/lang/Double::<init>(D)V
Diese Ausgabe gibt an, dass die com.company.Util
Klasse einen veralteten Konstruktor der java.lang.Double
Klasse aufruft. Der Javadoc wird eine API empfehlen, die anstelle der veralteten API verwendet werden soll.
error: cannot find class sun/misc/BASE64Encoder
kann nicht gelöst werden, da die API entfernt wurde. Seit Java 8 sollte java.util.Base64
verwendet werden.
Führen Sie die Ausführung jdeprscan --release 11 --list
aus, um zu erfahren, welche API seit Java 8 veraltet ist.
Führen Sie zum Abrufen einer Liste der entfernten API aus jdeprscan --release 11 --list --for-removal
.
Verwenden von jdeps
Verwenden Sie jdeps, mit der Option, Abhängigkeiten von der --jdk-internals
internen JDK-API zu finden. Für dieses Beispiel ist die Befehlszeilenoption --multi-release 11
erforderlich, da log4j-core-2.13.0.jar eine Jar-Datei mit mehreren Versionen ist.
Ohne diese Option gibt jdeps eine Warnung aus, wenn es eine Multi-Release-Jar-Datei findet. Die Option gibt an, welche Version von Klassendateien überprüft werden soll.
jdeps --jdk-internals --multi-release 11 --class-path log4j-core-2.13.0.jar my-application.jar
Util.class -> JDK removed internal API
Util.class -> jdk.base
Util.class -> jdk.unsupported
com.company.Util -> sun.misc.BASE64Encoder JDK internal API (JDK removed internal API)
com.company.Util -> sun.misc.Unsafe JDK internal API (jdk.unsupported)
com.company.Util -> sun.nio.ch.Util JDK internal API (java.base)
Warning: JDK internal APIs are unsupported and private to JDK implementation that are
subject to be removed or changed incompatibly and could break your application.
Please modify your code to eliminate dependence on any JDK internal APIs.
For the most recent update on JDK internal API replacements, please check:
https://wiki.openjdk.java.net/display/JDK8/Java+Dependency+Analysis+Tool
JDK Internal API Suggested Replacement
---------------- ---------------------
sun.misc.BASE64Encoder Use java.util.Base64 @since 1.8
sun.misc.Unsafe See http://openjdk.java.net/jeps/260
Die Ausgabe gibt einige gute Ratschläge zur Beseitigung der Verwendung der internen JDK-API! Wenn möglich, wird die Ersetzungs-API vorgeschlagen. Der Name des Moduls, in dem das Paket gekapselt ist, wird in den Klammern angegeben. Der Modulname kann mit --add-exports
oder --add-opens
verwendet werden, wenn es erforderlich ist, um die Kapselung explizit zu durchbrechen.
Die Verwendung von sun.misc.BASE64Encoder oder sun.misc.BASE64Decoder führt zu einem java.lang.NoClassDefFoundError in Java 11. Code, der diese APIs verwendet, muss geändert werden, um java.util.Base64 zu verwenden.
Versuchen Sie, die Verwendung von APIs, die aus dem Modul jdk.unsupported stammen, zu beseitigen. DIE API dieses Moduls referenziert JDK Enhancement Proposal (JEP) 260 als vorgeschlagenen Ersatz. Kurz gesagt, JEP 260 sagt, dass die Verwendung der internen API unterstützt wird, bis die Ersetzungs-API verfügbar ist. Obwohl Ihr Code möglicherweise die interne JDK-API verwendet, wird er zumindest eine Zeit lang ausgeführt. Sehen Sie sich JEP 260 an, da sie auf Ersetzungen für einige interne API verweist. Variable Handles können z.B. anstelle einiger sun.misc.Unsafe API verwendet werden.
jdeps kann mehr als nur nach der Verwendung von JDK-Interna suchen. Es ist ein nützliches Tool zum Analysieren von Abhängigkeiten und zum Generieren einer Modul-Info-Dateien. Sehen Sie sich die Dokumentation für weitere Informationen an.
Verwenden von Javac
Das Kompilieren mit JDK 11 erfordert Updates zum Erstellen von Skripts, Tools, Testframeworks und enthaltenen Bibliotheken. Verwenden Sie die -Xlint:unchecked
Option für Javac , um details zur Verwendung der internen JDK-API und anderer Warnungen abzurufen. Es kann auch erforderlich sein, --add-opens
oder --add-reads
zu verwenden, um gekapselte Pakete für den Compiler verfügbar zu machen (siehe JEP 261).
Für Bibliotheken kann das Verpacken als JAR-Datei mit mehreren Releases genutzt werden. Multi-Release-Jar-Dateien ermöglichen Es Ihnen, sowohl Java 8- als auch Java 11-Laufzeiten aus derselben Jar-Datei zu unterstützen. Sie fügen dem Build Komplexität hinzu. Das Erstellen von Multi-Release-JAR-Dateien geht über den Umfang dieses Dokuments hinaus.
Ausführen auf Java 11
Die meisten Anwendungen sollten ohne Änderung auf Java 11 ausgeführt werden. Der erste Versuch besteht darin, auf Java 11 auszuführen, ohne den Code neu zu kompilieren. Mit dieser Ausführung soll ermittelt werden, welche Warnungen und Fehler sich dabei ergeben. Bei diesem Ansatz
Die Ausführung der Anwendung auf Java 11 beschleunigen, indem man sich auf das notwendige Minimum konzentriert.
Die meisten probleme, die auftreten können, können behoben werden, ohne code neu kompilieren zu müssen.
Wenn ein Problem im Code behoben werden muss, nehmen Sie die Korrektur vor, kompilieren Sie aber weiterhin mit JDK 8. Wenn möglich, arbeiten Sie daran, die Anwendung mit Version 11 java
, bevor Sie mit JDK 11 kompilieren.
Überprüfen von Befehlszeilenoptionen
Führen Sie vor der Ausführung auf Java 11 eine schnelle Überprüfung der Befehlszeilenoptionen durch. Die entfernten Optionen führen dazu, dass der virtuelle Java-Computer (JVM) beendet wird. Diese Prüfung ist besonders wichtig, wenn Sie GC-Protokollierungsoptionen verwenden, da sie sich drastisch von Java 8 geändert haben. Das JaCoLine-Tool eignet sich gut, um Probleme mit den Befehlszeilenoptionen zu erkennen.
Überprüfen von Drittanbieterbibliotheken
Eine potenzielle Ursache für Probleme sind Bibliotheken von Drittanbietern, die Sie nicht steuern. Sie können Bibliotheken von Drittanbietern proaktiv auf neuere Versionen aktualisieren. Oder Sie können sehen, was bei der Ausführung der Anwendung abfällt, und nur diese Bibliotheken aktualisieren, die erforderlich sind. Das Problem beim Aktualisieren aller Bibliotheken auf eine aktuelle Version besteht darin, dass es schwieriger wird, die Ursache zu finden, wenn in der Anwendung ein Fehler auftritt. Ist der Fehler aufgrund einer aktualisierten Bibliothek aufgetreten? Oder wurde der Fehler durch einige Änderungen in der Laufzeit verursacht? Das Problem, nur das Erforderliche zu aktualisieren, besteht darin, dass es mehrere Iterationen dauern kann, um das Problem zu lösen.
Es wird empfohlen, möglichst wenige Änderungen vorzunehmen und Drittanbieterbibliotheken separat zu aktualisieren. Wenn Sie eine Drittanbieterbibliothek aktualisieren, benötigen Sie häufiger als nicht die neueste und größte Version, die mit Java 11 kompatibel ist. Je nachdem, wie weit Ihre aktuelle Version zurückliegt, könnten Sie in Betracht ziehen, einen vorsichtigeren Ansatz zu wählen und ein Upgrade auf die erste mit Java 9+ kompatible Version durchzuführen.
Zusätzlich zur Betrachtung der Versionshinweise können Sie jdeps und jdeprscan verwenden, um die Jar-Datei zu bewerten. Darüber hinaus verwaltet die OpenJDK-Qualitätsgruppe eine Wiki-Seite zur Qualität der Öffentlichkeitsarbeit , auf der der Status der Tests vieler Free Open Source Software (FOSS)-Projekte für Versionen von OpenJDK aufgeführt ist.
Explizites Festlegen der Garbage Collection
Der Parallel Garbage Collector (Parallel GC) ist der Standard-GC in Java 8. Wenn die Anwendung den Standardwert verwendet, sollte die GC explizit mit der Befehlszeilenoption -XX:+UseParallelGC
festgelegt werden.
In Java 9 wurde die Standardeinstellung in „Garbage First Garbage Collector“ (G1GC) geändert. Um einen fairen Vergleich einer Anwendung zu erzielen, die auf Java 8 und Java 11 ausgeführt wird, müssen die GC-Einstellungen identisch sein. Das Experimentieren mit den GC-Einstellungen sollte zurückgestellt werden, bis die Anwendung auf Java 11 überprüft wurde.
Explizite Festlegung von Standardoptionen
Bei der Ausführung auf der HotSpot-VM führt das Festlegen der Befehlszeilenoption -XX:+PrintCommandLineFlags
dazu, dass die Werte der von der VM festgelegten Optionen ausgegeben werden. Dies gilt vor allem für die Standardeinstellungen, die für die GC festgelegt wurden.
Verwenden Sie dieses Flag für die Ausführung unter Java 8 und die ausgegebenen Optionen für die Ausführung unter Java 11.
Die Standardwerte sind für Version 8 und 11 größtenteils identisch. Die Verwendung der Einstellungen von 8 stellt jedoch die Parität sicher.
Das Festlegen der Befehlszeilenoption --illegal-access=warn
wird empfohlen.
In Java 11 führt die Verwendung der Spiegelung für den Zugriff auf die JDK-interne API zu einer illegalen reflektierenden Zugriffswarnung.
Standardmäßig wird die Warnung nur für den ersten illegalen Zugriff ausgegeben. Die Einstellung --illegal-access=warn
führt zu einer Warnung bei jedem illegalen reflektierenden Zugriff. Sie können eine größere Zahl von Fällen mit unzulässigem Zugriff ermitteln, wenn die Option auf warn festgelegt ist. Sie erhalten aber auch viele redundante Warnungen.
Sobald die Anwendung auf Java 11 läuft, setzen Sie --illegal-access=deny
ein, um das zukünftige Verhalten der Java-Runtime nachzuahmen. Ab Java 16 lautet --illegal-access=deny
der Standardwert .
Warnhinweise zu ClassLoader
In Java 8 können Sie den System-Class-Loader in einen URLClassLoader
umwandeln. Dies geschieht in der Regel von Anwendungen und Bibliotheken, die Klassen zur Laufzeit in den Klassenpfad einfügen möchten. Die Klassenladehierarchie wurde in Java 11 geändert. Das Systemklassenladeprogramm (auch als Anwendungsklassenladeprogramm bezeichnet) ist jetzt eine interne Klasse.
Beim Umwandeln in URLClassLoader
wird zur Laufzeit eine ClassCastException
ausgelöst. Java 11 verfügt nicht über eine API zum dynamischen Erweitern des Klassenpfads zur Laufzeit. Hierfür kann aber die Reflexion genutzt werden, auch wenn dann die üblichen Einschränkungen in Bezug auf die Nutzung der internen API gelten.
In Java 11 lädt das Startklassenladeprogramm nur Kernmodule. Wenn Sie ein Klassenladeprogramm ohne übergeordnetes Element erstellen, werden ggf. nicht alle Plattformklassen gefunden. In Java 11 müssen Sie in solchen Fällen ClassLoader.getPlatformClassLoader()
anstelle des null
als übergeordneten Klassenlader übergeben.
Änderungen von Gebietsschemadaten
Die Standardquelle für Gebietsschemadaten in Java 11 wurde mit JEP 252 auf das Common Locale Data Repository des Unicode-Konsortiums umgestellt.
Dies kann auswirkungen auf lokalisierte Formatierungen haben. Legen Sie bei Bedarf die Systemeigenschaft java.locale.providers=COMPAT,SPI
fest, um das Gebietsschemaverhalten von Java 8 wiederherzustellen.
Potenzielle Probleme
Hier sind einige der häufig auftretenden Probleme. Folgen Sie den Links, um weitere Details zu diesen Problemen zu erhalten.
- Nicht erkannte VM-Option
- Nicht erkannte Option
- VM-Warnung: Option "Ignorieren"
- VM-Warnung: <Option> wurde als veraltet markiert
- WARNUNG: Ein illegaler reflektierender Zugriffsvorgang ist aufgetreten.
- java.lang.reflect.InaccessibleObjectException
- java.lang.NoClassDefFoundError
- -Xbootclasspath/p ist keine unterstützte Option mehr
- java.lang.UnsupportedClassVersionError
Nicht erkannte Optionen
Wenn eine Befehlszeilenoption entfernt wurde, wird die Anwendung Unrecognized option:
oder Unrecognized VM option
gefolgt vom Namen der entfernten Option ausgeben. Eine nicht erkannte Option führt dazu, dass der virtuelle Computer beendet wird.
Optionen, die veraltet, aber nicht entfernt wurden, erzeugen eine VM-Warnung.
Im Allgemeinen haben optionen, die entfernt wurden, keinen Ersatz, und der einzige Rückgriff besteht darin, die Option aus der Befehlszeile zu entfernen. Eine Ausnahme stellen die Optionen für die Protokollierung bei der Garbage Collection dar. Die GC-Protokollierung wurde in Java 9 erneut implementiert , um das einheitliche JVM-Protokollierungsframework zu verwenden. Weitere Informationen finden Sie in "Tabelle 2-2: Zuordnung der veralteten Garbage Collection Logging-Flags zur Xlog-Konfiguration" im Abschnitt Logging mit dem einheitlichen JVM-Logging-Framework aktivieren der Java SE 11-Werkzeugreferenz.
VM-Warnungen
Die Verwendung veralteter Optionen führt zu einer Warnung. Eine Option ist veraltet, wenn sie ersetzt wurde oder nicht mehr nützlich ist. Wie bei entfernten Optionen sollten diese Optionen aus der Befehlszeile entfernt werden.
Die Warnung VM Warning: Option <option> was deprecated
bedeutet, dass die Option weiterhin unterstützt wird, aber diese Unterstützung kann in Zukunft entfernt werden.
Eine Option, die nicht mehr unterstützt wird und die Warnung VM Warning: Ignoring option
generiert.
Optionen, die nicht mehr unterstützt werden, wirken sich nicht auf die Laufzeit aus.
Der VM-Options-Explorer für Webseiten bietet eine vollständige Liste der Optionen, die seit JDK 7 zu Java hinzugefügt oder aus java entfernt wurden.
Fehler: Der virtuelle Java-Computer konnte nicht erstellt werden.
Diese Fehlermeldung wird gedruckt, wenn der JVM auf eine nicht erkannte Option trifft.
WARNUNG: Ein illegaler reflektierender Zugriffsvorgang ist aufgetreten
Wenn Java-Code Spiegelung für den Zugriff auf die interne JDK-API verwendet, gibt die Laufzeit eine illegale reflektierende Zugriffswarnung aus.
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by my.sample.Main (file:/C:/sample/) to method sun.nio.ch.Util.getTemporaryDirectBuffer(int)
WARNING: Please consider reporting this to the maintainers of com.company.Main
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Dies bedeutet, dass ein Modul das Paket, auf das über Reflexion zugegriffen wird, nicht exportiert hat. Das Paket wird im Modul gekapselt und ist im Grunde interne API. Die Warnung kann ignoriert werden, um einen ersten Schritt zur Inbetriebnahme mit Java 11 zu machen. Die Java 11-Laufzeit ermöglicht den reflektierenden Zugriff, sodass Legacycode weiterhin funktioniert.
Um diese Warnung zu beheben, suchen Sie nach aktualisiertem Code, der die interne API nicht verwendet. Wenn das Problem nicht mit aktualisiertem Code behoben werden kann, kann entweder die --add-exports
Befehlszeilenoption oder die --add-opens
Befehlszeilenoption verwendet werden, um den Zugriff auf das Paket zu öffnen.
Diese Optionen ermöglichen den Zugriff auf nicht exportierende Typen eines Moduls aus einem anderen Modul.
Mit --add-exports
der Option kann das Zielmodul auf die öffentlichen Typen des benannten Pakets des Quellmoduls zugreifen. Es kommt auch vor, dass im Code setAccessible(true)
verwendet wird, um auf nicht öffentliche Member und die API zuzugreifen. Dies wird als tiefe Reflexion bezeichnet. Verwenden Sie in diesem Fall --add-opens
, um Ihrem Code Zugriff auf die nicht-öffentlichen Mitglieder eines Pakets zu geben. Wenn Sie sich nicht sicher sind, ob Sie --add-exports oder --add-opens verwenden sollen, beginnen Sie mit --add-exports.
Die Optionen --add-exports
oder --add-opens
sollten als Notlösung betrachtet werden, nicht als langfristige Lösung.
Durch die Verwendung dieser Optionen wird die Kapselung des Modulsystems unterbrochen, wodurch die JDK-interne API nicht verwendet wird. Wenn die interne API entfernt oder geändert wird, schlägt die Anwendung fehl. Der reflektierende Zugriff wird in Java 16 verweigert, sofern er nicht mit Befehlszeilenoptionen wie --add-opens
aktiviert wird.
Um das zukünftige Verhalten nachzuahmen, verwenden Sie --illegal-access=deny
in der Befehlszeile.
Die Warnung im obigen Beispiel wird ausgegeben, da das sun.nio.ch
Paket nicht vom java.base
Modul exportiert wird. Mit anderen Worten, es gibt keine exports sun.nio.ch;
in der module-info.java
Datei des Moduls java.base
. Sie können dies mit --add-exports=java.base/sun.nio.ch=ALL-UNNAMED
lösen.
Klassen, die in einem Modul nicht definiert sind, gehören implizit zum unbenannten Modul, buchstäblich benannt ALL-UNNAMED
.
java.lang.reflect.InaccessibleObjectException
Diese Ausnahme gibt an, dass Sie versuchen, ein Feld oder eine Methode einer gekapselten Klasse aufzurufen setAccessible(true)
.
Unter Umständen erhalten Sie auch eine Warnung zu einem unzulässigen reflektierenden Zugriff. Verwenden Sie die --add-opens
Option, um Ihrem Code Zugriff auf die nicht öffentlichen Mitglieder eines Pakets zu gewähren. Die Ausnahmemeldung teilt Ihnen mit, dass das Modul das Paket für das Modul, das versucht, setAccessible aufzurufen, nicht öffnet. Wenn es sich um ein „nicht benanntes Modul“ handelt, sollten Sie UNNAMED-MODULE
als Zielmodul in der Option --add-opens verwenden.
java.lang.reflect.InaccessibleObjectException: Unable to make field private final java.util.ArrayList jdk.internal.loader.URLClassPath.loaders accessible:
module java.base does not "opens jdk.internal.loader" to unnamed module @6442b0a6
$ java --add-opens=java.base/jdk.internal.loader=UNNAMED-MODULE example.Main
java.lang.NoClassDefFoundError
NoClassDefFoundError wird höchstwahrscheinlich durch ein geteiltes Paket oder durch Verweisen auf entfernte Module verursacht.
NoClassDefFoundError aufgrund von geteilten Paketen
Ein geteiltes Paket ist der Zeitpunkt, an dem ein Paket in mehr als einer Bibliothek gefunden wird. Das Symptom eines Split-Package-Problems ist, dass eine Klasse, die Sie kennen, auf dem Klassenpfad nicht gefunden wird.
Dieses Problem tritt nur bei Verwendung des Modulpfads auf. Das Java-Modulsystem optimiert die Klassensuche, indem ein Paket auf ein benanntes Modul beschränkt wird. Die Laufzeit gibt dem Modulpfad vorrang vor dem Klassenpfad, wenn eine Klassensuche ausgeführt wird. Wenn ein Paket zwischen einem Modul und dem Klassenpfad aufgeteilt wird, wird nur das Modul zum Nachschlagen der Klasse verwendet. Dies kann zu Fehlern vom Typ NoClassDefFound
führen.
Eine einfache Möglichkeit, nach einem geteilten Paket zu suchen, besteht darin, den Modulpfad und den Klassenpfad in jdeps zu verbinden und den Pfad zu Ihren Anwendungsklassendateien als <Pfad> zu verwenden. Wenn ein geteiltes Paket vorhanden ist, gibt jdeps eine Warnung aus: Warning: split package: <package-name> <module-path> <split-path>
.
Dieses Problem kann behoben werden, indem das geteilte Paket mithilfe von --patch-module <module-name>=<path>[,<path>]
zum benannten Modul hinzugefügt wird.
Ein "NoClassDefFoundError", verursacht durch die Verwendung von Java EE- oder CORBA-Modulen
Wenn die Anwendung auf Java 8 ausgeführt wird, aber eine java.lang.NoClassDefFoundError
oder eine java.lang.ClassNotFoundException
auslöst, ist es wahrscheinlich, dass die Anwendung ein Paket aus den Java EE- oder CORBA-Modulen verwendet.
Diese Module wurden in Java 9 veraltet und in Java 11 entfernt.
Um das Problem zu beheben, fügen Sie Ihrem Projekt eine Laufzeitabhängigkeit hinzu.
Modul entfernt | Betroffenes Paket | Vorgeschlagene Abhängigkeit |
---|---|---|
Java-API für XML-Webdienste (JAX-WS) | java.xmlWS | JAX WS RI Runtime |
Java-Architektur für XML-Bindung (JAXB) | java.xml.bind | JAXB Runtime |
JavaBeans Activation Framework (JAV) | java.activation | JavaBeans (TM) Activation Framework |
Allgemeine Anmerkungen | java.xml.ws.annotation | Javax-Anmerkungs-API |
Common Object Request Broker Architecture (CORBA) | java.corba | GlassFish CORBA ORB |
Java Transaction API (JTA) | java.transaction | Java Transaction API |
-Xbootclasspath/p ist keine unterstützte Option mehr
Der Support für -Xbootclasspath/p
wurde entfernt. Verwenden Sie stattdessen --patch-module
. Die Option "-patch-module " wird in JEP 261 beschrieben. Suchen Sie nach dem Abschnitt mit der Bezeichnung "Patching-Modulinhalt".
--patch-module kann mit javac und mit Java verwendet werden, um die Klassen in einem Modul außer Kraft zu setzen oder zu erweitern.
Im Wesentlichen fügt --patch-module das Patchmodul in die Klassensuche des Modulsystems ein. Das Modulsystem übernimmt zuerst die Klasse aus dem Patchmodul. Dies hat denselben Effekt wie das Voranstellen des Bootclasspaths in Java 8.
UnsupportedClassVersionError
Diese Ausnahme bedeutet, dass Sie Versuchen, Code auszuführen, der mit einer späteren Version von Java in einer früheren Version von Java kompiliert wurde. Sie arbeiten beispielsweise mit Java 11 und einem Jar, das mit JDK 13 kompiliert wurde.
Java-Version | Klassendateiformat-Version |
---|---|
8 | 52 |
9 | 53 |
10 | 54 |
11 | 55 |
12 | 56 |
13 | 57 |
Nächste Schritte
Sobald die Anwendung auf Java 11 ausgeführt wird, sollten Sie in Betracht ziehen, Bibliotheken vom Klassenpfad und auf den Modulpfad zu verschieben. Suchen Sie nach aktualisierten Versionen der Bibliotheken, von derEn Anwendung abhängig ist. Wählen Sie, falls verfügbar, modulare Bibliotheken aus. Verwenden Sie den Modulpfad so weit wie möglich, auch wenn Sie nicht planen, Module in Ihrer Anwendung zu verwenden. Die Verwendung des Modulpfads bietet eine bessere Leistung beim Laden von Klassen als der Klassenpfad.