简体   繁体   中英

Scala Type Erasure on case classes how to solve

I have a trait and two case classes that extends it:

trait Authenticatable {
  val email: String
  val pass: String
  val id: Long
  val sessionid: String
}

case class Admin(
  id: Long,
  email: String,
  pass: String,
  sessionid: Option[String] = None) extends Authenticatable

case class Client(
  id: Long,
  email: String,
  pass: String,
  sessionid: Option[String] = None) extends Authenticatable

And I have functions witch should authenticate user, make copy of object with new sessionid and return it.

  def auth(email: String, password: String): Try[Admin] ={
    checkPass(models.Admin.findBy(sqls"email = $email"), password)
  }

  def auth(email: String, password: String, customer: Customer): Try[Customer] ={
    checkPass(models.Customer.findBy(sqls"email = $email"), password)
  }

  private def checkPass (model: Option[Authenticatable], password: String): Try[Authenticatable]={
    model match {
      case Some(m) => check(password, m.pass).map(_ => m)
      case _ => Failure(new Exception("Authentication failure!"))
    }
  }

The problem is: I can't make copy of object in auth function because function checkPass returns Authenticatable and not Client or Admin class and Authenticatable doesn't have copy method of case classes.

What is the right way to solve this problem?

If you use type parameters, you can avoid throwing away the information that checkPass will always return the same type of Authenticable as was given to it:

private def checkPass[A <: Authenticatable](model: Option[A], password: String): Try[A] =
  // exactly the same body here

This means that in auth you can have eg:

def auth(email: String, password: String): Try[Admin] =
  checkPass(models.Admin.findBy(sqls"email = $email"), password)
    .map(_.copy(sessionid = Some("whatever")))

I would propose to add an abstract method to Authenticable which sets session ID and which is implemented by individual case classes by using of the generated copy method.

trait Authenticable {
  def email: String
  def pass: String
  def id: Long
  def sessionid: Option[String]
  def setSessionId(id: String): Authenticable
}

case class Admin(
  id: Long,
  email: String,
  pass: String,
  sessionid: Option[String] = None) extends Authenticable {
  def setSessionId(id: String) = copy(sessionid = Some(id))
}

case class Client(
  id: Long,
  email: String,
  pass: String,
  sessionid: Option[String] = None) extends Authenticable {
  def setSessionId(id: String) = copy(sessionid = Some(id))
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM