Home > other >  Is there a way to use .apply/.unapply on Generic objects?
Is there a way to use .apply/.unapply on Generic objects?

Time:09-23

I am using a Generic Mapper to map a Model from a DBModel in scala 2.11

it has a method defined as:

def fromModelToDBModel(m: T) : R

where T is the type of the Model and R is the type of the DBModel.

This method is implemented the same way in almost all inheriting objects, ie:

override def fromModelToDBModel(p: RawModel): RawDBModelV1 = {

  val values = RawModel.unapply(p).get
  val makeDBModel = (RawDBModelV1.apply _).tupled
  makeDBModel(values)
}

Is it possible to somehow define a generic object in the base Trait, so I can call apply/unapply on it?

example of the logic I would like to implement:

def fromModelToDBModel(m: T) : R = {

  val values = Object[T].unapply(p).get
  val makeDBModel = (Object[R].apply _).tupled
  makeDBModel(values)
}

This would eliminate the need for writing every mapper individually, making the code more DRY.

CodePudding user response:

You can look into generic programming with Shapeless. With Shapeless, your function could be written as:

import shapeless._

def fromModelToDBModel[In, Out, Repr <: HList](p: In)(implicit genI: Generic.Aux[In, Repr], genO: Generic.Aux[Out, Repr]): Out = {
  val values = genI.to(p)
  val makeDBModel = genO.from _
  makeDBModel(values)
}
case class RawModel(a: Int, b: String, c: Boolean)
case class RawModelV1(x: Int, y: String, z: Boolean)

val rawModel = RawModel(42, "foo", true)
val rawModelV1 = fromModelToDBModel[RawModel, RawModelV1, Int :: String :: Boolean :: HNil](RawModel(42, "foo", true))

This can be a little unwieldy with the required explicit type params so might want to refer to this SO question for ways to avoid explicit type params. For example, with partial application:

def fromModelToDBModel2[B] = new PartiallyApplied[B]

class PartiallyApplied[B] {
  def apply[A, Repr](a: A)(implicit genA: Generic.Aux[A, Repr], genB: Generic.Aux[B, Repr]) = genB.from(genA.to(a))
}

val rawModelV1_2 = fromModelToDBModel2[RawModelV1](rawModel)
  • Related