I'm trying to add some Kotlin classes into my existing Java project under Vaadin Framework (v 8.4.5).
I've fully read the tutorial on how to mixing java and Kotlin, and I've successfully created a Kotlin class inside my existing Java Project.
The new Kotlin class is inside my project (ofc I've cutted away all code for privacy)
package it.projectName.utils
import it.projectName.otherClasses
class SecurityUtils (user: User) {
//various val and var, and of course the isCrypted calculated val
init {
if(!isCrypted){
//encrypt user password
}
}
}
Now I'm using this Kotlin class inside my Java class with
import it.projectName.utils.SecurityUtils;
public class UserDao{
//[... other code ...]
SecurityUtils securityUtils = new SecurityUtils(user);
}
Everything is fine, I don't get any compiler error.
But when I try to run my project with maven with jetty:run , it throws an error:
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] /C:/pathToClass/UserDao.java:[9,36] cannot find symbol
symbol: class SecurityUtils
location: package it.projectName.utils
[INFO] 1 error
[INFO] -------------------------------------------------------------
The line he's referring to is import it.projectName.utils.SecurityUtils;
I've checked my pom.xml, everything looks fine there aswell:
<properties>
<kotlin.version>1.2.61</kotlin.version>
<kotlin.compiler.incremental>true</kotlin.compiler.incremental>
</properties>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test</artifactId>
<version>${kotlin.version}</version>
<scope>test</scope>
</dependency>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>src/main/java</sourceDir>
<sourceDir>src/main/kotlin</sourceDir>
</sourceDirs>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>src/main/java</sourceDir>
<sourceDir>src/main/kotlin</sourceDir>
</sourceDirs>
</configuration>
</execution>
</executions>
<configuration>
<jvmTarget>1.8</jvmTarget>
</configuration>
</plugin>
What I'm missing?
Thanks
We have to use two different source directories for each, under the src/main directory. (I'm talking about maven folder structure).
For example for Java, it is src/main/java and for Kotlin, it's like src/main/kotlin.
As per the documentation here, under topic of Compiling Kotlin and Java sources, JetBrains provides comprehensive maven plugin to declare each of aforementioned directories as their corresponding source directory. So then the compiler can detect both source directories, and in the building process, able to copy respective binary files to the class path.
Here is that maven plugin declaration,
<build>
<plugins>
<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>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<executions>
<!-- Replacing default-compile as it is treated specially by maven -->
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<!-- Replacing default-testCompile as it is treated specially by maven -->
<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>
</plugins>
Also, I personally recommend following property must be there to increase the speed of build process.
<properties>
<kotlin.compiler.incremental>true</kotlin.compiler.incremental>
</properties>
This one had worked for me pretty well, even if you creating a maven project with modules.
Related
I have a Multi-module Maven project. I had to import a maven module Vader (which uses a mix of Kotlin 1.5.0 and Java 11) and use it as a dependency for one of my modules which purely uses java 11. The code compiles well but at runtime I get this error:
java.lang.UnsupportedClassVersionError: org/revcloud/vader/matchers/AnyMatchers has been compiled by a more recent version of the Java Runtime (class file version 59.0), this version of the Java Runtime only recognizes class file versions up to 55.0
The file for which I get this error is a .kt file in my dependency module. I don’t get this error for java files. On the dependency module (vader) I made sure jvmTarget is set to java 11 and jdkHome points to java 11. I even confirmed by running javap -verbose AnyMatchers.class | grep “major” which gives me major version: 55
I am clueless as to what am I missing, where is this 59.0 coming from? Even my system only has JDK 11 and JDK 15 is not installed.
PFB the <build> section of pom.xml for dependency project(vader). (This has lombok too. So I delombok first into target/delombok and kotlin-maven-plugin picks up sources from this place. However none of the lombok annotations are used in Kotlin classes)
<build>
<sourceDirectory>${project.build.directory}/delombok</sourceDirectory>
<testSourceDirectory>${project.build.directory}/delombok-test</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<configuration>
<jvmTarget>${kotlin.compiler.jvmTarget}</jvmTarget>
<jdkHome>${kotlin.compiler.jdkHome}</jdkHome>
</configuration>
<executions>
<execution>
<id>compile</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>${project.build.directory}/delombok</sourceDir>
</sourceDirs>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<goals>
<goal>test-compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>${project.build.directory}/delombok-test</sourceDir>
</sourceDirs>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-maven-plugin</artifactId>
<version>${lombok.version}.0</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
<executions>
<execution>
<id>delombok</id>
<phase>generate-sources</phase>
<goals>
<goal>delombok</goal>
</goals>
<configuration>
<sourceDirectory>src/main/java</sourceDirectory>
<outputDirectory>${project.build.directory}/delombok</outputDirectory>
<addOutputDirectory>false</addOutputDirectory>
</configuration>
</execution>
<execution>
<id>delombok-test</id>
<phase>generate-test-sources</phase>
<goals>
<goal>delombok</goal>
</goals>
<configuration>
<sourceDirectory>src/test/java</sourceDirectory>
<outputDirectory>${project.build.directory}/delombok-test</outputDirectory>
<addOutputDirectory>false</addOutputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${kotlin.compiler.jvmTarget}</source>
<target>${kotlin.compiler.jvmTarget}</target>
</configuration>
<executions>
<!-- Replacing default-compile as it is treated specially by maven -->
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<!-- Replacing default-testCompile as it is treated specially by maven -->
<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>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
</plugin>
</plugins>
</build>
Figured it out, had to change the Target JVM version for the Kotlin Compiler in Intellij
When I compile Scala sources this pom.xml works :
<build>
<sourceDirectory>${project.basedir}/src/main/scala</sourceDirectory>
<plugins>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>4.4.0</version>
<executions>
<execution>
<id>scala-compile-first</id>
<phase>process-resources</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
[...]
But not this alternative :
<build>
<plugins>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>4.4.0</version>
<executions>
<execution>
<id>scala-compile-first</id>
<phase>process-resources</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<sourceDir>${project.basedir}/src/main/scala</sourceDir>
<testSourceDir>${project.basedir}/src/test/scala</testSourceDir>
</configuration>
</execution>
[...]
Even if sourceDir and testSourceDir are mentioned in the plugin documentation for this usage.
I need the second alternative because I this execution is followed by a call to the Java compiler that relies on other source file directory.
I tried a call to the add-source goal too. Without success.
You tried to override de configuration with something wrong, I guess ${project.basedir} is not replaced by the expected value.
What you want is the default behavior, so you can simply remove the override
<build>
<plugins>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>4.4.0</version>
<executions>
<execution>
<id>scala-compile-first</id>
<phase>process-resources</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
Update: Check the log (output) to see which folder the plugin scan for compilation.
Recently we changed maven version to 3.5.4
According to https://issues.apache.org/jira/browse/MNG-5940
the maven-source-plugin jar goal has been changed into jar-no-fork in Maven Super POM
We have company master pom:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
which one I can not change.
Together with maven super pom in effective pom I got
<plugin>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
<goal>jar</goal>
</goals>
</execution>
</executions>
<inherited>true</inherited>
</plugin>
During release sources are generated twice (one file override the second one) but on deployment to Artifactory I got error because of no rights to override artifacts.
Can I configure some how my pom to disable one goal for plugin?
You need to remove the execution from your parent pom (it's enough to remove the default phase) and add a new execution with the new goal:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>attach-sources</id>
<phase/>
</execution>
<execution>
<id>custom-attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
<inherited>true</inherited>
</plugin>
I'm working on a mixed java and kotlin project by using maven.
The problem I'm facing right now is, maven-compiler-plugin runs before compiling kotlin-maven-plugin.
[INFO] --- maven-compiler-plugin:3.0:compile (default-compile) #annotation ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 11 source files to /Users/hannes/workspace/tikxml/annotation/target/classes
[INFO] --- kotlin-maven-plugin:1.0.0-beta-4583:compile (compile) # annotation
[INFO] Kotlin Compiler version 1.0.0-beta-4583
In my java source code I'm referencing classes written in kotlin. But javac runs before kotlinc. Hence, maven interrupts with compiler errors.
My pom (parent pom, I use submodules) looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.sonatype.oss</groupId>
<artifactId>oss-parent</artifactId>
<version>7</version>
</parent>
...
<modules>
<module>core</module>
<module>annotation</module>
<module>processor</module>
</modules>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.7</java.version>
<kotlin.version>1.0.0-beta-4583</kotlin.version>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<sourceDirs>
<source>src/main/java</source>
</sourceDirs>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
<configuration>
<sourceDirs>
<source>src/test/java</source>
</sourceDirs>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
The Kotlin documentation on Using Maven suggests explicitly binding the kotlin-maven-plugin execution to the process-sources phase. Since maven-compiler-plugin is bound to the compile phase, binding kotlin-maven-plugin to the process-sources phase makes it run first.
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<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>
Although it's more verbose, you can compile both Java and Kotlin sources in the compile phase with the following configuration:
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>kotlin-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>kotlin-test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5</version>
<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>
Normally, plugins are executed in the order they are declared in the POM, but the executions of default-compile and default-testCompile are special because they're built-in, so they always go first. The above configuration gets around that by disabling the default compile executions, and declaring maven-compiler-plugin with new compilation executions after the kotlin-maven-plugin. In this way, you can get all compilation to properly occur during the compile phase of the build lifecycle.
A simple but effective solution would be to change the two phases (the <phase> element) applied to the executions of the Kotlin Maven Plugin, from compile to process-sources and from test-compile to process-test-sources.
You want the Kotlin part to be executed before the Java one. Maven by default will invoke the Maven Compiler Plugin as part of the compile phase for source code, and test-compile for test code. Moving the Kotlin part to their previous phases would then make the flow as you wished.
If you wanted the opposite (first Java then Kotlin), then you could have moved the Kotlin part to the next phases (as an example: from compile to process-classes and from test-compile to process-test-classes).
For further details about Maven phases, check the official documentation.
In case you are open to using a different build system, dependent projects are easy to set up with Kobalt:
val p1 = javaProject { ... }
val p2 = kotlinProject(p1) { ... }
This makes project p2 depend on p1. You can also mix Java and Kotlin projects.
I see a lot of similar questions. But unable to make this work.
I have tried testresources and build-helper-maven-plugin so far
Also I read in 1 thread how to write my own assembly plugin to do something like that.
But posting this again to see if there are cleaner ways that I don't know of
This is existing code and i got to fix it. The thing is when i open the jar after a successful build i am unable to find the src/test/java classes inside the jar. We got a maven build-helper-maven-plugin and maven-jar-plugin. But I don't see the test classes in it still.
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>src/test/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>test</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
I see the generated classes in a test-classes directory inside the target folder. But not inside the jar
I want them inside the jar as I am depending on that jar in another project. The other project is not compiling because its importing that test class inside src/test/Java
I cannot create a new project just for this case as I don't have that liberty.
Did you try maven-dependency-plugin (instead of build-helper-maven-plugin) in combination with maven-jar-plugin ?
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.9</version><!--$NO-MVN-MAN-VER$-->
<executions>
<execution>
<id>unpack</id>
<phase>prepare-package</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>you-project-group-id</groupId>
<artifactId>you-project-artifact-id</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<overWrite>false</overWrite>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>