Как разрешить java.ленг.Noclassdeffounderror: javax/xml/bind/JAXBException в Java 9

У меня есть код, который использует классы API JAXB, которые были предоставлены как часть JDK в Java 6/7/8. Когда я запускаю тот же код с Java 9, во время выполнения я получаю ошибки, указывающие, что классы JAXB не могут быть найдены.

классы JAXB были предоставлены как часть JDK с Java 6, так почему Java 9 больше не может найти эти классы?

15 ответов


API JAXB считаются API Java EE и поэтому больше не содержатся в пути к классу по умолчанию в Java SE 9. В Java 11 они полностью удалены из JDK.

Java 9 вводит понятия модулей, и по умолчанию java.se модуль aggregate доступен на пути к классу (или, скорее, пути к модулю). Как следует из названия,java.se модуль aggregate делает не Включить API Java EE, которые традиционно были в комплекте с Java 6/7/8.

к счастью, эти API Java EE, которые были предоставлены в JDK 6/7/8, все еще находятся в JDK, но они просто не находятся на пути класса по умолчанию. Дополнительные API Java EE предоставляются в следующих модулях:

java.activation
java.corba
java.transaction
java.xml.bind  << This one contains the JAXB APIs
java.xml.ws
java.xml.ws.annotation

быстрое и грязное решение: (только JDK 9/10)
Чтобы сделать API JAXB доступными во время выполнения, укажите следующий параметр командной строки:
--add-modules java.xml.bind

но мне все еще нужно, чтобы это работало с Java 8!!!
Если вы попытаетесь указать --add-modules со старым JDK он взорвется, потому что это непризнанный вариант. Предлагаю один из двух вариантов:

  1. вы можете условно применить аргумент в сценарии запуска (если он у вас есть), проверив версию JDK, проверив $JAVA_HOME/release на JAVA_VERSION собственность.
  2. вы можете добавить -XX:+IgnoreUnrecognizedVMOptions чтобы JVM молча игнорировал непризнанные параметры, а не взрывался. Но берегись! Любой другой используемые вами args командной строки больше не будут проверяться JVM. Эта опция работает с Oracle / OpenJDK, а также IBM JDK (начиная с JDK 8sr4)

альтернативное быстрое решение: (только JDK 9/10)
Обратите внимание, что вы можете сделать все вышеперечисленные модули Java EE доступными во время выполнения, указав . The java.se.ee модуль является агрегатным модулем, который включает в себя java.se.ee а также выше Java EE API модули.


правильное долгосрочное решение: (все версии JDK)

все перечисленные выше модули API Java EE отмечены @Deprecated(forRemoval=true), потому что они запланировано на на Java 11. Так что --add-module подход не будет работать в Java 11 из коробки.

что вам нужно будет сделать в Java 11 и вперед, это включить свою собственную копию API Java EE на пути к классу или модуле путь. Например, вы можете добавить API JAX-B в качестве зависимости maven следующим образом:

<!-- Java 6 = JAX-B Version 2.0   -->
<!-- Java 7 = JAX-B Version 2.2.3 -->
<!-- Java 8 = JAX-B Version 2.2.8 -->
<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.2.11</version>
</dependency>
<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-core</artifactId>
    <version>2.2.11</version>
</dependency>
<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-impl</artifactId>
    <version>2.2.11</version>
</dependency>
<dependency>
    <groupId>javax.activation</groupId>
    <artifactId>activation</artifactId>
    <version>1.1.1</version>
</dependency>

для получения полной информации о модульности Java см. JEP 261: модуль системы


в моем случае (spring boot fat jar) я просто добавляю следующее в pom.XML.

<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.0</version>
</dependency>

ни одно из этих решений работал для меня в последние JDK версии 9.0.1.

я обнаружил, что этого списка зависимостей достаточно для правильного функционирования, поэтому вы не нужно явно указать --add-module (хотя он указан в pom этих зависимостей). Единственное, что вам нужно, это указать список зависимостей:

<dependencies>
    <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>com.sun.xml.bind</groupId>
        <artifactId>jaxb-impl</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jaxb</groupId>
        <artifactId>jaxb-runtime</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>javax.activation</groupId>
        <artifactId>activation</artifactId>
        <version>1.1.1</version>
    </dependency>
</dependencies>

это сработало для меня:

<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.0</version>
</dependency>
<dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>eclipselink</artifactId>
    <version>2.7.0</version>
</dependency>

обновление

как предложил @Jasper, чтобы избежать зависимости от всей библиотеки EclipseLink, вы также можете просто зависеть от Eclipselink MOXy:

Maven

<dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>org.eclipse.persistence.moxy</artifactId>
    <version>2.7.3</version>
</dependency>

ш

compile group: 'org.eclipse.persistence', name: 'org.eclipse.persistence.moxy', version: '2.7.3'

как зависимости для моего приложения Java 8, которое производит *.jar, который может выполняться как JRE 8, так и JRE 9 без дополнительных аргументов.

In кроме того, это должно быть выполнено где-то до того, как будет использоваться JAXB API:

System.setProperty("javax.xml.bind.JAXBContextFactory", "org.eclipse.persistence.jaxb.JAXBContextFactory");

отлично работает до сих пор, как обходной путь. Не похоже на идеальное решение...


во время компиляции, а также во время выполнения добавьте переключатель --add-modules java.xml.bind

javac --add-modules java.xml.bind <java file name>

java --add-modules java.xml.bind <class file>

хорошее введение JDK 9 модули можно также найти на : https://www.youtube.com/watch?v=KZfbRuvv5qc


можно использовать --add-modules=java.xml.bind опция JVM для добавления модуля привязки xml в среду выполнения JVM.

например: java --add-modules=java.xml.bind XmlTestClass


чтобы решить эту проблему, я импортировал некоторые файлы JAR в мой над файлами и скопируйте их в папку libs в проекте

  • добавить импортированные файлы JAR в Java Build Path

  • для выполнения Java Web Start мы можем использовать предложение Энди Гиберта следующим образом:

    <j2se version="1.6+" 
          java-vm-args="-XX:+IgnoreUnrecognizedVMOptions --add-modules=java.se.ee"/>
    

    обратите внимание на дополнительные " = " в --add-modules. См.этот билет OpenJDK или последнее примечание в разделе "понимание предупреждений о доступе во время выполнения"платформа Java, Стандартное издание Oracle JDK 9 руководство по миграции.


    это сработало для меня. Добавления только JAXB-api было недостаточно.

            <dependency>
                <groupId>javax.xml.bind</groupId>
                <artifactId>jaxb-api</artifactId>
                <version>${jaxb-api.version}</version>
            </dependency>
            <dependency>
                <groupId>com.sun.xml.bind</groupId>
                <artifactId>jaxb-impl</artifactId>
                <version>${jaxb-api.version}</version>
            </dependency>
            <dependency>
                <groupId>com.sun.xml.bind</groupId>
                <artifactId>jaxb-core</artifactId>
                <version>${jaxb-api.version}</version>
            </dependency>
    

    перейдите к своей сборке.gradle и добавьте ниже зависимости для Java 9 или Java 10.

    sourceCompatibility = 10 // You can also decrease your souce compatibility to 1.8 
    
    //java 9+ does not have Jax B Dependents
    
        compile group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.0'
        compile group: 'com.sun.xml.bind', name: 'jaxb-core', version: '2.3.0'
        compile group: 'com.sun.xml.bind', name: 'jaxb-impl', version: '2.3.0'
        compile group: 'javax.activation', name: 'activation', version: '1.1.1'
    

    после какие артефакты я должен использовать для JAXB RI в моем проекте Maven? в Maven, вы можете использовать профиль типа:

    <profile>
        <id>java-9</id>
        <activation>
            <jdk>9</jdk>
        </activation>
        <dependencies>
            <dependency>
                <groupId>org.glassfish.jaxb</groupId>
                <artifactId>jaxb-runtime</artifactId>
                <version>2.3.0</version>
            </dependency>
            <dependency>
                <groupId>javax.activation</groupId>
                <artifactId>activation</artifactId>
                <version>1.1.1</version>
            </dependency>
        </dependencies>
    </profile> 
    

    дерево зависимостей показывает:

    [INFO] +- org.glassfish.jaxb:jaxb-runtime:jar:2.3.0:compile
    [INFO] |  +- org.glassfish.jaxb:jaxb-core:jar:2.3.0:compile
    [INFO] |  |  +- javax.xml.bind:jaxb-api:jar:2.3.0:compile
    [INFO] |  |  +- org.glassfish.jaxb:txw2:jar:2.3.0:compile
    [INFO] |  |  \- com.sun.istack:istack-commons-runtime:jar:3.0.5:compile
    [INFO] |  +- org.jvnet.staxex:stax-ex:jar:1.7.8:compile
    [INFO] |  \- com.sun.xml.fastinfoset:FastInfoset:jar:1.2.13:compile
    [INFO] \- javax.activation:activation:jar:1.1.1:compile
    

    чтобы использовать это в затмении, скажем, кислород.3a Release (4.7.3 a) или более поздней версии, Ctrl-Alt-P или щелкните правой кнопкой мыши на проекте, Maven, затем выберите профиль.


    не ответ, а дополнение: я получил, потому что работает groovysh (Groovy 2.4.13) если JAVA_HOME указывает на установку Java 9 (java version "9.0.1" если быть точным) терпит неудачу:

    java.lang.reflect.InvocationTargetException
            at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
            at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            at java.base/java.lang.reflect.Method.invoke(Method.java:564)
            at org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:107)
            at org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:129)
    Caused by: java.lang.NoClassDefFoundError: Unable to load class groovy.xml.jaxb.JaxbGroovyMethods due to missing dependency javax/xml/bind/JAXBContext
            at org.codehaus.groovy.vmplugin.v5.Java5.configureClassNode(Java5.java:400)
            at org.codehaus.groovy.ast.ClassNode.lazyClassInit(ClassNode.java:277)
            at org.codehaus.groovy.ast.ClassNode.getMethods(ClassNode.java:397)
            ...
            ..
            .
            ..
            ...
            at org.codehaus.groovy.tools.shell.Groovysh.<init>(Groovysh.groovy:135)
            at org.codehaus.groovy.vmplugin.v7.IndyInterface.selectMethod(IndyInterface.java:232)
            at org.codehaus.groovy.tools.shell.Main.<init>(Main.groovy:66)
            at org.codehaus.groovy.vmplugin.v7.IndyInterface.selectMethod(IndyInterface.java:232)
            at org.codehaus.groovy.tools.shell.Main.main(Main.groovy:163)
    ... 6 more
    

    решение было:

    • перейти к проект JAXB на GitHub.Ио ( "JAXB лицензируется под двойной лицензией-CDDL 1.1 и GPL 2.0 с исключением Class-path")

    • скачать jaxb-ri-2.3.0.zip

    • распакуйте везде, где вы помещаете свои файлы инфраструктуры java (в моем случае,/usr/local/java/jaxb-ri/). Может существовать другое решение (возможно, через SDKMAN, я не знаю)

    • убедитесь, что банки в подкаталоге lib на CLASSPATH. Я делаю это через скрипт, запущенный при запуске bash, называемый /etc/profile.d/java.sh, где я добавил (среди многих других линий) следующий цикл:

    упаковано в функцию...

    function extend_qzminynshg {
       local BASE="/usr/local/java"
       for LIB in jaxb-api.jar  jaxb-core.jar  jaxb-impl.jar  jaxb-jxc.jar  jaxb-xjc.jar; do
          local FQLIB="$BASE/jaxb-ri/lib/$LIB"
          if [[ -f $FQLIB ]]; then
             export CLASSPATH=$FQLIB:$CLASSPATH
          fi
        done
    }
    
    extend_qzminynshg; unset extend_qzminynshg
    

    и это работает!


    Я следил за этим URL-адресом, и приведенные ниже настройки действительно помогли мне. Я использую Java 10 с STS IDE в Macbook Pro. Это работает как шарм.

       <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jaxb</groupId>
        <artifactId>jaxb-runtime</artifactId>
        <version>2.3.0</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>javax.activation</groupId>
        <artifactId>javax.activation-api</artifactId>
        <version>1.2.0</version>
    </dependency>
    

    хорошо, у меня была такая же проблема, но я использовал java 8 и продолжал получать эту ошибку, я пробовал большинство решений. но оказывается, что мой maven все еще указывал на java 9, хотя я установил глобальную java как 8, поэтому, как только я исправил, что все это сработало, для любого тела, у которого может быть такая проблема, проверьте (как исправить Maven для использования Java по умолчанию ) https://blog.tompawlak.org/maven-default-java-version-mac-osx


    я столкнулся с той же проблемой, используя Spring Boot 2.0.5.RELEASE на Java 11.

    добавлять javax.xml.bind:jaxb-api:2.3.0 в одиночку не удалось решить проблему. Мне также пришлось обновить Spring Boot до последней вехи 2.1.0.M2, Так что я предполагаю, что это будет исправлено в следующем официальном релизе.