Sasgorilla
Sasgorilla

Reputation: 3130

How can I use Scala reflection to get only primary constructor parameters?

I have a case class:

case class Cow(breed: Breed, gender: Gender)(implicit grass: Pasture) {
  val hasSpots: Boolean
}

How can I use reflection at runtime to get back just the list (breed, gender)? Here's what doesn't work:

def getConstructorParams[C](implicit ct: ClassTag[C]) =
  ct.runtimeClass.getDeclaredFields.map(_.getName)
  // returns (breed, gender, grass, hasSpots)

def getConstructorParams[C](implicit ct: ClassTag[C]) =
  ct.runtimeClass.getConstructors.head.getParameters.map(_.getName)
  // returns (arg0, arg1, arg2)

The first solution includes non-constructor fields (hasSpots), which is not what I want. The second solution loses the parameter names. Both methods also include the curried implicit grass/arg2 argument, which I also don't want.

Is there some way to get back just the (breed, gender) fields?

Upvotes: 1

Views: 570

Answers (1)

oowekyala
oowekyala

Reputation: 7768

Assuming you're using the scala-reflect API (I tested it with 2.12 but it may work with other versions), you could do

import scala.reflect.runtime.universe._

def getConstructorParams[T: TypeTag] =
    typeOf[T].decl(termNames.CONSTRUCTOR)
             .alternatives.head.asMethod // this is the primary constructor
             .paramLists.head.map(_.asTerm.name.toString)


getConstructorParams[Cow] == List("breed", "gender")

Upvotes: 3

Related Questions