Scala case class 動態copy

在scala中、case class 確實好用、但是隻支持指定字段名稱使用copy複製、在動態情場中、一個類的字段可是非常多的、如何處理這樣的問題?這就得使用到反射功能了、下面已經給大家寫好了。

CopyUtil.scala

import java.lang.reflect.Modifier

object CopyUtil {

  def copy[T](o: T, vals: (String, Any)*): T = {
    if(vals.isEmpty) return o
    val copier = new Copier(o.getClass)
    val maps = vals.map(kv => {
      kv._1 -> kv._2
    }).toMap
    copier(o, maps)
  }

  def copy[T](o: T, vals: Map[String, Any]): T = {
    if(vals.isEmpty) return o
    val copier = new Copier(o.getClass)
    copier(o, vals)
  }

  private class Copier(cls: Class[_]) {
    private val ctor = cls.getConstructors.apply(0)
    private val getters = cls.getDeclaredFields
      .filter {
        f =>
          val m = f.getModifiers
          Modifier.isPrivate(m) && Modifier.isFinal(m) && !Modifier.isStatic(m)
      }
      .take(ctor.getParameterTypes.length)
      .map(f => cls.getMethod(f.getName))

    def apply[T](o: T, vals: Map[String, Any]): T = {
      val byIx = vals.map {
        case (name, value) =>
          val ix = getters.indexWhere(_.getName == name)
          if (ix < 0) throw new IllegalArgumentException("Unknown field: " + name)
          (ix, value.asInstanceOf[Object])
      }.toMap

      val args = getters.indices.map {
        i =>
          byIx.getOrElse(i, getters(i).invoke(o))
      }
      ctor.newInstance(args: _*).asInstanceOf[T]
    }

  }

}

使用

case class User(username:String,password:String)
val user = User("lake","admin")
CopyUtil.copy(user,Map("username"->"admin"))
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章