3

If I have a class like this:

case class Key(
  id: Long,
  var text: String,
  var `type`: String
)

Is there any way to get from that class the list of arguments like this:

['id', 'text', 'type']

If so, how would I do that? Thanks!

om-nom-nom
  • 62,329
  • 13
  • 183
  • 228
Di Zou
  • 4,469
  • 13
  • 59
  • 88
  • 3
    Your question is answered [here](https://stackoverflow.com/questions/16079113/scala-2-10-reflection-how-do-i-extract-the-field-values-from-a-case-class#16079804). If you are on scala 2.10+, I'm going to close this as duplicate. – om-nom-nom Aug 26 '14 at 19:20
  • @om-nom-nom Yup, I'm on Scala 2.10+. I didn't know this was called reflection, so go ahead and close it. Thanks! – Di Zou Aug 26 '14 at 19:25
  • Actually this is not a duplicate because `case class K(i: Int)(j: Int)`, j is a param only. The answer on the other question that was not accepted might cover this. – som-snytt Aug 26 '14 at 19:48
  • @som-snytt isn't it kinda corner case? I agree this should be covered too, but it's very uncommon to see case classes defined as such. – om-nom-nom Aug 26 '14 at 20:32
  • I don't know if it's a use case: http://stackoverflow.com/a/14293872/1296806 and actually the other answer fails on this case, so it's not hard, but hard to get right. Anyway, maybe dupes http://stackoverflow.com/q/17177427/1296806 – som-snytt Aug 26 '14 at 20:46
  • @om-nom-nom I followed your [link](https://stackoverflow.com/questions/16079113/scala-2-10-reflection-how-do-i-extract-the-field-values-from-a-case-class#16079804) and implemented the `getMethods` function in the solution. Is there a way to tell if the constructor argument is optional or not? I've been looking at the `MethodSymbol` documentation, but I can't find anything. – Di Zou Aug 28 '14 at 15:26
  • @om-nom-nom Oh, I think I can use `returnType` to figure out if it's optional or not. – Di Zou Aug 28 '14 at 15:29

1 Answers1

0

I don't know the solution for myself, but I found this on github:

https://gist.github.com/heathermiller/354befb88b097330d42d

import scala.reflect.runtime.universe._

class AbstractParams[T: TypeTag] {
  def tag: TypeTag[T]  = typeTag[T]
  override def toString: String = {
    // Find all case class fields in concrete class instance and print them as "[field name] [field value]"
    val tag = this.tag
    val tpe = tag.tpe
    val allAccessors = tpe.declarations.collect { case meth: MethodSymbol if meth.isCaseAccessor => meth }
    
    val m = runtimeMirror(getClass.getClassLoader)
    val im = m.reflect(this)
    val ctorArg2Strings = allAccessors map { sym =>
      val fldMirror = im.reflectField(sym)
      val value = fldMirror.get
      "[" + sym.name + ": " + value + "]"
    }
    ctorArg2Strings.mkString(" ")
  }
}

case class MyParams(id: String, stuff: Int) extends AbstractParams[MyParams]

object Ex extends App {
  val p = new MyParams("joe", 2)
  println(s"$p")
  // prints:
  // [id: joe] [stuff: 2]
}

I hope this might help. I know that it's not exactly what you was looking for, but you can adjust this solution for yourself.

Sergei Tishkov
  • 551
  • 5
  • 6