Kotlin Controllers are not able to resolve Twirl templates
I started with a very simple Play application which has a Controller in Kotlin that references a Twirl template. The Twirl needs to be complied before the Kotlin so that the generated class is visible, but the Kotlin appears to be compiled first resulting in errors:
[info] Compiling 2 Kotlin sources
[error] /Users/apowell/dev/kotlin-play-poc/app/controllers/HomeController.kt: 6, 19: Unresolved reference: index
[error] /Users/apowell/dev/kotlin-play-poc/app/controllers/HomeController.kt: 11, 27: Unresolved reference: index
[error] Compilation failed. See log for more details
[error] (compile:kotlinCompile) Compilation failed. See log for more details
My Controller is:
package controllers
import play.mvc.Controller
import play.mvc.Result
import play.mvc.Results
import views.html.index
class HomeController : Controller() {
fun home(): Result {
return Results.ok(index.apply("Your new application is ready"))
}
}
If I remove the reference to the Twirl template (eg: return Results.ok("Kotlin controller is working")) then the compilation is successful, Java controllers can reference this template and the application runs.
Is there a way to force the Twirl/scala compilation to happen first?
kotlin cannot compile before scala in this plugin. This is due to mix-mode scala+java+kotlin support.
If twirl compiles directly to classes, you can make kotlinCompile depend on twirl:
kotlinCompile in Compile := ((kotlinCompile in Compile) dependsOn theTwirlTaskIDontKnowWhatItIs).value
I'll see if I can find out the name of that task, thanks for the pointer.
kotlinCompile in Compile := ((kotlinCompile in Compile) dependsOn (TwirlKeys.compileTemplates in Compile)).value
will compile the Twirl templates, but the task doesn't result in .class files but rather some .scala files under target/scala-1.12/twirl/main/views/html.
Since the Kotlin Controller needs to import and reference these as classes, it sounds like I would need a mix-mode scala+java+kotlin which doesn't exist. Thanks for your help.
You will need to remove the dependency on kotlinCompile from compile (see how it's defined in Defaults.scala for sbt and re-declare it); it will look something like the following:
// fix task scopes as necessary.
compile in Compile := Defaults.compileTask.value
compile in Compile := { // this will make kotlinCompile run after compile
KotlinCompile.compile(kotlincOptions.value,
sourceDirectories.value, kotlincPluginOptions.value,
dependencyClasspath.value, (managedClasspath in KotlinInternal).value,
classDirectory.value, streams.value)
(compile in Compile).value
},