'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 1:[1]
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
Solution 2:[2]
I have been struggling with a similar issue In my gradle spring boot project
I am using the output of the following for adding modules in jlink in my dockerfile with (openjdk:17-alpine
):
RUN jdeps \
--ignore-missing-deps \
-q \
--multi-release 17 \
--print-module-deps \
--class-path build/lib/* \
app.jar > deps.info
RUN jlink --verbose \
--compress 2 \
--strip-java-debug-attributes \
--no-header-files \
--no-man-pages \
--output jre \
--add-modules $(cat deps.info)
I think your mvn build is fine as long as you have all the required dependencies. But just in case I modified my gradle jar task to include the dependencies as follow:
jar {
manifest {
attributes "Main-Class": "com.demo.Application"
}
duplicatesStrategy = DuplicatesStrategy.INCLUDE
from {
configurations.default.collect { it.isDirectory() ? it : zipTree(it)
}
}
}
Solution 3:[3]
I was facing a similar issue, what helped in my case - is specifying both --class-path
and --module-path
pointing to the same directory with libs.
According to your example, I think it should be jdeps --ignore-missing-deps --print-module-deps --multi-release 17 --module-path="target/lib/*" --class-path="target/lib/*" target/errorrr-*.jar
.
Also, jdeps
from JDK 17 (and maybe earlier versions) seems to have a bug where it can throw com.sun.tools.jdeps.MultiReleaseException
. It seems to have been fixed in JDK 18, at least it works without any issues for me.
With Docker you can do a staged build that will identify the dependencies first using JDK 18, and then build a new JRE image out of JDK 17. Like this:
FROM amazoncorretto:18-alpine as deps
COPY ./app.jar /app/app.jar
RUN mkdir /app/unpacked && \
cd /app/unpacked && \
unzip ../app.jar && \
cd .. && \
$JAVA_HOME/bin/jdeps \
--ignore-missing-deps \
--print-module-deps \
-q \
--recursive \
--multi-release 17 \
--class-path="./unpacked/BOOT-INF/lib/*" \
--module-path="./unpacked/BOOT-INF/lib/*" \
./app.jar > /deps.info
FROM amazoncorretto:17.0.3-alpine as corretto-jdk
RUN apk add --no-cache binutils
COPY --from=deps /deps.info /deps.info
RUN $JAVA_HOME/bin/jlink \
--verbose \
--add-modules $(cat /deps.info) \
--strip-debug \
--no-man-pages \
--no-header-files \
--compress=2 \
--output /customjre
You can check the full example here: https://github.com/monosoul/jvm-in-docker/blob/main/jre-slim-auto.dockerfile
For anyone interested, here's a blog article about using jlink
and jdeps
: https://blog.monosoul.dev/2022/04/25/reduce-java-docker-image-size/
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Bryan Motta |
Solution 2 | SHK |
Solution 3 |