«1. Введение
Все, кто пробовал обновиться до Java 9, вероятно, сталкивались с ошибкой NoClassDefFoundError при компиляции кода, который ранее работал в более ранних версиях Java.
В этой статье мы рассмотрим общий отсутствующий класс JAXBException и различные способы его решения. Приведенные здесь решения обычно применимы к любому классу, который может отсутствовать при обновлении до Java 9.
2. Почему Java 9 не может найти JAXBException?
Одной из наиболее обсуждаемых особенностей Java 9 является модульная система. Целью модульной системы Java 9 является разделение основных классов JVM и связанных проектов на отдельные модули. Это помогает нам создавать приложения меньшего размера за счет включения только минимально необходимых классов для запуска.
Недостатком является то, что многие классы больше не доступны в пути к классам по умолчанию. В этом случае класс JAXBException можно найти в одном из новых модулей Jakarta EE с именем java.xml.bind. Поскольку этот модуль не требуется основной среде выполнения Java, по умолчанию он недоступен в пути к классам.
Попытка запустить приложение, использующее JAXBException, приведет к:
NoClassDefFoundError: javax/xml/bind/JAXBException
Чтобы обойти это, мы должны включить модуль java.xml.bind. Как мы увидим ниже, есть несколько способов сделать это.
3. Краткосрочное решение
Самый быстрый способ убедиться, что классы JAXB API доступны приложению, — добавить аргумент командной строки add-modules:
--add-modules java.xml.bind
Однако, это не может быть хорошим решением по нескольким причинам.
Во-первых, аргумент –add-modules также является новым в Java 9. Для приложений, которые должны работать на нескольких версиях Java, это создает некоторые проблемы. Нам пришлось бы поддерживать несколько наборов файлов сборки, по одному для каждой версии Java, на которой работает приложение.
Чтобы обойти это, мы также можем использовать аргумент командной строки -XX:+IgnoreUnrecognizedVMOptions для старых компиляторов Java.
Однако это означает, что любая опечатка или неправильно написанный аргумент не будут доведены до нашего сведения. Например, если мы попытаемся установить минимальный или максимальный размер кучи и опечатаемся в имени аргумента, мы не получим предупреждение. Наше приложение все равно запустится, но оно будет работать с другой конфигурацией, чем мы ожидаем.
Во-вторых, опция —add-modules будет объявлена устаревшей в будущем выпуске Java. Это означает, что в какой-то момент после обновления до новой версии Java мы столкнемся с той же проблемой использования неизвестного аргумента командной строки и должны будем решить эту проблему снова.
4. Долгосрочное решение
Существует лучший подход, который будет работать в разных версиях Java и не сломается в будущих версиях.
Решение состоит в том, чтобы использовать инструмент управления зависимостями, такой как Maven. При таком подходе мы бы добавили библиотеку API JAXB в качестве зависимости, как и любую другую библиотеку:
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
Указанная выше библиотека содержит только классы API JAXB, включая JAXBException. В зависимости от приложения нам может понадобиться включить другие модули.
Также имейте в виду, что имена артефактов Maven могут отличаться от имен модулей Java 9, как в случае с JAXB API. Его можно найти на Maven Central.
5. Заключение
Модульная система Java 9 обеспечивает ряд преимуществ, таких как уменьшение размера приложения и повышение производительности.
Однако это также приводит к некоторым непредвиденным последствиям. При обновлении до Java 9 важно понять, какие модули действительно требуются приложению, и предпринять шаги, чтобы убедиться, что они доступны в пути к классам.