in scala, i have a situation where a base class/trait is extended by very many child classes. i'm going to be serializing an instance of a child class (for the purpose of reconstructing it later) by getting the name of the class and the arguments used to instantiate the class. it's easy to get the name of the class instance using reflection but i'm not sure how to get the arguments of the instance in a way that doesn't require me to write code in every child class. this needs to also work for arguments called by name. it seems tricky because every child class might have a completely different number and type of constructor arguments:
abstract class Base {
// ideally implements some way of finding out the arguments used to construct this object
def getArgs = {...}
}
class ChildA() // args would be a 0-tuple
class ChildB(arg1: Int) // getArgs would be a 1-tuple of arg1
class ChildC(arg1: Double, arg2: Boolean) // args would be a 2-tuple of (arg1, arg2)
// etc...
what i want to avoid is having each class implementing a method like "getArgs" and just returning a tuple duplicating the arguments from the constructor. any way to do this?
i realize an alternative approach is to have some sort of interceptor for object creation, but i couldn't figure out how to do that without having to write boilerplate code for every child class as well.
edit: the case class approach is elegant but in my situation is not suitable because we must be able to allow concrete child classes to extend other concrete child classes.
If your goal is to avoid writing code in each child class to capture the arguments and all child classes are in a flat hierarchy, directly inheriting from Base
and not from each other, you should consider declaring them as case class
es instead. They would then automatically extend Product
and you could use and productIterator
to e.g. save all args to an Array[Any]
(I'm using Array
because that's what's needed when you reflectively call the constructor of these classes later):
scala> def toArray(p: Product) = p.productIterator.toArray
toArray: (p: Product)Array[Any]
scala> case class ChildA()
defined class ChildA
scala> toArray(ChildA())
res0: Array[Any] = Array()
scala> case class ChildB(arg1: Int)
defined class ChildB
scala> toArray(ChildB(42))
res1: Array[Any] = Array(42)
If you want toArray
to only accept subclasses of Base
, then declare its parameter as Product with Base
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With