我正在使用scala play 2 + slick编写一个Web应用程序。我也想使用akka + scala-async。将 scala-async 的依赖项添加到我的项目并从播放控制台运行应用程序(使用“运行”命令)后,我的应用程序失败打造。但是,当我使用“dist”命令并运行网站时,一切正常正常。我知道这个问题在某种程度上与使用宏的scala-async相关联。
使用“run”命令构建时,我得到以下异常:
play.api.UnexpectedException: Unexpected exception[NoSuchMethodException: slick.
tables.Requests$.<init>()]
at play.core.ReloadableApplication$$anonfun$get$1$$anonfun$apply$1$$anon
fun$1.apply(ApplicationProvider.scala:148) ~[play_2.10-2.2.1.jar:2.2.1]
at play.core.ReloadableApplication$$anonfun$get$1$$anonfun$apply$1$$anon
fun$1.apply(ApplicationProvider.scala:112) ~[play_2.10-2.2.1.jar:2.2.1]
at scala.Option.map(Option.scala:145) ~[scala-library-2.10.3.jar:na]
at play.core.ReloadableApplication$$anonfun$get$1$$anonfun$apply$1.apply
(ApplicationProvider.scala:112) ~[play_2.10-2.2.1.jar:2.2.1]
at play.core.ReloadableApplication$$anonfun$get$1$$anonfun$apply$1.apply
(ApplicationProvider.scala:110) ~[play_2.10-2.2.1.jar:2.2.1]
at scala.util.Success.flatMap(Try.scala:200) ~[scala-library-2.10.3.jar:
na]
Caused by: java.lang.NoSuchMethodException: slick.tables.Requests$.<init>()
at java.lang.Class.getConstructor0(Class.java:2800) ~[na:1.7.0_40]
at java.lang.Class.getConstructor(Class.java:1708) ~[na:1.7.0_40]
at scala.reflect.runtime.JavaMirrors$JavaMirror$$anonfun$constructorToJa
va$1.apply(JavaMirrors.scala:1242) ~[scala-reflect-2.10.3.jar:na]
at scala.reflect.runtime.JavaMirrors$JavaMirror$$anonfun$constructorToJa
va$1.apply(JavaMirrors.scala:1236) ~[scala-reflect-2.10.3.jar:na]
at scala.reflect.runtime.TwoWayCache.toJava(TwoWayCache.scala:49) ~[scal
a-reflect-2.10.3.jar:na]
at scala.reflect.runtime.JavaMirrors$JavaMirror.constructorToJava(JavaMi
rrors.scala:1236) ~[scala-reflect-2.10.3.jar:na]
如何使其有效?
修改
我知道这个问题在某种程度上与使用宏的 scala-async 有关,因为当我尝试使用我的宏来生成 forInsert时会出现同样的错误我的光滑表中的语句,而不依赖于 scala-async 。
最近我发现了另一件有趣的事情。 如果我使用 class 而不是 object 来描述我的光滑表,则错误消失。虽然在这种情况下,play框架会启动无休止的重新编译循环我用我的宏。
修改
这是我的Buid.scala
import sbt._
import Keys._
import Defaults.defaultSettings
import org.scalastyle.sbt.ScalastylePlugin.{Settings => scalastyleSettings}
import play.Project.playScalaSettings
import net.virtualvoid.sbt.graph.Plugin.graphSettings
object Resolvers {
val typesafe = Resolver.typesafeRepo("releases")
val sonatype = Resolver.sonatypeRepo("releases")
}
import Resolvers._
object Dependencies {
val scalatest = "org.scalatest" %% "scalatest" % "1.9.2" % "test"
val scalamock = "org.scalamock" %% "scalamock-scalatest-support" % "3.0.1" % "test"
val scalaz = "org.scalaz" %% "scalaz-core" % "7.0.4"
val akka = "com.typesafe.akka" %% "akka-actor" % "2.2.3"
val slickorm = "com.typesafe.slick" %% "slick" % "1.0.1"
val scalacheck = "org.scalacheck" %% "scalacheck" % "1.10.1" % "test"
val webjarsPlay = "org.webjars" %% "webjars-play" % "2.2.0"
val underscorejs = "org.webjars" % "underscorejs" % "1.5.1"
val jquery = "org.webjars" % "jquery" % "2.0.3-1"
val angularjs = "org.webjars" % "angularjs" % "1.2.0-rc.3"
val angularui = "org.webjars" % "angular-ui-bootstrap" % "0.6.0-1"
val bootstrap = "org.webjars" % "bootstrap" % "2.3.2" exclude("org.webjars", "jquery")
val requirejs = "org.webjars" % "requirejs" % "2.1.8"
val playSlick = "com.typesafe.play" %% "play-slick" % "0.5.0.8"
val logback = "ch.qos.logback" % "logback-classic" % "1.0.13"
val postgresql = "postgresql" % "postgresql" % "9.1-901.jdbc4"
val nscalaTime = "com.github.nscala-time" %% "nscala-time" % "0.6.0"
val scalaAsync = "org.scala-lang.modules" %% "scala-async" % "0.9.0-M4"
}
import Dependencies._
object BankSettings {
val bankSettings = Seq(
organization := "org.zeka",
version := "0.0.0-SNAPSHOT",
scalaVersion := "2.10.3",
scalacOptions := Seq(
"-optimise",
"-deprecation",
"-unchecked",
"-feature",
"-g:vars",
"-target:jvm-1.7",
"-encoding", "UTF-8",
"-language:postfixOps"
),
resolvers ++= Seq(
typesafe,
sonatype
)
)
}
import BankSettings._
object BankBuild extends Build {
lazy val bank = Project(
"bank",
file ("."),
settings = defaultSettings ++ scalastyleSettings ++ graphSettings ++ playScalaSettings ++ bankSettings ++ Seq(
libraryDependencies ++= Seq(
scalatest,
scalamock,
scalaz,
akka,
logback,
playSlick,
webjarsPlay,
bootstrap,
angularjs,
angularui
)
)
) dependsOn (common, logick, slick) aggregate (common, logick, slick)
lazy val common = Project(
"common",
file ("modules/common"),
settings = defaultSettings ++ scalastyleSettings ++ graphSettings ++ bankSettings ++ Seq(
libraryDependencies ++= Seq(
scalatest,
scalamock,
nscalaTime
)
)
)
lazy val logick = Project(
"logic",
file ("modules/logic"),
settings = defaultSettings ++ scalastyleSettings ++ graphSettings ++ bankSettings ++ Seq(
libraryDependencies ++= Seq(
scalatest,
scalamock,
akka,
scalaAsync
)
)
) dependsOn (common, slick)
lazy val slick = Project(
"slick",
file ("modules/slick"),
settings = defaultSettings ++ scalastyleSettings ++ graphSettings ++ bankSettings ++ Seq(
libraryDependencies ++= Seq(
scalatest,
scalamock,
akka,
slickorm,
postgresql
)
)
) dependsOn common
}
修改
这是我的宏。
package slick
import scala.language.experimental.macros
import scala.reflect.macros.Context
import scala.slick.driver.PostgresDriver.simple._
import scala.slick.lifted.ColumnBase
import scala.reflect.api.Liftable._
object SlickMacro {
def *[T]: ColumnBase[T] = macro starImpl[T]
def starImpl[T: c.WeakTypeTag](c: Context): c.Expr[ColumnBase[T]] = {
import c.universe._
val tpe = weakTypeOf[T]
if (!tpe.typeSymbol.asClass.isCaseClass) {
c.abort(c.enclosingPosition, "not a case class")
} else {
val companion = tpe.typeSymbol.companionSymbol
val params = tpe.declarations.collectFirst {
case m: MethodSymbol if m.isPrimaryConstructor => m
}.get.paramss.head
def build(params: List[Symbol], acc: Tree): Tree = params match {
case Nil => acc
case h :: t => build(t, q"$acc ~ ${h.name}")
}
c.Expr[ColumnBase[T]] {
q"${build(params.tail, q"id.?")} <> ($companion, $companion.unapply _)"
}
}
}
def forInsert[T]: ColumnBase[T] = macro forInsertImpl[T]
def forInsertImpl[T: c.WeakTypeTag](c: Context): c.Expr[ColumnBase[T]] = {
import c.universe._
val tpe = weakTypeOf[T]
if (!tpe.typeSymbol.asClass.isCaseClass) {
c.abort(c.enclosingPosition, "not a case class")
} else {
val companion = tpe.typeSymbol.companionSymbol
val params = tpe.declarations.collectFirst {
case m: MethodSymbol if m.isPrimaryConstructor => m
}.get.paramss.head
def build(params: List[Symbol], acc: Tree): Tree = params match {
case Nil => acc
case h :: t => build(t, q"$acc ~ ${h.name}")
}
val paramsTail = params.tail
def l1 = (1 to paramsTail.size).map(i => q"x.${newTermName("_" + i)}")
def l2 = (2 to params.size).map(i => q"x.${newTermName("_" + i)}")
c.Expr[ColumnBase[T]] {
q"${build(paramsTail.tail, q"${paramsTail.head.name}")} <> ({ x => $companion(None, ..$l1) }, { (u: $tpe) => $companion.unapply(u).map(x => (..$l2)) })"
}
}
}
}