Marco
Marco

Reputation: 1652

Playframework plugins and generics

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

Answers (1)

johanandren
johanandren

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

Related Questions