75

Given:

case class FirstCC {
  def name: String = ... // something that will give "FirstCC"
}
case class SecondCC extends FirstCC
val one = FirstCC()
val two = SecondCC()

How can I get "FirstCC" from one.name and "SecondCC" from two.name?

Gabe
  • 84,912
  • 12
  • 139
  • 238
pr1001
  • 21,727
  • 17
  • 79
  • 125

6 Answers6

115
def name = this.getClass.getName

Or if you want only the name without the package:

def name = this.getClass.getSimpleName

See the documentation of java.lang.Class for more information.

Esko Luontola
  • 73,184
  • 17
  • 117
  • 128
  • 24
    Note, however, that `getSimpleName` can sometimes throw `java.lang.InternalError: Malformed class name`, for instance when calling it on the class of an object. – pr1001 May 22 '13 at 13:21
  • 1
    Since 1.5 you can also use `getCanonicalName` – Benoit May 22 '14 at 09:40
  • 4
    getSimpleName and getCannonicalName are still buggy, there is an ongoing ticket. https://issues.scala-lang.org/browse/SI-2034 (and it's closed-as-duplicate issue https://issues.scala-lang.org/browse/SI-5425) – Lucas Nov 11 '14 at 15:24
  • also note that for `case class \`First-CC\`` you will get the simple name this: `First$minusCC` which you'll need to normalize to make it match the actual name again – Cpt. Senkfuss Oct 13 '16 at 14:05
26

You can use the property productPrefix of the case class:

case class FirstCC {
  def name = productPrefix
}
case class SecondCC extends FirstCC
val one = FirstCC()
val two = SecondCC()

one.name
two.name

N.B. If you pass to scala 2.8 extending a case class have been deprecated, and you have to not forget the left and right parent ()

Patrick
  • 15,702
  • 1
  • 39
  • 39
16
class Example {
  private def className[A](a: A)(implicit m: Manifest[A]) = m.toString
  override def toString = className(this)
}
Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
  • What is the benefit of this (2.8-only) approach over `this.getClass.getName`? – pr1001 Apr 16 '10 at 22:43
  • 6
    @pr1001 It will preserve type parameters if you have them. – Daniel C. Sobral Apr 16 '10 at 23:40
  • 1
    Is there any way to retrieve class name without package part from that (just as in case of `getSimpleName`)? I find your answer very nice way to overcome `java.lang.InternalError: Malformed class name` exception in case of nested objects – omnomnom Jan 23 '14 at 14:14
  • This also ensures that type ``Foo-Bar-Gong`` (with back-ticks) renders as "Foo-Bar-Gong" (as of 2.11.6) – Coder Guy Aug 18 '15 at 22:11
11
def name = this.getClass.getName
Rex Kerr
  • 166,841
  • 26
  • 322
  • 407
8

Here is a Scala function that generates a human-readable string from any type, recursing on type parameters:

https://gist.github.com/erikerlandson/78d8c33419055b98d701

import scala.reflect.runtime.universe._

object TypeString {

  // return a human-readable type string for type argument 'T'
  // typeString[Int] returns "Int"
  def typeString[T :TypeTag]: String = {
    def work(t: Type): String = {
      t match { case TypeRef(pre, sym, args) =>
        val ss = sym.toString.stripPrefix("trait ").stripPrefix("class ").stripPrefix("type ")
        val as = args.map(work)
        if (ss.startsWith("Function")) {
          val arity = args.length - 1
          "(" + (as.take(arity).mkString(",")) + ")" + "=>" + as.drop(arity).head
        } else {
          if (args.length <= 0) ss else (ss + "[" + as.mkString(",") + "]")
        }
      }
    }
    work(typeOf[T])
  }

  // get the type string of an argument:
  // typeString(2) returns "Int"
  def typeString[T :TypeTag](x: T): String = typeString[T]
}
eje
  • 945
  • 11
  • 22
5
def name = getClass.getSimpleName.split('$').head

This will remove the $1 appearing at the end on some classes.

Javier Montón
  • 4,601
  • 3
  • 21
  • 29
  • 1
    I found a better solution [here](https://stackoverflow.com/a/48204470/378070). Basically using Scala's reflection instead of Java's, will solve the issue. I did like this: `classOf[Int].getSimpleName`. This solves the issue of $ at the end. – Mital Pritmani Nov 09 '20 at 23:29
  • That's a good solution too, but if you are running that on a Trait maybe you don't know which type has `this` so you don't know what to put inside `classOf[]` – Javier Montón Nov 10 '20 at 11:47