
How it works...
To make self-executable JARs, we need a manifest file called MANIFEST.MF in the META-INF directory. For our purposes here, we just need to specify the name of the Java class that contains the Java-based extractor program's main() method.
One might argue that even though we don’t have top-level class declaration, we are specifying it as HelloWorldKt in the code for the jar task:
manifest {
attributes 'Main-Class': 'HelloWorldKt'
}
The reason for putting the preceding code block in the jar task is that Kotlin compiler adds all top-level functions to respective classes for back-compatibility with JVM. So, the class generated by Kotlin compiler will have the filename, plus the Kt suffix, which makes it HelloWorldKt.
Also, the reason we added from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } in jar task is because we want Gradle to copy all of a JAR’s dependencies. The reason for doing so is that, by default, when Gradle (as well as Maven) packs some Java class files into a JAR file, it assumes that this JAR file will be referenced by an application, where all of its dependencies are also accessible in the classpath of the loading application. So, by specifying the preceding lines in jar task, we are telling gradle to take all of this JAR’s referenced dependencies and copy them as part of the JAR itself. In the Java community, this is known as a fat JAR. In a fat JAR, all the dependencies end up within the classpath of the loading application, so the code can be executed without problems. The only downside to creating fat JARs is their growing file size (which kind of explains the name), though it is not a big concern in most situations.