findResource("") returning null when module-info.java is present, why is that?

Solution 1:

One thing I notice is that your application (assuming that it's packaged in tech.flexpoint.dashman) does not seem to be opened up to Spring in any way, which will surely result in failed class loading/illegal access.

I would expect to see something like this in module-info.java (depending on your Spring dependencies):

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

The exception is a NoClassDefFoundError, which is thrown at runtime when the class definition of a class that was known at compile time cannot be resolved, in this case the interface javax.transaction.UserTransaction, which is part of the Java Transaction API (JTA).

As others have pointed out, JTA is not bundled with the JDK, and needs to be added as a compile dependency. However, the class that needs to load the UserTransaction class definition comes from the spring-boot-autoconfigure artifact, which is responsible for its own dependencies ([email protected] 🡒 [email protected] 🡒 [email protected]), so you should not need to add JTA as a dependency.

However, because you want to package your own app as a Java 9 module, it needs to explicitly state its dependencies. spring-boot-autoconfigure is not yet a modularized Java 9 library, and does not do this for you (i.e. transitively). The automatic module name for JTA is java.transaction, so you need to add the requirement in module-info.java:

requires java.transaction;

I got your example running and did indeed get NoClassDefFoundErrors when running from IntelliJ IDEA. The stacktrace pointed back to a ClassNotFoundException, which indicates classpath problems. Since IDEA calculates the classpath when launching the application from there, I wanted to see if I could reproduce the error when using the spring-boot-maven-plugin to run the application.

I copied the IDEA run configuration to the spring-boot-maven-plugin configuration, as shown below:

<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>

Then I invoked mvn spring-boot:run and voila, the application booted successfully without errors. I can only conclude that this is an issue with the classpath calculated by IntelliJ.

Solution 2:

Assuming you have declared the dependency:

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

Include the following in module-info.java:

requires java.transaction;

Version 1.3 declares the automatic module name, while version 1.2 doesn't.
The latter requires javax.transaction.api;. Source