Почему Java кричит «NoClassDefFoundError: javax/xml/bind/JAXBException» и что с этим делать в 2025?
Вы когда-нибудь сталкивались с ситуацией, когда ваше Java-приложение, которое ещё вчера работало как часы, сегодня падает с пугающей ошибкой java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException? Если да — вы не одиноки. Этот вопрос собрал тысячи просмотров на Stack Overflow, и спрос на решение не падает даже в 2025 году. Дело в том, что проблема связана с фундаментальными изменениями в экосистеме Java, которые произошли несколько лет назад, но до сих пор аукаются разработчикам.
В этой статье мы не просто дадим «рыбу» — мы разберём, почему возникает эта ошибка, и покажем три надёжных способа её исправить. Вы узнаете, как правильно настроить Maven, Gradle или JVM-аргументы, чтобы ваше приложение снова заработало. Поехали!
Корень зла: Java 9 и модульная система
Всё началось с Java 9 (выпущенной в 2017 году). В этой версии Oracle внедрила модульную систему (Project Jigsaw). Многие пакеты, которые раньше были частью стандартной библиотеки (JDK), были вынесены в отдельные модули или удалены вовсе. Одним из таких «изгоев» стал пакет javax.xml.bind (JAXB — Java Architecture for XML Binding).
В Java 8 и старше JAXB был доступен «из коробки». Начиная с Java 9, он стал опциональным. А в Java 11 его и вовсе удалили из JDK. Если вы пишете код, который использует javax.xml.bind.JAXBContext, JAXBException или Marshaller, и запускаете его на Java 11+, вы гарантированно получите NoClassDefFoundError.
Важно: NoClassDefFoundError отличается от ClassNotFoundException. Первая возникает, когда класс был доступен на этапе компиляции, но исчез во время выполнения. Вторая — когда класс не найден вообще.
Сценарий: как выглядит проблема на практике
Представьте, что у вас есть простой класс для работы с XML:
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class XmlProcessor {
public void convertToXml(Object obj) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(obj.getClass());
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
// ... логика вывода
}
}
Вы компилируете этот код на Java 8 — всё окей. Затем вы обновляете JDK до версии 11 или 17, запускаете приложение и видите:
Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
at XmlProcessor.convertToXml(XmlProcessor.java:6)
...
Знакомо? Теперь давайте решать.
Способ 1: Добавьте JAXB API как внешнюю зависимость (рекомендуемый)
Самый правильный и современный подход — явно указать, что ваше приложение использует JAXB. Для этого нужно подключить библиотеку через систему сборки (Maven или Gradle).
Для Maven (pom.xml)
Добавьте в <dependencies>:
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>4.0.5</version>
<scope>runtime</scope>
</dependency>
Обратите внимание: с Jakarta EE 9 (июнь 2021) пакет javax.xml.bind переименован в jakarta.xml.bind. Если ваш код старый и использует javax.*, вы можете всё равно использовать jakarta.xml.bind-api — она прозрачно маппится. Но лучше обновить импорты в коде.
Для Gradle (build.gradle)
dependencies {
implementation 'jakarta.xml.bind:jakarta.xml.bind-api:4.0.2'
runtimeOnly 'org.glassfish.jaxb:jaxb-runtime:4.0.5'
}
После добавления зависимостей запустите сборку заново. NoClassDefFoundError исчезнет, потому что JAXB-классы теперь физически присутствуют в classpath.
Способ 2: Используйте JVM-аргумент --add-modules (для Java 9–10)
Этот способ подходит, если вы не можете менять код или систему сборки (например, работаете с легаси-проектом). Он работает на Java 9 и 10, но не работает на Java 11+, так как модуль был удалён.
Просто добавьте при запуске JVM флаг:
java --add-modules java.xml.bind -jar your-app.jar
Или, если вы запускаете из командной строки:
java --add-modules java.xml.bind -cp your-classpath MainClass
Этот флаг подключает модуль java.xml.bind из JDK. Но ещё раз: на Java 11+ модуля нет, поэтому вы получите ошибку «Module java.xml.bind not found».
Способ 3: Переход на альтернативу (JAXB → Jackson или SAX)
Иногда лучший способ решить проблему — не использовать JAXB вообще. В 2025 году это не самая популярная библиотека. Рассмотрите альтернативы:
- Jackson XML — отлично работает с JSON и XML, активно поддерживается.
- SAX / DOM / StAX — стандартные XML-парсеры, встроенные в JDK.
- XStream — простая сериализация в XML.
Пример с Jackson XML (добавьте зависимость jackson-dataformat-xml):
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
public class JacksonXmlProcessor {
private final XmlMapper xmlMapper = new XmlMapper();
public String toXml(Object obj) throws Exception {
return xmlMapper.writeValueAsString(obj);
}
public <T> T fromXml(String xml, Class<T> clazz) throws Exception {
return xmlMapper.readValue(xml, clazz);
}
}
Этот код не зависит от JAXB и будет работать на любой версии Java.
Проверка версии Java и classpath
Прежде чем паниковать, убедитесь, что вы знаете, какая версия Java используется:
java -version
Если вы видите openjdk version "11"