Get companion object of class by given generic type Scala

前端 未结 4 1215
星月不相逢
星月不相逢 2020-12-08 04:35

What I am trying to do is to make a function that would take a generic class and use a static method in it (sorry for Java language, I mean method of its companion object).<

相关标签:
4条回答
  • 2020-12-08 05:13

    You could use reflection to get the companion class and its instance, but that relies on Scala internals that might change in some far(?) future. And there is no type safety as you get an AnyRef. But there is no need to add any implicits to your classes and objects.

    def companionOf[T : Manifest] : Option[AnyRef] = try{
      val classOfT = implicitly[Manifest[T]].erasure
      val companionClassName = classOfT.getName + "$"
      val companionClass = Class.forName(companionClassName)
      val moduleField = companionClass.getField("MODULE$")
      Some(moduleField.get(null))
    } catch {
      case e => None
    }
    
    case class A(i : Int)
    
    companionOf[A].collect{case a : A.type  => a(1)}
    // res1: Option[A] = Some(A(1))
    
    0 讨论(0)
  • 2020-12-08 05:17

    I keep hitting this page when I forget how to do this and the answers are not hundred percent satisfactory for me. Here is how I do with reflection:

    val thisClassCompanion = m.reflect(this).symbol.companion.asModule
    val structural = m.reflectModule(thisClassCompanion)
                      .instance.asInstanceOf[{def doSth: Unit}]
    

    You might need to verify that the class actually has a companion object or companion.asModule will throw a reflection exception is not a module

    Updated: added another example for clarity:

        object CompanionUtil {
    
      import scala.reflect.runtime.{currentMirror => cm}
    
      def companionOf[T, CT](implicit tag: TypeTag[T]): CT = {
        Try[CT] {
          val companionModule = tag.tpe.typeSymbol.companion.asModule
          cm.reflectModule(companionModule).instance.asInstanceOf[CT]
        }
      }.getOrElse(throw new RuntimeException(s"Could not get companion object for type ${tag.tpe}"))
    
    }
    
    0 讨论(0)
  • 2020-12-08 05:26

    Based on the answer by Miquel, here's a method that gets the type reference of the companion object of the specified class object:

      /**
        * Returns the companion object type reference for the specified class
        *
        * @param clazz The class whose companion is required
        * @tparam CT Type of the companion object
        * @return The type of the relevant companion object
        */
      def companionOf[CT](clazz: Class[_]): CT = {
        import scala.reflect.runtime.{currentMirror => cm}
        Try[CT] {
          val companionModule = cm.classSymbol(clazz).companion.asModule
          cm.reflectModule(companionModule).instance.asInstanceOf[CT]
        }.getOrElse(throw new RuntimeException(s"Could not get companion object for $clazz"))
      }
    
    0 讨论(0)
  • 2020-12-08 05:30

    A gist by Miles Sabin may give you a hint:

    trait Companion[T] {
      type C
      def apply() : C
    }
    
    object Companion {
      implicit def companion[T](implicit comp : Companion[T]) = comp()
    }
    
    object TestCompanion {
      trait Foo
    
      object Foo {
        def bar = "wibble"
    
        // Per-companion boilerplate for access via implicit resolution
        implicit def companion = new Companion[Foo] {
          type C = Foo.type
          def apply() = Foo
        }
      }
    
      import Companion._
    
      val fc = companion[Foo]  // Type is Foo.type
      val s = fc.bar           // bar is accessible
    }
    

    This should be compiled with the -Ydependent-method-types flag if using Scala 2.9.x.

    0 讨论(0)
提交回复
热议问题