I’m recently learning about AWS features and one of them are “Lambdas”. Those are functions that can be deployed and triggered on various events (like HTTP request, or file upload), but you don’t have to maintain the servers that run them. By default AWS provides several runtimes like NodeJS, Python and Java. Since I’m recently a bit tired with Python, I’ve decided to refresh my Java knowledge. The first step would be to understand the Java manifest files.
What is Java Manifest?
While you can find some description of manifests in Oracle’s official docs, they don’t really seem to be something that gives you an idea, what it is:
When you create a JAR file, it automatically receives a default manifest file. There can be only one manifest file in an archive, and it always has the pathname.
Honestly? I didn’t have any clue what to do with that info. So what are manifests?
Well, think about it that way: when you compile java source code, you get binary
class files. Those files are understood by the Java Virtual Machine, which is something that actually runs it. Just as you type
python main.py to run Python script, you can execute those binaries by running
javac Main.java and then
java Main.class to compile and run Java source code (the link to the example repo is at the end of this article). The problem with this approach is that in big projects, you’re going to have tons of those
class files and you’d like to pack them into a single file that you can run.
Indeed, someone has thought about solving this problem and has designed the
jar files. Jars contain compressed code. You can create your jar by running
jar cf Main.jar Main.class. It creates
Main.jar out of the
Main.class file. Cool. Let’s run it.
$ java -jar Main.jar no main manifest attribute, in Main.jar
Why Doesn’t My jar Work?
As you can see there’s some problem with the manifest file. Remember when I said, that
jar is a compressed file? Well, it’s a zip. So we can actually browse its contents with tools like vim by running
" zip.vim version v28 " Browsing zipfile /home/gonczor/Projects/blog/Jars/Main.jar " Select a file with cursor and press ENTER META-INF/ META-INF/MANIFEST.MF Main.class
OK, some manifest has been created for us. Let’s look at its contents.
Manifest-Version: 1.0 Created-By: 11.0.10 (Ubuntu)
The problem is that it does not tell the JVM where it should start executing the jar. There’s no entrypoint. In Assembly, we expect an address of the first instruction in the
data section, here we expect the name of the place to start the execution (you may want to look at some reverse engineering stuff I did or look at some assemblies).
Luckily, we can add such info to the Java Manifest file. Let’s create a text file called
And merge it into current jar. To do this we need one extra parameter to our command.
jar -cfm Main.jar manifest.txt Main.class
m letter tells to add contents of the
manifest.txt to the
Main.jar, which will also include the
Main.class. Does it work now?
$ java -jar Main.jar Hello, world!
Jars are way more powerful than just creating executables. They can help to sign the code and do other magic that is currently beyond my comprehension. I hope, however, that you got your “AHA” moment, just like I got mine a few minutes ago.
That’s all folks, happy hacking.