Play 在单独的包中找不到自定义 QueryString 活页夹
Play cannot find custom QueryString binder in separate package
尝试为 models.DeviceContext 实现我的第一个 QueryStringBindable:
case class DeviceContext( deviceIdLike: String = "", deviceUseridLike: String = "")
我有util.Binders.scala如下:
package util
import play.api.mvc.QueryStringBindable
import models._
object Binders {
implicit def deviceContextBinder(implicit stringBinder: QueryStringBindable[String]) =
new QueryStringBindable[DeviceContext] {
override def bind(key: String, params: java.util.Map[String, Array[String]]): Option[Either[String, DeviceContext]] = {
Some({
val deviceIdLike = stringBinder.bind(key + ".deviceIdLike", params)
val deviceIUseridLike = stringBinder.bind(key + ".deviceUseridLike", params)
(deviceIdLike.isDefined && deviceIUseridLike.isDefined) match {
case true => Right(DeviceContext(deviceIdLike.get, deviceIUseridLike.get))
case false => Left("Unable to bind DeviceContext")
}
})
}
override def unbind(key: String, deviceContext: DeviceContext): String =
stringBinder.unbind(
key + ".deviceIdLike=" + deviceContext.deviceIdLike +
"&" + key + ".deviceUserIdLike=" + deviceContext.deviceUseridLike)
}
}
改编自 documentation 中的示例。我的 build.sbt 文件试图使 util.Binders 对路由可见,其中:
import play.PlayImport.PlayKeys._
routesImport += "util.Binders._"
路线看起来像:
GET /device controllers.Devices.list(dc:models.DeviceContext)
然而,编译器并不高兴:
[error] \conf\routes:76: No QueryString binder found for type models.DeviceContext.
Try to implement an implicit QueryStringBindable for this type.
[error] GET /device controllers.Devices.list(deviceContext:DeviceContext)
[error] \conf\routes:76: not enough arguments for method implicitly: (implicit e: play.api.mvc.QueryStringBindable[models.DeviceContext])play.api.mvc.QueryStringBindable[models.DeviceContext].
[error] Unspecified value parameter e.
Scala版本是2.11.5,play是2.3.9
import util.Binders
是显式导入,因此应包含在隐式搜索中。就好像 implicit def deviceContextBinder
的签名不符合要求,但它 returns 是我的类型的 QueryStringBindable,所以我不明白为什么它不匹配。
感谢任何指点!
(附带说明,文档使用 params: Map[String,Seq[String]]
但如果我使用它,编译器会抱怨它期望 java.util.Map[String,Array[String]]
这看起来很奇怪......请参阅下面的答案。)
编辑 1:
当我使用标准数据类型时,为了不调用我的客户QueryStringBindable,而是将代码留在项目中,编译器随后报告新的错误,第一个错误是:
type arguments [String] do not conform to trait QueryStringBindable's type parameter bounds [T <: play.mvc.QueryStringBindable[T]]
而不是 routesImport += "util.Binders"
尝试 routesImport += "util.Binders._"
从对象中导入所有内容。
好吧,解决方案是我似乎必须将代码放在与案例 class 相同的包中。当我这样做时,上面提到的 java.util.Map "workaround" 解决了,因此,删除 Binders.scala 并将 DeviceContext.Scala 扩展到以下工作:
package models
case class DeviceContext(deviceIdLike: String = "", deviceUseridLike: String = "")
object DeviceContext {
import play.api.mvc.QueryStringBindable
implicit def deviceContextBinder(implicit stringBinder: QueryStringBindable[String]) =
new QueryStringBindable[DeviceContext] {
override def bind(key: String, params: Map[String, Seq[String]]): Option[Either[String, DeviceContext]] = {
Some({
val deviceIdLike = stringBinder.bind(key + ".deviceIdLike", params)
val deviceIUseridLike = stringBinder.bind(key + ".deviceUseridLike", params)
(deviceIdLike, deviceIUseridLike) match {
case (Some(Right(di)), Some(Right(du))) => Right(DeviceContext(di, du))
case _ => Left("Unable to bind DeviceContext")
}
})
}
override def unbind(key: String, deviceContext: DeviceContext): String =
stringBinder.unbind(
key + ".deviceIdLike", deviceContext.deviceIdLike) +
"&" + stringBinder.unbind(key + ".deviceUserIdLike", deviceContext.deviceUseridLike)
}
}
我还发现,如果我想在路由文件中以非限定方式引用我的类型,则 仅 需要 routesImports,即 controllers.Devices.list(dc:DeviceContext)
。如果我愿意把参数写成dc:models.DeviceContext
,那么就不需要routesImports了。
在我的例子中,我在错误的伴随对象中定义了 QueryStringBindable。
尝试为 models.DeviceContext 实现我的第一个 QueryStringBindable:
case class DeviceContext( deviceIdLike: String = "", deviceUseridLike: String = "")
我有util.Binders.scala如下:
package util
import play.api.mvc.QueryStringBindable
import models._
object Binders {
implicit def deviceContextBinder(implicit stringBinder: QueryStringBindable[String]) =
new QueryStringBindable[DeviceContext] {
override def bind(key: String, params: java.util.Map[String, Array[String]]): Option[Either[String, DeviceContext]] = {
Some({
val deviceIdLike = stringBinder.bind(key + ".deviceIdLike", params)
val deviceIUseridLike = stringBinder.bind(key + ".deviceUseridLike", params)
(deviceIdLike.isDefined && deviceIUseridLike.isDefined) match {
case true => Right(DeviceContext(deviceIdLike.get, deviceIUseridLike.get))
case false => Left("Unable to bind DeviceContext")
}
})
}
override def unbind(key: String, deviceContext: DeviceContext): String =
stringBinder.unbind(
key + ".deviceIdLike=" + deviceContext.deviceIdLike +
"&" + key + ".deviceUserIdLike=" + deviceContext.deviceUseridLike)
}
}
改编自 documentation 中的示例。我的 build.sbt 文件试图使 util.Binders 对路由可见,其中:
import play.PlayImport.PlayKeys._
routesImport += "util.Binders._"
路线看起来像:
GET /device controllers.Devices.list(dc:models.DeviceContext)
然而,编译器并不高兴:
[error] \conf\routes:76: No QueryString binder found for type models.DeviceContext. Try to implement an implicit QueryStringBindable for this type. [error] GET /device controllers.Devices.list(deviceContext:DeviceContext)
[error] \conf\routes:76: not enough arguments for method implicitly: (implicit e: play.api.mvc.QueryStringBindable[models.DeviceContext])play.api.mvc.QueryStringBindable[models.DeviceContext]. [error] Unspecified value parameter e.
Scala版本是2.11.5,play是2.3.9
import util.Binders
是显式导入,因此应包含在隐式搜索中。就好像 implicit def deviceContextBinder
的签名不符合要求,但它 returns 是我的类型的 QueryStringBindable,所以我不明白为什么它不匹配。
感谢任何指点!
(附带说明,文档使用 params: Map[String,Seq[String]]
但如果我使用它,编译器会抱怨它期望 java.util.Map[String,Array[String]]
这看起来很奇怪......请参阅下面的答案。)
编辑 1: 当我使用标准数据类型时,为了不调用我的客户QueryStringBindable,而是将代码留在项目中,编译器随后报告新的错误,第一个错误是:
type arguments [String] do not conform to trait QueryStringBindable's type parameter bounds [T <: play.mvc.QueryStringBindable[T]]
而不是 routesImport += "util.Binders"
尝试 routesImport += "util.Binders._"
从对象中导入所有内容。
好吧,解决方案是我似乎必须将代码放在与案例 class 相同的包中。当我这样做时,上面提到的 java.util.Map "workaround" 解决了,因此,删除 Binders.scala 并将 DeviceContext.Scala 扩展到以下工作:
package models
case class DeviceContext(deviceIdLike: String = "", deviceUseridLike: String = "")
object DeviceContext {
import play.api.mvc.QueryStringBindable
implicit def deviceContextBinder(implicit stringBinder: QueryStringBindable[String]) =
new QueryStringBindable[DeviceContext] {
override def bind(key: String, params: Map[String, Seq[String]]): Option[Either[String, DeviceContext]] = {
Some({
val deviceIdLike = stringBinder.bind(key + ".deviceIdLike", params)
val deviceIUseridLike = stringBinder.bind(key + ".deviceUseridLike", params)
(deviceIdLike, deviceIUseridLike) match {
case (Some(Right(di)), Some(Right(du))) => Right(DeviceContext(di, du))
case _ => Left("Unable to bind DeviceContext")
}
})
}
override def unbind(key: String, deviceContext: DeviceContext): String =
stringBinder.unbind(
key + ".deviceIdLike", deviceContext.deviceIdLike) +
"&" + stringBinder.unbind(key + ".deviceUserIdLike", deviceContext.deviceUseridLike)
}
}
我还发现,如果我想在路由文件中以非限定方式引用我的类型,则 仅 需要 routesImports,即 controllers.Devices.list(dc:DeviceContext)
。如果我愿意把参数写成dc:models.DeviceContext
,那么就不需要routesImports了。
在我的例子中,我在错误的伴随对象中定义了 QueryStringBindable。