I'd like to achieve some type safety in the following situation.
Basically, I have different types of requests that are stored in a database, their type being identified with some string code. For business reasons, this code does not match the class names.
Each type of request include some sort of payload, the type of the payload directly depends on the type of request.
Here is a simplified version of what I have achieved so far:
trait Request[Payload] {
def metadata: String // Not relevant
def payload: Payload
}
case class RequestWithString(override val metadata: String, override val payload: String) extends Request[String]
case class AnotherTypeOfRequestWithString(override val metadata: String, override val payload: String) extends Request[String]
case class RequestWithInt(override val metadata: String, override val payload: Int) extends Request[Int]
object Request {
def apply(code: String)(metadata: String, payload: Any): Request[_] = code match {
case "S" => RequestWithString(metadata, payload.asInstanceOf[String])
case "S2" => AnotherTypeOfRequestWithString(metadata, payload.asInstanceOf[String])
case "I" => RequestWithInt(metadata, payload.asInstanceOf[Int])
}
}
This is not satisfying as I would like Scala to infer the type of the payload to avoid casting, and the (parametered) type of the returned value.
What I am looking for is something like that:
object Request {
def apply[P, R <: Request[P]](code: String)(metadata: String, payload: P): R = code match {
case "S" => RequestWithString(metadata, payload)
case "S2" => AnotherTypeOfRequestWithString(metadata, payload)
case "I" => RequestWithInt(metadata, payload)
}
}
But this does not seem to work, I can't get rid of some type mismatch errors:
found : P
required: String
case "S" => RequestWithString(metadata, payload)
^
Shouldn't Scala infer that P is String in this case? What am I missing?