Learn through the super-clean Baeldung Pro experience:
>> Membership and Baeldung Pro.
No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.
Last updated: March 19, 2024
In this quick tutorial, we’ll see how to set up a Maven project handling both Java and Kotlin sources.
We’ll first create a project for Java sources only. We’ll then add the kotlin-maven-plugin to handle Kotlin as well.
And finally, we’ll add some dummy classes, package our application, and test if everything works as expected.
First of all, let’s create a straightforward Java project with Maven:
<artifactId>maven-java-kotlin</artifactId>
<packaging>jar</packaging>
<properties>
<java.version>11</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
This pom file contains all we need to compile Java sources and package them into a jar file.
Now we need to tune this pom file so that it can handle Kotlin sources as well.
Let’s first add kotlin.version to our properties and kotlin-stdlib to our dependencies. This way we’ll have access to Kotlin features:
<properties>
<java.version>11</java.version>
<kotlin.version>1.8.0</kotlin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
Then, we need to add the kotlin-maven-plugin to our Maven plugins.
We’ll configure it to handle both compile and test-compile goals, telling it where to find our sources.
By convention, we keep Java and Kotlin sources in different directories, though we could put them all in the same:
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>${project.basedir}/src/main/kotlin</sourceDir>
<sourceDir>${project.basedir}/src/main/java</sourceDir>
</sourceDirs>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<goals>
<goal>test-compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>${project.basedir}/src/test/kotlin</sourceDir>
<sourceDir>${project.basedir}/src/test/java</sourceDir>
</sourceDirs>
</configuration>
</execution>
</executions>
</plugin>
This is nearly the end of the configuration. We need to adapt maven-compiler-plugin configuration as we need Kotlin sources to be compiled before Java sources.
Frequently, Maven plugins executions happen according to the declaration order. So we should place maven-compiler-plugin after kotlin-maven-plugin. But the former has two specific executions that are executed before everything else during the phases: default-compile and default-testCompile.
We need to disable them and enable java-compile and java-test-compile instead to ensure that kotlin-maven-plugin execution will happen before maven-compiler-plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
<executions>
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<execution>
<id>default-testCompile</id>
<phase>none</phase>
</execution>
<execution>
<id>java-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>java-test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
We can see that the default executions are disabled using phase none, and Java-specific executions are bound to compile and test-compile phases.
Now that we have correctly set everything up let’s say hello to the world… from both Java and Kotlin.
To do that, let’s create an Application class with a main() method. This method will either call a Java or a Kotlin class according to its first argument:
public class Application {
static String JAVA = "java";
static String KOTLIN = "kotlin";
public static void main(String[] args) {
String language = args[0];
switch (language) {
case JAVA:
new JavaService().sayHello();
break;
case KOTLIN:
new KotlinService().sayHello();
break;
default:
// Do nothing
break;
}
}
}
The JavaService and KotlinService classes are simply saying “Hello World!”:
public class JavaService {
public void sayHello() {
System.out.println("Java says 'Hello World!'");
}
}
class KotlinService {
fun sayHello() {
System.out.println("Kotlin says 'Hello World!'")
}
}
We can now compile and package our application by calling mvn package command.
Let’s test the produced jar by running the following commands in a terminal:
java -cp maven-java-kotlin-1.0.0-SNAPSHOT.jar path.to.your.Class "java"
As we can see this calls the JavaService class which prints to the console “Java says ‘Hello World!'”.
java -cp maven-java-kotlin-1.0.0-SNAPSHOT.jar path.to.your.Class "kotlin"
And this one calls KotlinService class, which prints “Kotlin says ‘Hello World!'”.
In this article, we focused on how to create a Maven project handling both Java and Kotlin sources, compiling and packaging them into a jar.