Reputation: 1652
I would like to implement a situation like this: abstract class with a generic parameter and a concrete plugin that implements this class.
for example:
abstract class BasePlugin[T] extends Plugin {
def d: T
}
class MyPlugin(app: Application) extends BasePlugin[String] {
val d = "test"
}
My desire is to achieve the following:
val plugin = app.plugin[BasePlugin[String]]
//Ok, plugin = Some(MyPlugin)
val plugin = app.plugin[BasePlugin[Int]]
//KO, plugin = None
Of course this does not happen, because myPlugin is found using any type as a parameter (type erasure?). In any case it would be very effective for me to find a technique to obtain the above. Any idea?
Upvotes: 0
Views: 133
Reputation: 11479
The play plugin api uses Class.isAssignableFrom when it looks for plugins which is part of Java so it will not help that Scala has got ClassTag/TypeTags.
Maybe you could create your own sub-plugin format, something like:
trait SubPlugin[T] {
def doSomething(t: T) {}
}
trait MetaPlugin {
private val subPlugins: Seq[(Class[_], SubPlugin[_])] = ???
def subPlugin[T](implicit classTag: ClassTag[T]): Option[SubPlugin[T]] = {
subPlugins.collectFirst {
case (c, p) if c.isAssignableFrom(classTag.runtimeClass) => p.asInstanceOf[SubPlugin[T]]
}
}
}
object MetaPlugin {
def apply[T](implicit app: play.api.Application, classTag: ClassTag[T]): Option[SubPlugin[T]] =
app.plugin[MetaPlugin].flatMap(_.subPlugin[T])
}
object AndThenSomeWhere {
import play.api.Play.current
MetaPlugin[String].map(_.doSomething("a string"))
}
Upvotes: 1