Reputation: 2796
I have a web application built on play framework.
One of my endpoints provides response composed of output of different classes. The consumer can choose which pieces of output he wants to have in the response:
GET /model/:modelId?fields=length,width,age
.
Accordingly, I have LengthProvider
, WidthProvider
.
Now, I want to have a configuration map in the controller, like
val providers = Map(
"length" -> LengthProvider,
"width" -> WidthProvider
)
to be able to filter consumer's input by this map and apply all the providers, like
fields.collect {
case field if providers.contains(field) => providers(field)(db).get(modelId)
}
The problem arises when I try to build corresponding classes.
I have an abstract FieldProvider
:
abstract class FieldProvider(db: DB) {
def get(modelId: Long): Future[Seq[Writes]]
}
And corresponding implementations (LengthProvider
, WidthProvider
). Now, to make the configuration Map compile, I need to define companion objects for the classes I want to reference (e.g. I need LengthProvider
object). And then, when I use the value of the Map (class name), I cannot initialize the class instance like I do that normally, I only have access to the apply
method defined in companion object. But the problem is that this is not part of the abstract class I define, so the compiler doesn't understand the apply
method signature (as it is only defined in subclasses' companion objects, not in the parent abstract class):
fields.collect {
case field if providers.contains(field) => providers(field)(db).get(modelId)
↑ won't compile
}
Is there a way to make companion object's apply
signature part of the abstract class? Or is there an another, better approach?
Upvotes: 0
Views: 75
Reputation: 7152
As the instances in your map would actually be the companion object, you could let the companion objects inherit from Function1 e.g.:
object LengthProvider extends ((DB) => LengthProvider) {
def apply(v1: DB): LengthProvider = new LengthProvider(v1)
}
object WidthProvider extends ((DB) => WidthProvider) {
def apply(v1: DB): WidthProvider = new WidthProvider(v1)
}
val providers: Map[String, ((DB) => FieldProvider)] = Map(
"length" -> LengthProvider,
"width" -> WidthProvider
)
Upvotes: 1