Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to reflect case class fields in scala 2.11?

I want to (static) reflect a sample class like this:

case class Foo[T,U](stuff:T, more:U, age:Int) {
  val ignore:Boolean = false
}

I started like this:

val symbol = currentMirror.classSymbol(clazz)   // symbol is universe.ClassSymbol
// I want to know about type placeholders T and U
val typeParamArgs = symbol.typeParams.map( tp => tp.name.toString)
if( symbol.isCaseClass ) {
  val tsig = symbol.typeSignature
  println(tsig)
}

Ok, at this point if I print tsig I see:

[T, U]scala.AnyRef
        with scala.Product
        with scala.Serializable {
  val stuff: T
  private[this] val stuff: T
  val more: U
  private[this] val more: U
  val age: scala.Int
  private[this] val age: scala.Int
  def <init>(stuff: T,more: U,age: scala.Int): co.blocke.Foo[T,U]
  val ignore: scala.Boolean
  private[this] val ignore: scala.Boolean
  def copy[T, U](stuff: T,more: U,age: scala.Int): co.blocke.Foo[T,U]
  def copy$default$1[T, U]: T @scala.annotation.unchecked.uncheckedVariance
  def copy$default$2[T, U]: U @scala.annotation.unchecked.uncheckedVariance
  def copy$default$3[T, U]: scala.Int @scala.annotation.unchecked.uncheckedVariance
  override def productPrefix: java.lang.String
  def productArity: scala.Int
  def productElement(x$1: scala.Int): scala.Any
  override def productIterator: Iterator[scala.Any]
  def canEqual(x$1: scala.Any): scala.Boolean
  override def hashCode(): scala.Int
  override def toString(): java.lang.String
  override def equals(x$1: scala.Any): scala.Boolean
}

See that line in the middle with <init>? That's the declaration I want to introspect. It's got what I need.

How can I pick apart tsig (universe.Type) to get info about <init>? (I don't want info about 'ignore'.)

like image 925
Greg Avatar asked Feb 10 '15 21:02

Greg


People also ask

For which kind of data should you use a case class in Scala?

A Scala Case Class is like a regular class, except it is good for modeling immutable data. It also serves useful in pattern matching, such a class has a default apply() method which handles object construction. A scala case class also has all vals, which means they are immutable.

What methods get generated when we declare a case class in Scala?

As javap shows, Scala generates a lot of source code when you declare a class as a case class, including getter and setter methods, and the methods I mentioned: copy , hashCode , equals , toString , unapply , apply , and many more.

Does Scala have reflection?

Scala reflection enables a form of metaprogramming which makes it possible for programs to modify themselves at compile time. This compile-time reflection is realized in the form of macros, which provide the ability to execute methods that manipulate abstract syntax trees at compile-time.

What is the benefit of case class in Scala?

When we use the case keyword, the Scala compiler adds these methods for free to avoid boilerplate code. A companion object with apply and unapply methods, that's why there is no need to use new keywords to create instances of a Case classes copy method. Easy to use in pattern matching.


1 Answers

Instead of inspecting the class's .typeSignature, inspect the type signature of the constructor with .primaryConstructor.typeSignature:

val csig = symbol.primaryConstructor.typeSignature
val params = csig.paramLists.head  // paramLists returns a List of Lists

This gives you a list of the parameters of the primary constructor, so you can query the names, types, etc.:

scala> params(1).name
res47: reflect.runtime.universe.Symbol#NameType = more

scala> params(2).typeSignature
res48: reflect.runtime.universe.Type = scala.Int
like image 135
Dan Getz Avatar answered Sep 19 '22 15:09

Dan Getz