0

I have one main class like this:

class Test {
  def exe(first:String, second:String, task:String):String = {
     task match {
       case "A" => {
          val obj = new A(first)
          obj.defineSecond(second)
       }
       case "B" => {
          val obj = new B(first)
          obj.defineSecond(second)
       }
       case "C" => {
          val obj = new C(first)
          obj.defineSecond(second)
       }
       ....so many cases
   }
 }
}

Instead of writing case in my Test class everytime a new class is added, I tried using the concept of reflection in scala. Below is what I trying:

val m = ru.runtimeMirror(getClass.getClassLoader)
val classTest = ru.typeOf[Test].typeSymbol.asClass
val cm = m.reflectClass(classTest)

But getting error as "class Test is inner class, use reflectClass on an InstaneMirror to obtain its classMirror".

Can anyone knows how can I can avoid adding cases to my main class everytime a new class is created, instead I can write my main class in a way it will work for every case.

Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66

1 Answers1

1

I guess you haven't provided all necessary information in your question. It's written that "class Test is inner class" in your error message but Test is not inner in your code snippet. If you want your runtime-reflection code to be fixed please provide code snippet that reflects actual use case.

Meanwhile you can try a macro (working at compile time)

import scala.language.experimental.macros
import scala.reflect.macros.blackbox

class Test {
  def exe(first: String, second: String, task: String): String = macro Test.exeImpl
}

object Test {
  def exeImpl(c: blackbox.Context)(first: c.Tree, second: c.Tree, task: c.Tree): c.Tree = {
    import c.universe._
    val cases = Seq("A", "B", "C").map(name =>
      cq"""${Literal(Constant(name))} => {
        val obj = new ${TypeName(name)}($first)
        obj.defineSecond($second)
      }"""
    )
    q"$task match { case ..$cases }"
  }
}

Usage:

class A(s: String) {
  def defineSecond(s1: String): String = ""
}
class B(s: String) {
  def defineSecond(s1: String): String = ""
}
class C(s: String) {
  def defineSecond(s1: String): String = ""
}

new Test().exe("first", "second", "task")

//scalac: "task" match {
//  case "A" => {
//    val obj = new A("first");
//    obj.defineSecond("second")
//  }
//  case "B" => {
//    val obj = new B("first");
//    obj.defineSecond("second")
//  }
//  case "C" => {
//    val obj = new C("first");
//    obj.defineSecond("second")
//  }
//}
Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
  • Thanks!! My actual class definition is the same as Test only. And case 'A','B' is nothing but the rule class. And the name of the rule class to call is there in 'Task: String', and first contains the actual data on which I have to apply the rule. **Everytime I implement new class I have to add that too the Test class, so need this thing to be dynamic so that repetitive code should be removed**, because all the cases are almost same except for the class name. – Sunny Arora Aug 31 '20 at 13:17
  • 1
    @SunnyArora Once again, in your code snippet `Test` is not inner. Is it actually inner? Then please provide code snippet where it's inner. – Dmytro Mitin Aug 31 '20 at 13:27