1 year ago

#228259

test-img

Simon Campano

How to calculate list of needed java modules with jdeps?

I'm basically working with a tomcat webapp that has a complex structure, with many jars and classes at several locations and I want to generate a JRE with jlink and its --add-modules option in order to reduce the weight and attack surface of the binaries I use.

To clarify, if I include all modules with jlink --add-modules ALL-MODULE-PATH everything runs smoothly.

I've given this a few attempts:

1) run jdeps on whole dir

The target I need to analyse is a classic tomcat structure, which contains jars and classes at several locations.

> tree -L 1 /usr/local/tomcat/                                                                                                                  
├── LICENSE
├── NOTICE
├── RELEASE-NOTES
├── bin
├── conf
├── db.sh
├── favicon.ico
├── lib
├── logs
├── run
├── save.sh
├── start.sh
├── stop.sh
├── temp
├── webapps
└── work

> find . -name "*.jar" -o -name "*.class" | wc -l                                                                                             
     938

I've been trying to use jdeps in several ways but the docs are not super helpfull. Below is the only command that returned something looking like what I'd expect:

> jdeps --recursive --print-module-deps --ignore-missing-deps /usr/local/tomcat/
java.base,java.compiler,java.desktop,java.management,java.naming,java.scripting,java.sql

That kind of works as expected, but it seems to only take the classes into account. Without --print-module-deps I get a whole bunch of unknown dependencies like this

com.my.app -> org.eclipse.jgit.diff  not found

Even though the dependecy is properly installed at /usr/local/tomcat/webapps/ROOT/WEB-INF/lib/org.eclipse.jgit-5.10.0.202012080955-r.jar.

As an obvious consequence, there are a lot of unlisted needed modules, and when executing the app with the custom JRE, I get errors because of the missing java modules.

2) Run jdeps on each jar/class file of the directory

I've tested runnning jdeps on every single jar to add the missing modules, even though a more direct / efficient approach with jdeps would be better.

The find . -name "*.jar" -o -name "*.class" | xargs jdeps --print-module-deps --ignore-missing-deps seems to do the trick on this basic usecase, but when applied to the bigger tomcat project, there still are runtime exceptions so I think the ignore-missing-deps makes it pointless.

terminal screenshot

3) Run jdeps on directory, providing all jar files to the classpath option of jdeps

Not being sure if jdeps is made to run on a full tomcat directory like that, I tried providing all jars to the -cp classpath option of jdeps, and it looks like it gets rid of some of the "not found" entries (262 => 43). Adding the classes makes no difference.

I still need to use --ignore-missing-deps in conjuction with --print-module-deps an a tail -1 to ignore the handfull of "split package" warnings

# run jdeps on directory (might need `apk -U add findutils` on alpine)
jdeps --multi-release 17 --recursive -cp "$(find . -name "*.jar" -printf "%h/*\n" | sort -u | paste -sd ":")" --ignore-missing-deps --print-module-deps ./  | tail -1

Using this output, I can go from the original full list of 68 java modules to only 17, gaining approximately 22MB. Not sure about the attack surface, but I've seen better results on weigh reduction!

This is still unperfect, for example I figured out that the app uses the jar:// FileSystemProvider. There is no specific import in the java class, so jdeps can't know that the app need the jdk.zipfs module to mount jars...

Conclusion

Not confident about my binary;

Why does jdeps still gives me not found errors and split package warnings, how can I fix that?

java

tomcat

java-module

jlink

jdeps

0 Answers

Your Answer

Accepted video resources