Знакомство с Kotlin и сборка jar при помощи maven
Это пост заметка о том, как я познакомился с языком Kotlin, какие использовал для этого ресурсы, инструменты, и как я собрал его в jar и запустил в консоли.
В общем-то я PHP программист, немного заком с Java. На днях решил посмотреть Kotlin. Это менее строго типизированный язык от JetBrains до того, что он, по сути, статически типизированный. В этом его основное принципиальное отличие от Java, плюс Kotlin имеет свой приятный синтаксис. Kotlin может быть скомпилирован в JVM или JavaScript.
Приступим к знакомству. Для начала понадобится IDE Idea.
http://www.jetbrains.com/idea/
Инструкции по установке там же на сайте. Версия 13+.
Внутри IDE я создал простой проект Java. Далее надо установить плагин от JetBrains для IDE.
http://confluence.jetbrains.com/display/Kotlin/Getting+Started
Плагин добавляет автозаполнение и возможность создавать Kotlin проекты.
Так же добавляются инструменты для компиляции Kotlin.
Особенность Kotlin в том, что он полностью совместим с Java. Т.е. код, написанный на Kotlin можно вызывать в Java и наоборот. Следовательно, все инструменты и библиотеки, которые используются для работы с Java, применимы и для Kotlin.
Если проект в IDE был создан не Kotlin изначально, то после установки плагина можно включить поддержку Kotlin. После включения в проект будут доаблены jar библиотеки Kotlin в директорию /lib.
Я включил Kotlin и написал следующий код для теста в папке /src/testing:
//first.kt package testing /** * Created by seyfer on 26.03.14. */ //fun main(args : Array) < // println("Hello, world!") //>//fun main(args : Array) < // if (args.size == 0) < // println("Please provide a name as a command-line argument") // return // >// println("Hello, $!") //> /*fun main(args : Array) < for (name in args) println("Hello, $name!") >*/ fun main(args: Array) < val language = if (args.size == 0) "EN" else args[0] println(when (language) < "EN" ->"Hello!" "FR" -> "Salut!" "IT" -> "Ciao!" "seyfer" -> "seed!" else -> "Sorry, I can't greet you in $language yet" >) >
В котлин файле комментарии я оставил нарочно. Это примеры со страницы
http://confluence.jetbrains.com/display/Kotlin/Hello%2C+world%21
Для начала я выполнял в IDE файл котлина отдельно, чтобы убедиться, что плагин работает и код компилируется.
Потом я создал java класс:
//first.java package testing; /** * Created with IntelliJ IDEA. * User: seyfer * Date: 24.07.13 * Time: 21:02 * To change this template use File | Settings | File Templates. */ public class first < public static void main(String[] args) < System.out.print("Hello " + args[0] + "\n"); TestingPackage.main(args); >>
Тут видно, что я хочу принять аргумент и передать его напрямую в котлин. В котлине же я использовал пример с языками и добавил еще один свой, который зависит от аргумента — моего ник нейма. В Java можно вызывать методы и получать доступ к переменным из котлина путем вызова — ИмяпакетаPackage.имяметода().
Если правильно настроить в IDE выполнение проекта, то можно задать с каким аргументом вызывать программу. Но это очень не удобно, я хотел бы менять аргумент на лету, чтобы отловить ошибки, для тестироавния. Мне нужно было собрать jar для запуска из консоли.
В проекте не было maven изначально, и я его туда добавил.
Помогла мне в этом вот эта страница.
http://confluence.jetbrains.com/display/Kotlin/Kotlin+Build+Tools
Документация котлина достаточно информативна для изучения языка по ней.
Так же, по поводу построения при помощи maven и gradle, можно посмотреть следующие примеры.
https://github.com/JetBrains/kotlin-examples
4.0.0 org.jetbrains.kotlin.examples idea_test 1.0-SNAPSHOT jar idea_test http://maven.apache.org 0.1-SNAPSHOT 4.10 UTF-8 org.jetbrains.kotlin kotlin-stdlib $ junit junit $ test org.apache.maven.plugins maven-jar-plugin true lib/ testing.first kotlin-maven-plugin org.jetbrains.kotlin $ < source >src/ < / s ource > compile process-sources compile test-compile process-test-sources test-compile sonatype.oss.snapshots Sonatype OSS Snapshot Repository http://oss.sonatype.org/content/repositories/snapshots false true sonatype.oss.snapshots Sonatype OSS Snapshot Repository http://oss.sonatype.org/content/repositories/snapshots false true
Тут используется настройка для kotlin-maven-plugin, где указывается, в какой директории искать файлы.
Так же, используется maven-jar-plugin. Тут очень важно правильно прописать < manifest >, иначе предстоит долго разбираться, почему jar не запускается с ошибкой «No Main Manifest Attribute«.
После билда в директории /target будет лежать jar проекта. В Idea есть отдельное окно maven projects, откуда удобно управлять построением.
Чтобы запустить jar обычно выполняется команда
java -jar /path/to/file.jar argument1 argument2
В моем случае это не сработало, т.к. я не воспользовался плагином maven, который бы добавил jar библиотеку котлина в билд.
Следовательно я получаю ошибку
java -jar target/idea_test-1.0-SNAPSHOT.jar 1 Hello 1 Exception in thread "main" java.lang.NoClassDefFoundError: kotlin/jvm/internal/Intrinsics at testing.TestingPackage-first-39a20e2.main(first.kt:27) at testing.TestingPackage.main(first.kt:1) at testing.first.main(first.java:16) Caused by: java.lang.ClassNotFoundException: kotlin.jvm.internal.Intrinsics at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
Отсюда понятно, что не находится Kotlin библиотека.
Правильный вызов с указанием jar зависимости такой
java -cp target/idea_test-1.0-SNAPSHOT.jar:lib/kotlin-runtime.jar testing.first seyfer Hello seyfer seed!
Теперь код работает верно. Как видно, я получил аргумент в java, вывел его, далее я передал его в kotlin, и на его основе отработала конструкция when (по смыслу похожа на switch-case).
Для того, чтобы собрать jar с включением зависимых jar в билд, можно воспользоваться плагином maven — maven-dependency-plugin. Или onejar-maven-plugin к проекту one-jar.
Я решил использовать one-jar.
org.dstovall onejar-maven-plugin 1.4.5 $/../lib/ kotlin-runtime.jar true onejar one-jar onejar-maven-plugin.googlecode.com http://onejar-maven-plugin.googlecode.com/svn/mavenrepo
В директории /target появится файл имяпроекта.one-jar.jar. Его можно вызвать обычным методом.
java -jar target/idea_test-1.0-SNAPSHOT.one-jar.jar seyfer Hello seyfer seed!
На этом настройка проекта для меня закончена. Далее можно изучать Kotlin по приведенным выше ссылкам на документацию.
Лично мне язык очень понравился. Несомненно он займет свою нишу, так же, как и язык hack, который разрабатывает Facebook, как свою версию PHP.
Maven
The kotlin-maven-plugin compiles Kotlin sources and modules. Currently, only Maven v3 is supported.
Define the version of Kotlin you want to use via a kotlin.version property:
Dependencies
Kotlin has an extensive standard library that can be used in your applications. To use the standard library in your project, add the following dependency in the pom file:
If you’re targeting JDK 7 or 8 with Kotlin versions older than:
- 1.8, use kotlin-stdlib-jdk7 or kotlin-stdlib-jdk8 , respectively.
- 1.2, use kotlin-stdlib-jre7 or kotlin-stdlib-jre8 , respectively.
If your project uses Kotlin reflection or testing facilities, you need to add the corresponding dependencies as well. The artifact IDs are kotlin-reflect for the reflection library, and kotlin-test and kotlin-test-junit for the testing libraries.
Compile Kotlin-only source code
To compile source code, specify the source directories in the tag:
The Kotlin Maven Plugin needs to be referenced to compile the sources:
Starting from Kotlin 1.8.20, you can replace the whole element above with
If several build plugins overwrite the default lifecycle and you also enabled the extensions option, the last plugin in the section has priority in terms of lifecycle settings. All earlier changes to lifecycle settings are ignored.
Compile Kotlin and Java sources
To compile projects that include Kotlin and Java source code, invoke the Kotlin compiler before the Java compiler. In Maven terms it means that kotlin-maven-plugin should be run before maven-compiler-plugin using the following method, making sure that the kotlin plugin comes before the maven-compiler-plugin in your pom.xml file:
Incremental compilation
To make your builds faster, you can enable incremental compilation for Maven by defining the kotlin.compiler.incremental property:
Alternatively, run your build with the -Dkotlin.compiler.incremental=true option.
Annotation processing
Jar file
To create a small Jar file containing just the code from your module, include the following under build->plugins in your Maven pom.xml file, where main.class is defined as a property and points to the main Kotlin or Java class:
Self-contained Jar file
To create a self-contained Jar file containing the code from your module along with dependencies, include the following under build->plugins in your Maven pom.xml file, where main.class is defined as a property and points to the main Kotlin or Java class:
This self-contained jar file can be passed directly to a JRE to run your application:
Specifying compiler options
Additional options and arguments for the compiler can be specified as tags under the element of the Maven plugin node:
Many of the options can also be configured through properties:
The following attributes are supported: