0

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?

1 Answer 1

1

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
)
Sign up to request clarification or add additional context in comments.

1 Comment

This worked well! Now I have a problem that in fact, LengthProvider requires an implicit argument as well. Can somehow forward it through this apply method in companion objects?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.