Search code examples
javaspring-bootmavenjlinkjdeps

Jdeps Module java.annotation not found


I'm trying to create a minimal jre for Spring Boot microservices using jdeps and jlink, but I'm getting the following error when I get to the using jdeps part

Exception in thread "main" java.lang.module.FindException: Module java.annotation not found, required by org.apache.tomcat.embed.core
    at java.base/java.lang.module.Resolver.findFail(Resolver.java:893)
    at java.base/java.lang.module.Resolver.resolve(Resolver.java:192)
    at java.base/java.lang.module.Resolver.resolve(Resolver.java:141)
    at java.base/java.lang.module.Configuration.resolve(Configuration.java:421)
    at java.base/java.lang.module.Configuration.resolve(Configuration.java:255)
    at jdk.jdeps/com.sun.tools.jdeps.JdepsConfiguration$Builder.build(JdepsConfiguration.java:564)
    at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.buildConfig(JdepsTask.java:603)
    at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.run(JdepsTask.java:557)
    at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.run(JdepsTask.java:533)
    at jdk.jdeps/com.sun.tools.jdeps.Main.main(Main.java:49)

I already tried the following commands with no effect

jdeps --ignore-missing-deps --multi-release 17 --module-path target/lib/* target/errorrr-*.jar
jdeps --multi-release 16 --module-path target/lib/* target/errorrr-*.jar
jdeps --ignore-missing-deps --multi-release 17 --class-path target/lib/* target/errorrr-*.jar

I already tried it with java versions 11, 16 and 17 and different versions of Spring Boot.

All dependencies needed for build are copied to target/lib folder by maven-dependency-plugin plugin when I run mvn install

After identifying the responsible dependency I created a new project from scratch with only it to isolate the error, but it remained.

I tried to use gradle at first but as the error remained I changed it to mavem but also no change.

When I add the specified dependency that is being requested the error changes to

#13 1.753 Exception in thread "main" java.lang.Error: java.util.concurrent.ExecutionException: com.sun.tools.jdeps.MultiReleaseException
        #13 1.753       at jdk.jdeps/com.sun.tools.jdeps.DependencyFinder.waitForTasksCompleted(DependencyFinder.java:271)
        #13 1.753       at jdk.jdeps/com.sun.tools.jdeps.DependencyFinder.parse(DependencyFinder.java:133)
        #13 1.753       at jdk.jdeps/com.sun.tools.jdeps.DepsAnalyzer.run(DepsAnalyzer.java:129)
        #13 1.753       at jdk.jdeps/com.sun.tools.jdeps.ModuleExportsAnalyzer.run(ModuleExportsAnalyzer.java:74)
        #13 1.753       at jdk.jdeps/com.sun.tools.jdeps.JdepsTask$ListModuleDeps.run(JdepsTask.java:1047)
        #13 1.753       at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.run(JdepsTask.java:574)
        #13 1.753       at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.run(JdepsTask.java:533)
        #13 1.753       at jdk.jdeps/com.sun.tools.jdeps.Main.main(Main.java:49)
        #13 1.753 Caused by: java.util.concurrent.ExecutionException: com.sun.tools.jdeps.MultiReleaseException
        #13 1.753       at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122)
        #13 1.753       at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)
        #13 1.753       at jdk.jdeps/com.sun.tools.jdeps.DependencyFinder.waitForTasksCompleted(DependencyFinder.java:267)
        #13 1.754       ... 7 more
        #13 1.754 Caused by: com.sun.tools.jdeps.MultiReleaseException
        #13 1.754       at jdk.jdeps/com.sun.tools.jdeps.VersionHelper.add(VersionHelper.java:62)
        #13 1.754       at jdk.jdeps/com.sun.tools.jdeps.ClassFileReader$JarFileReader.readClassFile(ClassFileReader.java:360)
        #13 1.754       at jdk.jdeps/com.sun.tools.jdeps.ClassFileReader$JarFileIterator.hasNext(ClassFileReader.java:402)
        #13 1.754       at jdk.jdeps/com.sun.tools.jdeps.DependencyFinder.lambda$parse$5(DependencyFinder.java:179)
        #13 1.754       at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
        #13 1.754       at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
        #13 1.754       at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
        #13 1.754       at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
        #13 1.754       at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
        #13 1.754       at java.base/java.lang.Thread.run(Thread.java:833)

My pom.xml

   <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>2.6.0</version>
       <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.example</groupId>
   <artifactId>errorrr</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>errorrr</name>
   <description>Demo project for Spring Boot</description>
   <properties>
       <java.version>17</java.version>
   </properties>
   <dependencies>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>

       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter</artifactId>
       </dependency>

       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-test</artifactId>
           <scope>test</scope>
       </dependency>

   </dependencies>

   <build>
       <plugins>
           <plugin>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-maven-plugin</artifactId>
           </plugin>
           <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-dependency-plugin</artifactId>
               <executions>
                   <execution>
                       <id>copy-dependencies</id>
                       <phase>package</phase>
                       <goals>
                           <goal>copy-dependencies</goal>
                       </goals>
                       <configuration>
                           <outputDirectory>${project.build.directory}/lib</outputDirectory>
                       </configuration>
                   </execution>
               </executions>
           </plugin>
       </plugins>
   </build>

</project>

If I don't need to use this dependency I can do all the build processes and at the end I have a 76mb jre


Solution

  • I arrived at a solution that is valid, not perfect, but it works correctly. In my case the lib "jackson" was the cause of the problem. It uses java multi release and somehow during jdeps it was causing some error. After some tests I understood that I could remove this lib from the evaluation, and that no module would be missing from deps.info. I needed to add this task for removal:

    task myDeleteTask(type: Delete) {
        delete files("${buildDir}/temp-lib/jackson-databind-{your_version}.jar")
        delete files("${buildDir}/temp-lib/jackson-datatype-jdk8-{your_version}.jar")
        delete files("${buildDir}/temp-lib/jackson-datatype-jsr310-{your_version}.jar")
        delete files("${buildDir}/temp-lib/jackson-module-parameter-names-{your_version}.jar")
        delete files("${buildDir}/temp-lib/jackson-core-{your_version}.jar")
        delete files("${buildDir}/temp-lib/jackson-dataformat-cbor-{your_version}.jar")
    }
    task tempCopyDependencies(type: Copy) {
        from configurations.runtimeClasspath
        into "$buildDir/temp-lib"
    }
    
    tasks.named("build"){
        finalizedBy("tempCopyDependencies")
        finalizedBy("myDeleteTask")
    }
    

    OBS: in the question I used maven because it is easier and I have a wider knowledge, but my real project uses gradle, which ends up making the delete task easier to do