0

Code I have:

abstract class Animal {
   def init(animalType: String, jsonBlob: String)
}

class Dog (name: String, colour: String) {
   def init(animalType: String, jsonBlob: String) : Unit = {
        name = jsonBlob.name
        colour = jsonBlob.colour
    }
}

class Cat (address: String) {
   def init(animalType: String, jsonBlob: String) : Unit = {
        address = jsonBlob.address
    }
}

What I want: to instantiate a Cat or Dog dynamically.

I have made an attempt with code that looks like this:

case class AnimalDefinition(animalType: String, jsonBlob: String)
val animalDefinitions : Array[AnimalDefinition] = // 
val animals : Array[Animal] = animalDefinitions.map(new Animal(_.animalType, _.jsonBlob)) 

It should dynamically instantiate the correct class using the animalType parameter. I think traditionally I would do this using a case statement (if animalType == "Cat", return new Cat(..)). But I believe there's an automatic way to do this with reflections.

The code doesn't compile. I've tried reading the Scala reflection docs but they don't have examples that show dynamic instantiation of subclasses with additional parameters

3
  • 2
    Why do you want to include reflection at all? What is wrong with just a simple factory function that instantes the correct type based on input? Commented Oct 23, 2019 at 1:03
  • @LuisMiguelMejíaSuárez so you are talking about something like this: alvinalexander.com/scala/… ? Commented Oct 23, 2019 at 22:29
  • Yeah, basically that. I would make the method return an Option[Animal] or an Either[String, Animal] to handle invalid entries. Commented Oct 23, 2019 at 23:14

1 Answer 1

1

You can replace

if animalType == "Cat", return new Cat("cat name") ...

with

import scala.reflect.runtime.universe._
val mirror = runtimeMirror(getClass.getClassLoader)
val classSymbol = mirror.staticClass(animalType)
val typ = classSymbol.info
val constructorSymbol = typ.decl(termNames.CONSTRUCTOR).asMethod
val classMirror = mirror.reflectClass(classSymbol)
val constructorMirror = classMirror.reflectConstructor(constructorSymbol)
constructorMirror("cat name").asInstanceOf[Animal]
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you. At this point, I'm not sure if my desire to use reflection was appropriate. Why would one choose to use the second code block instead of the first line?
@user Well, if you have let's say 100 cases like if animalType == "Cat", return new Cat("cat name") then reflection can be better than boilerplate code. Surely for 2 cases there's not much sense.
Gotcha. I have about 10 cases at this point, but I might have to come back to this in the future. Thanks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.