I built a .jar
in docker on the ARM architecture and one on AMD64.
The two .jar
files have the identical size, but vbindiff
says their contents are quite different.
I tested both .jar
files on my AMD64 computer and the reversed slogan "build anywhere, run once" holds.
My hypothesis is that this has to do with Java Native Interface (JNI). The .jar
is a Spring Boot Webflux backend. Unfortunately, I don't know if it or any other dependency uses JNI.
I noted that the ARM image has JDK 17.0.3 installed, while the AMD64 image has JDK 17.0.2. But this should not be a problem, since I built both .jar
s using the Gradle wrapper, which specifies the exact toolchain to be downloaded and used to build the project:
kotlin("jvm") version "1.6.10"
What could be the reason for the difference? Can I assume that either .jar
can be used on any platform that has a compatible JVM?
EDIT: I followed Thomas' advice and used diff -r
to compare the extracted contents of the .jar
files. They are identical.
However, diff
confirms that the .jar
files themselves are different.
I just learned that the .jar
format is based on .zip
, which can use various compression methods, as well as include extra information in file headers, such as 'last modified' or optional OS-specific attributes. Mystery solved.
CodePudding user response:
You can list the files in the .jar
using jar tf myfile.jar
. If the only contents are .class
files and the manifest data in META-INF/
, then chances are good that it's 100% portable. If you see other files like .so
, .dll
or .dylib
, then there is native code in there which might give trouble.
Here's how you can list all the files which might warrant a closer look:
jar tf myfile.jar | grep -Pv '^META-INF/|(\.class|/)$'
Since you have already built the .jar
s on two different platforms, you can also extract their contents using jar xf myfile.jar
and use diff -r
to compare them recursively. This is a more robust way to detect differences than comparing the archives directly, although I imagine that .class
files might not be byte-wise identical either even if they're semantically the same.
CodePudding user response:
I can't really tell why there is a difference but I am almost certain that the .jar file will run anywhere as long as there isn't anything platform specific in your java code. Your code is compiled for the JVM and not for the architecture of the CPU. The JVM is what handles the "translation" of your java binary to machine code so it can run anywhere.