Skip to content

Commit 95b9fe7

Browse files
rockjamggrossetie
authored andcommitted
twirl that works with scala API
1 parent f3ac2f4 commit 95b9fe7

File tree

2 files changed

+42
-81
lines changed

2 files changed

+42
-81
lines changed

twirllib/src/mill/twirllib/TwirlModule.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ trait TwirlModule extends mill.Module {
2323
MavenRepository("https://repo1.maven.org/maven2")
2424
),
2525
Lib.depToDependency(_, "2.12.4"),
26-
Seq(ivy"com.typesafe.play::twirl-compiler:${twirlVersion()}")
26+
Seq(
27+
ivy"com.typesafe.play::twirl-compiler:${twirlVersion()}",
28+
ivy"org.scala-lang.modules::scala-parser-combinators:1.0.5"
29+
)
2730
)
2831
}
2932

twirllib/src/mill/twirllib/TwirlWorker.scala

Lines changed: 38 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -3,104 +3,62 @@ package twirllib
33

44
import java.io.File
55
import java.net.URLClassLoader
6-
import java.util
76

87
import ammonite.ops.{Path, ls}
98
import mill.eval.PathRef
109
import mill.scalalib.CompilationResult
1110

1211
import scala.io.Codec
13-
import scala.reflect.runtime.universe._
1412
import scala.util.Properties
1513

1614
class TwirlWorker {
1715

1816
private var twirlInstanceCache = Option.empty[(Long, TwirlWorkerApi)]
19-
import scala.collection.JavaConverters._
2017

2118
private def twirl(twirlClasspath: Agg[Path]) = {
2219
val classloaderSig = twirlClasspath.map(p => p.toString().hashCode + p.mtime.toMillis).sum
2320
twirlInstanceCache match {
2421
case Some((sig, instance)) if sig == classloaderSig => instance
2522
case _ =>
26-
//callScalaAPI(twirlClasspath, classloaderSig)
27-
callJavaAPI(twirlClasspath, classloaderSig)
28-
}
29-
}
30-
31-
private def callJavaAPI(twirlClasspath: Agg[Path], classloaderSig: Long) = {
32-
val cl = new URLClassLoader(twirlClasspath.map(_.toIO.toURI.toURL).toArray)
33-
val twirlCompilerClass = cl.loadClass("play.japi.twirl.compiler.TwirlCompiler")
34-
// Use the Java API (available in Twirl 1.3+)
35-
// Using reflection on a method with "Seq[String] = Nil" parameter type does not seem to work.
36-
37-
// REMIND: Unable to call the compile method with a primitive boolean
38-
// codec and inclusiveDot will not be available
39-
val compileMethod = twirlCompilerClass.getMethod("compile",
40-
classOf[File],
41-
classOf[File],
42-
classOf[File],
43-
classOf[String],
44-
classOf[util.Collection[String]],
45-
classOf[util.List[String]])
46-
47-
val instance = new TwirlWorkerApi {
48-
override def compileTwirl(source: File,
49-
sourceDirectory: File,
50-
generatedDirectory: File,
51-
formatterType: String,
52-
additionalImports: Seq[String] = Nil,
53-
constructorAnnotations: Seq[String] = Nil,
54-
codec: Codec = Codec(Properties.sourceEncoding),
55-
inclusiveDot: Boolean = false) {
56-
val o = compileMethod.invoke(null, source,
57-
sourceDirectory,
58-
generatedDirectory,
59-
formatterType,
60-
additionalImports.asJava,
61-
constructorAnnotations.asJava)
62-
}
63-
}
64-
twirlInstanceCache = Some((classloaderSig, instance))
65-
instance
66-
}
67-
68-
private def callScalaAPI(twirlClasspath: Agg[Path], classloaderSig: Long) = {
69-
val cl = new URLClassLoader(twirlClasspath.map(_.toIO.toURI.toURL).toArray)
70-
val runtime = runtimeMirror(cl)
71-
val moduleMirror = runtime.reflectModule(runtime.staticModule("play.twirl.compiler.TwirlCompiler"))
72-
val moduleInstance = moduleMirror.instance
73-
val instanceMirror = runtime.reflect(moduleInstance)
74-
val compileSymbol = instanceMirror.symbol.typeSignature.member(TermName("compile")).asMethod
75-
// FIXME: type erasure, unable to call "play.twirl.compiler.TwirlCompiler.compile" function
76-
// https://github.com/playframework/twirl/blob/dd56444cf9ea2f95ef3961d3af911561f846df50/compiler/src/main/scala/play/twirl/compiler/TwirlCompiler.scala#L167
77-
val instance = new TwirlWorkerApi {
78-
override def compileTwirl(source: File,
79-
sourceDirectory: File,
80-
generatedDirectory: File,
81-
formatterType: String,
82-
additionalImports: Seq[String] = Nil,
83-
constructorAnnotations: Seq[String] = Nil,
84-
codec: Codec = Codec(Properties.sourceEncoding),
85-
inclusiveDot: Boolean = false) {
86-
87-
// scala.MatchError: List() (of class scala.collection.immutable.Nil$)
88-
// at scala.reflect.runtime.JavaMirrors$JavaMirror$DerivedValueClassMetadata.unboxer$lzycompute(JavaMirrors.scala:270)
89-
// at scala.reflect.runtime.JavaMirrors$JavaMirror$DerivedValueClassMetadata.unboxer(JavaMirrors.scala:269)
90-
// at scala.reflect.runtime.JavaMirrors$JavaMirror$MethodMetadata.paramUnboxers(JavaMirrors.scala:416)
91-
// at scala.reflect.runtime.JavaMirrors$JavaMirror$JavaTransformingMethodMirror.apply(JavaMirrors.scala:435)
92-
instanceMirror.reflectMethod(compileSymbol)(source,
93-
sourceDirectory,
94-
generatedDirectory,
95-
formatterType,
96-
additionalImports,
97-
constructorAnnotations,
98-
codec,
99-
inclusiveDot)
100-
}
23+
val cl = new URLClassLoader(twirlClasspath.map(_.toIO.toURI.toURL).toArray)
24+
val twirlCompilerClass = cl.loadClass("play.twirl.compiler.TwirlCompiler")
25+
val compileMethod = twirlCompilerClass.getMethod("compile",
26+
classOf[java.io.File],
27+
classOf[java.io.File],
28+
classOf[java.io.File],
29+
classOf[java.lang.String],
30+
cl.loadClass("scala.collection.Seq"),
31+
cl.loadClass("scala.collection.Seq"),
32+
cl.loadClass("scala.io.Codec"),
33+
classOf[Boolean])
34+
35+
val defaultAdditionalImportsMethod = twirlCompilerClass.getMethod("compile$default$5")
36+
val defaultConstructorAnnotationsMethod = twirlCompilerClass.getMethod("compile$default$6")
37+
val defaultCodecMethod = twirlCompilerClass.getMethod("compile$default$7")
38+
val defaultFlagMethod = twirlCompilerClass.getMethod("compile$default$8")
39+
40+
val instance = new TwirlWorkerApi {
41+
override def compileTwirl(source: File,
42+
sourceDirectory: File,
43+
generatedDirectory: File,
44+
formatterType: String,
45+
additionalImports: Seq[String] = Nil,
46+
constructorAnnotations: Seq[String] = Nil,
47+
codec: Codec = Codec(Properties.sourceEncoding),
48+
inclusiveDot: Boolean = false) {
49+
val o = compileMethod.invoke(null, source,
50+
sourceDirectory,
51+
generatedDirectory,
52+
formatterType,
53+
defaultAdditionalImportsMethod.invoke(additionalImports),
54+
defaultConstructorAnnotationsMethod.invoke(constructorAnnotations),
55+
defaultCodecMethod.invoke(codec),
56+
defaultFlagMethod.invoke(inclusiveDot))
57+
}
58+
}
59+
twirlInstanceCache = Some((classloaderSig, instance))
60+
instance
10161
}
102-
twirlInstanceCache = Some((classloaderSig, instance))
103-
instance
10462
}
10563

10664
def compile(twirlClasspath: Agg[Path], sourceDirectories: Seq[Path], dest: Path)

0 commit comments

Comments
 (0)