Mixed Kotlin + Java with Maven, unresolved reference

Viewed 7662

I have a Maven project with Kotlin code hello.kt which calls Java code JavaFoo.java which calls Kotlin code KotlinFoo.kt. hello.kt also calls KotlinFoo.kt directly. I'm trying to build this with mvn clean install using exactly the Maven settings described in kotlinlang's Maven docs.

If hello.kt doesn't call JavaFoo (but I leave JavaFoo in the project) then this builds just fine.

The docs say that the Kotlin compiler should be invoked before the Java compiler, which suggests to me that all Kotlin code needs to compile before any Java code, i.e. with this setup you can call Kotlin from Java but not vice versa. However, the docs describe this setup as just "mixed code applications", not "calling Kotlin from Java".

In other words, this failure seems consistent with what the docs seem to imply but not with what they directly say -- or I'm just misunderstanding something.

I want to call each language from the other. Is there a Maven configuration that will do this, please?

(I looked at various StackExchange questions on mixed code settings and none of the solutions works for me.)

Adding the code as requested: pom.xml:

<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example.kotlindemo</groupId>
    <artifactId>kotlin-demo</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>kotlin-demo</name>

    <properties>
        <kotlin.version>1.1.2-2</kotlin.version> 
        <kotlin.compiler.incremental>true</kotlin.compiler.incremental>
        <main.class>com.example.kotlindemo.HelloKt</main.class>
    </properties>

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

    <build>
        <plugins>
            <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>
                        <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>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.6</version>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals> <goal>single</goal> </goals>
                        <configuration>
                            <archive>
                                <manifest>
                                    <mainClass>${main.class}</mainClass>
                                </manifest>
                            </archive>
                            <descriptorRefs>
                                <descriptorRef>jar-with-dependencies</descriptorRef>
                            </descriptorRefs>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

src/main/kotlin/hello.kt:

package com.example.kotlindemo

fun main(args : Array<String>) { 
  println("Hello, world!") 

  var kfoo = KotlinFoo()
  kfoo.printFooString()

  kfoo.fooString = "init2"
  kfoo.printFooString()

  var foo2 = JavaFoo("abcd")
  foo2.printString()
}

src/main/kotlin/KotlinFoo.kt:

package com.example.kotlindemo

class KotlinFoo {
    var fooString = "init"

    fun printFooString() {
        println(this.fooString) 
    }
}

src/main/java/JavaFoo.java:

package com.example.kotlindemo;

class JavaFoo {
    private KotlinFoo k;

    JavaFoo(String initializer) {
        k = new KotlinFoo();
        k.setFooString(initializer);
    }

    void printString() {
        this.k.printFooString();
    }
}

Error:

[ERROR] .../src/main/kotlin/hello.kt: (12, 14) Unresolved reference: JavaFoo
2 Answers

If you are using maven, you need to add the goal: <goal>addSources</goal>

Like this:

<executions>
    <execution>
        <goals>
            <goal>addSources</goal>
            <goal>addTestSources</goal>
            <goal>generateStubs</goal>
            <goal>compile</goal>
            <goal>testGenerateStubs</goal>
            <goal>testCompile</goal>
            <goal>removeStubs</goal>
            <goal>removeTestStubs</goal>
        </goals>
    </execution>
</executions>

Related