theMadKing theMadKing - 2 months ago 12
Scala Question

Scala calling a Object from a variable name

I have a few objects created with a function called .clean in each one:


These Objects need to be called dynamically based on a record based on an API call being made that will let my Job know what object to call for instance I have it hard coded right now:

def matchSchema(schema:Int): Any = schema match {
case 1 => HiveCleanerTbl.clean(rawRecord)
case 32 => HiveCleanerDb.clean(rawRecord)

Earlier in the code instead of hardcoding the possible Objects is there a way to dynamically have the object populated like:

val systems = List[(String, String, Int)] = List((hiveTbl,HiveTblCleaner,6), (hiveDb,HiveDbCleaner,7))

And I have code that looks like this:

systems.foreach(x => if(x._1 == systemName) {
cleanObject = x._2

How will I make the cleanObject defined as the object I want to use that can call its .clean function?


Yes, you can do that.

val systems = List[(Cleanable, String, Int)] = List((hiveTbl,HiveTblCleaner,6), (hiveDb,HiveDbCleaner,7))

Lets say your hiveTbl and hiveDb are cleanable and lets say clean method is available on them to invoke.

systems.foreach { 
  case (db: Cleanable, "cleanSchemeName", _) => 
  case _ => () //ignore

If db does not have clean method then check the type of db and try pattern matching to resolve the real type of the db object.

Here is a general example how you can achieve this.

Cleanable gives clean method to A and B. List contains all cleanables so I can go ahead calling clean on each object without type casting the object.

Based on certain condition you can ignore clean some objects.

trait Cleanable {
  def clean(): Unit

case class A(a: Int) extends Cleanable {
  override def clean(): Unit = println("cleaned A")

case class B(a: Int) extends Cleanable {
  override def clean(): Unit = println("cleaned B")

val cleanableStuff: List[(String, Cleanable)] = List(("clean", A(10)), ("donot_clean", B(10)))

def cleanAll(list: List[(String, Cleanable)]): Unit = {
  list.foreach {
    case ("donot_clean", v) => //Ignore 1st object
    case (_, v) => v.clean() //clean other objects