Book Image

Kotlin Programming Cookbook

By : Aanand Shekhar Roy, Rashi Karanpuria
Book Image

Kotlin Programming Cookbook

By: Aanand Shekhar Roy, Rashi Karanpuria

Overview of this book

The Android team has announced first-class support for Kotlin 1.1. This acts as an added boost to the language and more and more developers are now looking at Kotlin for their application development. This recipe-based book will be your guide to learning the Kotlin programming language. The recipes in this book build from simple language concepts to more complex applications of the language. After the fundamentals of the language, you will learn how to apply the object-oriented programming features of Kotlin 1.1. Programming with Lambdas will show you how to use the functional power of Kotlin. This book has recipes that will get you started with Android programming with Kotlin 1.1, providing quick solutions to common problems encountered during Android app development. You will also be taken through recipes that will teach you microservice and concurrent programming with Kotlin. Going forward, you will learn to test and secure your applications with Kotlin. Finally, this book supplies recipes that will help you migrate your Java code to Kotlin and will help ensure that it's interoperable with Java.
Table of Contents (21 chapters)
Title Page
Copyright and Credits
Packt Upsell
Contributors
Preface
Index

How to build a self-executable JAR with Gradle and Kotlin


Kotlin is great for creating small command-line utilities, which can be packaged and distributed as normal JAR files. In this recipe, we will see how to do it using Gradle build system. Gradle build system is one of the most sophisticated build systems out there. It is the default build tool for Android and is designed to ease scripting of complex, multilanguage builds with a lot of dependencies (typical of big projects). It achieves the goal of automating your project without compromising on maintainability, usability, flexibility, extensibility, or performance. We will be using Gradle build system to create a self-extracting JAR file. This JAR file can be distributed to and run on any platform supporting Java.

Getting ready

You need an IDE (preferably IntelliJ or Android Studio), and you need to tell it where your Kotlin files are present. You can do so by specifying it in the build.gradle file by adding the following:

sourceSets {
   main.java.srcDirs += 'src/main/kotlin/'
}

The preceding lines are required if you have your Kotlin files separated from Java packages. This is optional, and you can continue working with Kotlin files under Java packages, but it’s a good practice to keep them separated.

We’ll be creating a very simple function that just prints Hello World! when executed. Since it’ll be a simple function, I am just adding it as a top-level main() function.

How to do it...

Let's go through these steps, with which we can create a self-executable JAR:

  1. We’ll create a simple class HelloWorld.kt having the main function, which just prints out “Hello world!”:
fun main(args:Array<String>){
   println("Hello world")
}
  1. Now we need to configure a jar task, which Gradle build goes through to inform it of our entry to our project. In a Java project, this will be the path to the class where our main() function resides, so you will need to add this jar task in build.gradle:
jar {
   manifest {
       attributes 'Main-Class': 'HelloWorldKt'
   }
   from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
  1. After adding the preceding snippet to build.gradle, you need to run the following gradle command to create the jar file:
./gradlew clean jar
  1. The created jar file can be found in the build/libs folder. Now you can just run the java -jar demo.jar command to run the JAR file.

After you do that, you can see the output in the console:

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.