Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

Let's say a I have a class:

case class Foo(id: Int, name: String, note: Option[String] = None)

Both the constructor and the apply method in the automatically generated companion object take three parameters. When viewed via reflection, the third parameter (note) is flagged:

p.isParamWithDefault = true

Also, by inspection I can find the method that produces the value in the companion object:

method <init>$default$3

and

method apply$default$3

Which both also have:

m.isParamWithDefault = true

However, I can neither find anything on the TermSymbol for the notes parameter that actually points me at the right methods to obtain the default value nor anything on the above MethodSymbols that point back to the TermSymbol for the parameter.

Is there a straight forward way to link TermSymbol for the parameter with the method that generates its default value? Or do I need to do something kludgey like inspect the names of the methods on the companion object?

I'm interested in this both for the case class constructor example I have here and for regular methods.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
99 views
Welcome To Ask or Share your Answers For Others

1 Answer

There are degrees of kludge.

Sample code at this answer, pasted below.

So as I was saying, the form of the name is in the spec at 4.6, 6.6.1. That is not ad-hoc. For every parameter pi , j with a default argument a method named f $default$n is generated which computes the default argument expression.

The lack of structured ability to access and reconstitute these generated names is a known issue (with a current thread on the ML).

import reflect._
import scala.reflect.runtime.{ currentMirror => cm }
import scala.reflect.runtime.universe._

// case class instance with default args

// Persons entering this site must be 18 or older, so assume that
case class Person(name: String, age: Int = 18) {
  require(age >= 18)
}

object Test extends App {

  // Person may have some default args, or not.
  // normally, must Person(name = "Guy")
  // we will Person(null, 18)
  def newCase[A]()(implicit t: ClassTag[A]): A = {
    val claas = cm classSymbol t.runtimeClass
    val modul = claas.companionSymbol.asModule
    val im = cm reflect (cm reflectModule modul).instance
    defaut[A](im, "apply")
  }

  def defaut[A](im: InstanceMirror, name: String): A = {
    val at = newTermName(name)
    val ts = im.symbol.typeSignature
    val method = (ts member at).asMethod

    // either defarg or default val for type of p
    def valueFor(p: Symbol, i: Int): Any = {
      val defarg = ts member newTermName(s"$name$$default$$${i+1}")
      if (defarg != NoSymbol) {
        println(s"default $defarg")
        (im reflectMethod defarg.asMethod)()
      } else {
        println(s"def val for $p")
        p.typeSignature match {
          case t if t =:= typeOf[String] => null
          case t if t =:= typeOf[Int]    => 0
          case x                         => throw new IllegalArgumentException(x.toString)
        }
      }
    }
    val args = (for (ps <- method.paramss; p <- ps) yield p).zipWithIndex map (p => valueFor(p._1,p._2))
    (im reflectMethod method)(args: _*).asInstanceOf[A]
  }

  assert(Person(name = null) == newCase[Person]())
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...