Знакомство с Kotlin и сборка jar при помощи maven

в 10:37, , рубрики: IDE, idea, jar, java, jetbrains, kotlin, Программирование

Это пост заметка о том, как я познакомился с языком 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<String>) {
//    println("Hello, world!")
//}

//fun main(args : Array<String>) {
//    if (args.size == 0) {
//        println("Please provide a name as a command-line argument")
//        return
//    }
//    println("Hello, ${args[0]}!")
//}

/*fun main(args : Array<String>) {
    for (name in args)
        println("Hello, $name!")
}*/

fun main(args: Array<String>) {
    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

Вот мой pom.xml файл

<?xml version="1.0" encoding="UTF-8"?>
<project
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
        xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <modelVersion>4.0.0</modelVersion>

    <groupId>org.jetbrains.kotlin.examples</groupId>
    <artifactId>idea_test</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>idea_test</name>
    <url>http://maven.apache.org</url>

    <properties>
        <kotlin.version>0.1-SNAPSHOT</kotlin.version>
        <junit.version>4.10</junit.version>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-stdlib</artifactId>
            <version>${kotlin.version}</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <!-- Build an executable JAR -->
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib/</classpathPrefix>
                            <mainClass>testing.first</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>kotlin-maven-plugin</artifactId>
                <groupId>org.jetbrains.kotlin</groupId>
                <version>${kotlin.version}</version>

                <configuration><sourceDirs>
                   < source > src/ < / s ource >
               </sourceDirs></configuration>

                <executions>
                    <execution>
                        <id>compile</id>
                        <phase>process-sources</phase>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>test-compile</id>
                        <phase>process-test-sources</phase>
                        <goals>
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>sonatype.oss.snapshots</id>
            <name>Sonatype OSS Snapshot Repository</name>
            <url>http://oss.sonatype.org/content/repositories/snapshots</url>
            <releases>
                <enabled>false</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>sonatype.oss.snapshots</id>
            <name>Sonatype OSS Snapshot Repository</name>
            <url>http://oss.sonatype.org/content/repositories/snapshots</url>
            <releases>
                <enabled>false</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>

</project>

Тут используется настройка для 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.

Вот что надо добавить к pom.xml

<plugin>
    <groupId>org.dstovall</groupId>
    <artifactId>onejar-maven-plugin</artifactId>
    <version>1.4.5</version>
    <executions>
        <execution>
            <configuration>
                <binlibs>
                    <fileSet>
                        <directory>${project.build.directory}/../lib/</directory>
                        <includes>
                            <include>kotlin-runtime.jar</include>
                        </includes>
                    </fileSet>
                </binlibs>
                <!-- Optional, default is false -->
                <attachToBuild>true</attachToBuild>
                <!-- Optional, default is "onejar" -->
                <classifier>onejar</classifier>
            </configuration>
            <goals>
                <goal>one-jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>

<pluginRepository>
    <id>onejar-maven-plugin.googlecode.com</id>
    <url>http://onejar-maven-plugin.googlecode.com/svn/mavenrepo</url>
</pluginRepository>

Далее пересобрать проект.

mvn package

В директории /target появится файл имяпроекта.one-jar.jar. Его можно вызвать обычным методом.

java -jar target/idea_test-1.0-SNAPSHOT.one-jar.jar seyfer
Hello seyfer
seed!

На этом настройка проекта для меня закончена. Далее можно изучать Kotlin по приведенным выше ссылкам на документацию.
Лично мне язык очень понравился. Несомненно он займет свою нишу, так же, как и язык hack, который разрабатывает Facebook, как свою версию PHP.

Официальная страница Kotlin.
http://kotlin.jetbrains.org/

Редактор с исполнением в браузере с примерами.
http://kotlin-demo.jetbrains.com/

Кстати, на Kotlin уже написан web framework.
http://karaframework.com/

Автор:

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js