roman-roman
roman-roman

Reputation: 2796

scala class names in configuration map

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

Answers (1)

Sascha Kolberg
Sascha Kolberg

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

Related Questions