Get case class field's name and type with shapeless

跟風遠走 提交于 2019-12-11 04:10:00

问题


Is it possible to get scala case class field's names and types with shapeless?

I've tried like this (T is case class):

trait Cpo[T] {

def withPrimaryKey[R <: HList, K, V <: HList](f: Seq[Symbol] => Seq[Symbol])(
    implicit labellGeneric: LabelledGeneric.Aux[T, R], keys: Keys.Aux[R, K],
    ktl: hlist.ToList[K, Symbol]): Cpo[T]
}

but I only can get field's name.

Zlaja


回答1:


Try

object typeablePoly extends Poly1 {
  implicit def default[A](implicit typeable: Typeable[A]): Case.Aux[A, String] = at(_ => typeable.describe)
}

trait Cpo[T] {

  def withPrimaryKey[R <: HList, K <: HList, V <: HList, V1 <: HList](f: Seq[Symbol] => Seq[Symbol])(implicit
    labellGeneric: LabelledGeneric.Aux[T, R],
    keys: Keys.Aux[R, K],
    ktl: hlist.ToList[K, Symbol],
    values: Values.Aux[R, V],
    mapper: hlist.Mapper.Aux[typeablePoly.type, V, V1],
    vtl: hlist.ToList[V1, String]
  ): Cpo[T] 
}

Now ktl gives list of field names (as Symbols) and vtl gives list of field types (as Strings).


Try

  object typeablePoly extends Poly1 {
    implicit def default[A](implicit typeable: Typeable[A]): Case.Aux[A, String] = at(_ => typeable.describe)
  }

  object nullPoly extends Poly0 {
    implicit def default[A]: ProductCase.Aux[HNil, A] = at(null.asInstanceOf[A])
  }

  trait Cpo[T] {

    def withPrimaryKey[R <: HList, K <: HList, V <: HList, V1 <: HList](f: Seq[Symbol] => Seq[Symbol])(implicit
      labellGeneric: LabelledGeneric.Aux[T, R],
      keys: Keys.Aux[R, K],
      ktl: hlist.ToList[K, Symbol],
      values: Values.Aux[R, V],
      mapper: hlist.Mapper.Aux[typeablePoly.type, V, V1],
      fillWith: hlist.FillWith[nullPoly.type, V],
      vtl: hlist.ToList[V1, String]
    ): Cpo[T] = {
      println(ktl(keys())) // List('i, 's)
      println(vtl(mapper(fillWith()))) // List(Int, String)
      ???
    }
  }

  case class MyClass(i: Int, s: String)
  new Cpo[MyClass] {}.withPrimaryKey(identity)



回答2:


You definitely can get field names. For example, here you can find how to write your shapeless-based generic derivation mechanism: Bits of shapeless part 2. More specific, you should look at Deriving case Classes part, there is a function which derives encoder for arbitrary case class, its signature is:

implicit def hconsToJson[Key <: Symbol, Head, Tail <: HList](
    implicit key: Witness.Aux[Key],
    headWrites: JsonWrites[Head],
    tailWrites: JsonWrites[Tail])
    : JsonWrites[FieldType[Key, Head] :: Tail] = ???

Hence, key parameter allows you to acces the field name of the certain field. For the types, the only known way to me is to use reflection. Read this for details Scala manual on type tags.




回答3:


If using shapeless is not necessary, you can get the type as well as value using Product class in scala

case class Test(x:Int,y:String,z:Boolean)
println(getGeyNameValueType(Test(1,"a",true)).foreach(println))

def getGeyNameValueType(inp: Product): Iterator[(Any, Class[_])] = {
    val itr = inp.productIterator
    for {
      item <- itr
    } yield (item, item.getClass)
}

The output is

(1,class java.lang.Integer)
(a,class java.lang.String)
(true,class java.lang.Boolean)
()


来源:https://stackoverflow.com/questions/55504430/get-case-class-fields-name-and-type-with-shapeless

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!