it-swarm.com.de

findResource ("") gibt null zurück, wenn module-info.Java vorhanden ist. Warum ist das so?

Ich debugge warum in der Spring Boot-Anwendung module-info.Java, wenn spring-orm eine Ausnahme während des Startvorgangs auslöst. Dies ist die Ausnahme:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is Java.lang.NoClassDefFoundError: javax/transaction/UserTransaction
    at [email protected]/org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.Java:1699) ~[spring-beans-5.0.8.RELEASE.jar:na]
    at [email protected]/org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.Java:573) ~[spring-beans-5.0.8.RELEASE.jar:na]
    at [email protected]/org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.Java:495) ~[spring-beans-5.0.8.RELEASE.jar:na]
    at [email protected]/org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.Java:317) ~[spring-beans-5.0.8.RELEASE.jar:na]
    at [email protected]/org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.Java:222) ~[spring-beans-5.0.8.RELEASE.jar:na]
    at [email protected]/org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.Java:315) ~[spring-beans-5.0.8.RELEASE.jar:na]
    at [email protected]/org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.Java:199) ~[spring-beans-5.0.8.RELEASE.jar:na]
    at [email protected]/org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.Java:1089) ~[spring-context-5.0.8.RELEASE.jar:na]
    at [email protected]/org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.Java:859) ~[spring-context-5.0.8.RELEASE.jar:na]
    at [email protected]/org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.Java:550) ~[spring-context-5.0.8.RELEASE.jar:na]
    at [email protected]/org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.Java:140) ~[spring-boot-2.0.4.RELEASE.jar:na]
    at [email protected]/org.springframework.boot.SpringApplication.refresh(SpringApplication.Java:762) [spring-boot-2.0.4.RELEASE.jar:na]
    at [email protected]/org.springframework.boot.SpringApplication.refreshContext(SpringApplication.Java:398) [spring-boot-2.0.4.RELEASE.jar:na]
    at [email protected]/org.springframework.boot.SpringApplication.run(SpringApplication.Java:330) [spring-boot-2.0.4.RELEASE.jar:na]
    at [email protected]/org.springframework.boot.SpringApplication.run(SpringApplication.Java:1258) [spring-boot-2.0.4.RELEASE.jar:na]
    at [email protected]/org.springframework.boot.SpringApplication.run(SpringApplication.Java:1246) [spring-boot-2.0.4.RELEASE.jar:na]
    at tech.flexpoint.dashmanserver/tech.flexpoint.dashmanserver.DashmanServerApplication.main(DashmanServerApplication.Java:13) [classes/:na]
    at Java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at Java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:62) ~[na:na]
    at Java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43) ~[na:na]
    at Java.base/Java.lang.reflect.Method.invoke(Method.Java:564) ~[na:na]
    at [email protected]/org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.Java:49) [spring-boot-devtools-2.0.4.RELEASE.jar:na]
Caused by: Java.lang.NoClassDefFoundError: javax/transaction/UserTransaction
    at Java.base/Java.lang.Class.getDeclaredMethods0(Native Method) ~[na:na]
    at Java.base/Java.lang.Class.privateGetDeclaredMethods(Class.Java:3119) ~[na:na]
    at Java.base/Java.lang.Class.privateGetPublicMethods(Class.Java:3144) ~[na:na]
    at Java.base/Java.lang.Class.getMethods(Class.Java:1863) ~[na:na]
    at [email protected]/org.hibernate.service.internal.AbstractServiceRegistryImpl.applyInjections(AbstractServiceRegistryImpl.Java:288) ~[hibernate-core-5.2.17.Final.jar:na]
    at [email protected]/org.hibernate.service.internal.AbstractServiceRegistryImpl.injectDependencies(AbstractServiceRegistryImpl.Java:279) ~[hibernate-core-5.2.17.Final.jar:na]
    at [email protected]/org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.Java:239) ~[hibernate-core-5.2.17.Final.jar:na]
    at [email protected]/org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.Java:210) ~[hibernate-core-5.2.17.Final.jar:na]
    at [email protected]/org.hibernate.service.internal.SessionFactoryServiceRegistryImpl.getService(SessionFactoryServiceRegistryImpl.Java:80) ~[hibernate-core-5.2.17.Final.jar:na]
    at [email protected]/org.hibernate.internal.SessionFactoryImpl.canAccessTransactionManager(SessionFactoryImpl.Java:942) ~[hibernate-core-5.2.17.Final.jar:na]
    at [email protected]/org.hibernate.internal.SessionFactoryImpl.buildCurrentSessionContext(SessionFactoryImpl.Java:953) ~[hibernate-core-5.2.17.Final.jar:na]
    at [email protected]/org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.Java:319) ~[hibernate-core-5.2.17.Final.jar:na]
    at [email protected]/org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.Java:462) ~[hibernate-core-5.2.17.Final.jar:na]
    at [email protected]/org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.Java:892) ~[hibernate-core-5.2.17.Final.jar:na]
    at [email protected]/org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.Java:57) ~[spring-orm-5.0.8.RELEASE.jar:na]
    at [email protected]/org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.Java:365) ~[spring-orm-5.0.8.RELEASE.jar:na]
    at [email protected]/org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.Java:390) ~[spring-orm-5.0.8.RELEASE.jar:na]
    at [email protected]/org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.Java:377) ~[spring-orm-5.0.8.RELEASE.jar:na]
    at [email protected]/org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.Java:341) ~[spring-orm-5.0.8.RELEASE.jar:na]
    at [email protected]/org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.Java:1758) ~[spring-beans-5.0.8.RELEASE.jar:na]
    at [email protected]/org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.Java:1695) ~[spring-beans-5.0.8.RELEASE.jar:na]
    ... 21 common frames omitted
Caused by: Java.lang.ClassNotFoundException: javax.transaction.UserTransaction
    at Java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.Java:582) ~[na:na]
    at Java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.Java:190) ~[na:na]
    at Java.base/Java.lang.ClassLoader.loadClass(ClassLoader.Java:499) ~[na:na]
    ... 42 common frames omitted

Ich habe das Problem aufgespürt, um URLClassLoader.findResource("") zurückzugeben und null zurückzugeben, wenn module-info.Java vorhanden ist, aber "file:/C:/Users/pupeno/Documents/Dashman/code/dashmanserver/target/classes/", falls dies nicht der Fall ist.

Ich habe das minimal mögliche Beispiel erstellt, das dieselbe Ausnahme auslöst. Um es auszuführen, müssen Sie:

  1. Klonen und installieren Sie eine aktuelle Kopie von Moditect von hier aus: https://github.com/moditect/moditect , da dieser Bugfix noch nicht verfügbar ist: https://github.com/moditect/moditect/ Ausgaben/51
  2. Klonen Sie das Demo-Repo von: https://github.com/dashmantech/demo
  3. Richten Sie eine lokale PostgreSQL-Datenbank mit den Berechtigungsnachweisen demo/confi/application.properties ein
  4. Führen Sie zuerst mvn clean package aus, damit ModiTec alle Module erstellt
  5. Öffnen Sie das Projekt in einer aktuellen Version von IntelliJ
  6. Klicken Sie auf play für das "Run Demo" -Profil (das .idea-Verzeichnis ist im entsprechenden Laufprofil mit Argumenten usw. enthalten).

Ich brauche findResource(""), um "file:/C:/Users/pupeno/Documents/Dashman/code/dashmanserver/target/classes/" zurückzugeben, damit spring-orm funktionieren kann.

findResource("") sieht so aus:

public URL findResource(final String name) {
    /*
     * The same restriction to finding classes applies to resources
     */
    URL url = AccessController.doPrivileged(
        new PrivilegedAction<>() {
            public URL run() {
                return ucp.findResource(name, true);
            }
        }, acc);

    return url != null ? URLClassPath.checkURL(url) : null;
}

Ich kann also sehen, dass es einige Zugriffe gibt, die ohne das Modulsystem in Ordnung sind, aber durch das Modulsystem von Java verhindert wird, wenn ein module-infe.Java vorhanden ist. Mein Problem ist, dass ich nicht sehe, wie es funktioniert, was soll exportiert oder geöffnet werden, damit es funktioniert.

Die Art und Weise, in der Spring Boot den Aufruf dieser Methode verursacht, ist RestartClassLoader, eine Unterklasse von URLClassLoader, insbesondere Zeile 124, in der super.findResource(name) aufgerufen wird:

@Override
public URL findResource(String name) {
    final ClassLoaderFile file = this.updatedFiles.getFile(name);
    if (file == null) {
        return super.findResource(name);
    }
    if (file.getKind() == Kind.DELETED) {
        return null;
    }
    return AccessController
            .doPrivileged((PrivilegedAction<URL>) () -> createFileUrl(name, file));
}

Die bestimmte RestartClassLoader-Instanz, die verwendet wird, ist ein Mitglied von ClassPathResource und ist folgendermaßen definiert:

this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());

im Konstruktor, Zeile 85 .

Schließlich sieht getDefaultClassLoader() so aus:

/**
 * Return the default ClassLoader to use: typically the thread context
 * ClassLoader, if available; the ClassLoader that loaded the ClassUtils
 * class will be used as fallback.
 * <p>Call this method if you intend to use the thread context ClassLoader
 * in a scenario where you clearly prefer a non-null ClassLoader reference:
 * for example, for class path resource loading (but not necessarily for
 * {@code Class.forName}, which accepts a {@code null} ClassLoader
 * reference as well).
 * @return the default ClassLoader (only {@code null} if even the system
 * ClassLoader isn't accessible)
 * @see Thread#getContextClassLoader()
 * @see ClassLoader#getSystemClassLoader()
 */
@Nullable
public static ClassLoader getDefaultClassLoader() {
    ClassLoader cl = null;
    try {
        cl = Thread.currentThread().getContextClassLoader();
    }
    catch (Throwable ex) {
        // Cannot access thread context ClassLoader - falling back...
    }
    if (cl == null) {
        // No thread context class loader -> use class loader of this class.
        cl = ClassUtils.class.getClassLoader();
        if (cl == null) {
            // getClassLoader() returning null indicates the bootstrap ClassLoader
            try {
                cl = ClassLoader.getSystemClassLoader();
            }
            catch (Throwable ex) {
                // Cannot access system ClassLoader - oh well, maybe the caller can live with null...
            }
        }
    }
    return cl;
}

Mein module-info.Java enthält:

module tech.flexpoint.dashman {
    exports tech.flexpoint.dashman to com.fasterxml.jackson.databind;
    exports tech.flexpoint.dashman.controllers.configurator to javafx.fxml;

    opens tech.flexpoint.dashman to javafx.graphics, jna;
    opens tech.flexpoint.dashman.controllers.common to javafx.fxml;
    opens tech.flexpoint.dashman.controllers.configurator to javafx.fxml;
    opens tech.flexpoint.dashman.models to org.hibernate.validator, tech.flexpoint.dashmancommon, javafx.base;

    opens common;
    opens configurator;
    opens displayer;
    opens winscreensaver;

    requires appdirs;
    requires org.bouncycastle.provider;
    requires com.fasterxml.jackson.core;
    requires com.fasterxml.jackson.databind;
    requires com.fasterxml.jackson.datatype.jdk8;
    requires io.sentry;
    requires jackson.annotations;
    requires Java.desktop;
    requires Java.sql;
    requires Java.validation;
    requires javafx.controls;
    requires javafx.fxml;
    requires javafx.graphics;
    requires javafx.media;
    requires javafx.web;
    requires jna;
    requires jna.platform;
    requires org.Apache.commons.lang3;
    requires org.kordamp.ikonli.javafx;
    requires org.kordamp.ikonli.fontawesome5;
    requires spring.core;
    requires spring.retry;
    requires spring.web;
    requires tech.flexpoint.dashmancommon;
}

In IntelliJ habe ich folgende Plugins aktiviert:

  • Lombok Plugin
  • .ginore
  • Power Shell
  • VisualVM Launcher
  • ANSI-Textmarker
  • Batch-Skripts unterstützen
  • Bytecode Viewer
  • CMD-Unterstützung
  • Urheberrechte ©
  • Deckung
  • CSS-Unterstützung
  • Datenbanktools und SQL
  • Git-Integration
  • GitHub
  • Gradle
  • Groovig
  • Heroku-Integration
  • HTML-Tools
  • HTTP-Client
  • 18n für Java
  • IDE-Einstellungen synchronisieren
  • Java Bytecode Decompiler
  • Java EE: EJB, JPA, Servlets
  • Java Stream-Debugger
  • JavaFX
  • JUnit
  • Zeilen-Sortierer
  • Markdown-Unterstützung
  • Maven-Integration
  • Maven Integration Extension
  • Unterstützung für Persistenz-Frameworks
  • Eigenschaften Support
  • Smali-Unterstützung
  • Frühling AOP/@ AspectJ
  • Spring Batch
  • Spring Boot
  • Frühlingsdaten
  • Spring Integration Patterns
  • Spring OSGi
  • Frühlingssicherheit
  • Frühling Unterstützung
  • Spring Web Services
  • Spring WebSocket
  • Terminal
  • YAML
48
pupeno

Ich stelle fest, dass Ihre Anwendung (vorausgesetzt, sie ist in tech.flexpoint.dashman verpackt ist) in keiner Weise für Spring geöffnet zu sein scheint, was sicherlich dazu führen kann, dass Klassen nicht geladen werden oder der Zugriff illegal ist.

Ich würde erwarten, etwas in module-info.Java zu sehen (abhängig von Ihren Spring-Abhängigkeiten):

opens tech.flexpoint.dashman to spring.core, spring.beans, spring.context;

Die Ausnahme ist eine NoClassDefFoundError, die zur Laufzeit ausgelöst wird, wenn die Klassendefinition einer Klasse, die zur Kompilierzeit bekannt war, nicht aufgelöst werden kann. In diesem Fall kann die Schnittstelle javax.transaction.UserTransaction, die Teil der Java Transaction API ist ( JTA) .

Wie andere darauf hingewiesen haben, ist JTA nicht im JDK enthalten und muss als Kompilierungsabhängigkeit hinzugefügt werden. Die Klasse, die die UserTransaction-Klassendefinition laden muss, stammt jedoch aus dem spring-boot-autoconfigure-Artefakt, das für seine eigenen Abhängigkeiten verantwortlich ist ( [email protected] ???? [email protected] ???? [email protected] ). Daher sollten Sie not JTA als Abhängigkeit hinzufügen.

Da Sie jedoch Ihre eigene App als Java 9-Modul packen möchten, müssen Sie explizit ihre Abhängigkeiten angeben . spring-boot-autoconfigure ist noch keine modularisierte Java 9-Bibliothek und führt dies nicht für Sie aus (d. h. durchgehend). Der automatische Modulname für JTA lautet Java.transaction. Daher müssen Sie die Anforderung in module-info.Java hinzufügen:

requires Java.transaction;

Ich habe Ihr Beispiel zum Laufen gebracht und tatsächlich habe ich NoClassDefFoundErrors erhalten, als ich von IntelliJ IDEA lief. Der Stacktrace zeigte auf eine ClassNotFoundException, die auf Klassenpfadprobleme hinweist. Da IDEA den Klassenpfad beim Starten der Anwendung von dort aus berechnet, wollte ich herausfinden, ob ich den Fehler reproduzieren könnte, wenn Sie spring-boot-maven-plugin verwenden, um die Anwendung auszuführen.

Ich habe die Ausführungskonfiguration IDEA in die spring-boot-maven-plugin-Konfiguration kopiert, wie unten gezeigt:

<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <configuration>
      <mainClass>tech.flexpoint.demo.DemoApplication</mainClass>
      <jvmArguments>--show-module-resolution --add-opens=Java.base/Java.lang=spring.core --add-opens=Java.base/Java.io=Tomcat.embed.core --add-opens=Java.base/Java.lang=ALL-UNNAMED --add-opens=Java.rmi/Sun.rmi.transport=ALL-UNNAMED</jvmArguments>
      <workingDirectory>${project.basedir}</workingDirectory>
  </configuration>
</plugin>

Dann habe ich mvn spring-boot:run und voila aufgerufen, die Anwendung hat erfolgreich ohne Fehler gebootet . Ich kann nur zu dem Schluss kommen, dass dies ein Problem mit dem von IntelliJ berechneten Klassenpfad ist.

11
Henrik

Angenommen, Sie haben die Abhängigkeit erklärt:

<dependency>
    <groupId>javax.transaction</groupId>
    <artifactId>javax.transaction-api</artifactId>
    <version>1.3</version>
</dependency>

Fügen Sie Folgendes in module-info.Java ein:

requires Java.transaction;

Version 1.3 gibt den automatischen Modulnamen an, während Version 1.2 dies nicht tut.
Letzteres requires javax.transaction.api;Quelle

3

Wie Sie in Ihrem ursprünglichen Problem erwähnt haben, funktioniert der Code ohne module-info.Java, jedoch nicht mit module-info.Java. Ich kann sehen, dass Sie all diese harte Arbeit geleistet haben, um das Problem zu erklären, ein minimales Projekt usw. zu erstellen, um das Problem näher zu untersuchen.

Wenn Sie Ihr Problem betrachten, ist es offensichtlich, dass eines der Module die URLClassLoader.findResource("") zurückgibt, die null zurückgibt. Möglicherweise überschreibt eines der Module in der Liste diese Klassenmethode oder hat eine mehrdeutige Implementierung.

Warum fängst du nicht mit einem leeren module-info.Java für das Minimalbeispiel an und fügst immer nur ein Modul hinzu, bis wir den Fehler sehen? Ich glaube, das wird uns helfen, den Täter zu finden.

1
Rinsad Ahmed

diese (oder ähnliche) Ausgabe wurde bereits für Springboot auf GitHub (jedoch mit Java 9) eingereicht.

Ich hätte moditect unter Verdacht, während auch moditect Probleme auf GitHub hinterlegt hat und ich auch Ihre Ausgabe dort gefunden habe; Das Aktualisieren von ASM auf 6.2.1 behebt mindestens eine weitere Änderung:

<dependency>
    <groupId>org.ow2.asm</groupId>
    <artifactId>asm</artifactId>
    <version>6.2.1</version>
</dependency>
0
Martin Zeitler