Reputation: 66
I have an instance of a collection that I want to store externally and then restore back into the original collection type. For example
class Foo {
var x : List[Int]
}
val f = new Foo
f.x = List(1, 2, 3)
I "serialize" out f, I want to reflectively create a new Foo, f2, and populate f2.x with the correct results.
I can create the new Foo by doing classOf[Foo].newInstance
, but how do I then create the correct collection type and populate it?
Note, I'm making lots of assumptions here, notable: 1) I know the type of f.x, and I can even serialize out the type of that 2) I'm serializing out the contents of x into something that preserves the values 3) I don't want to use any "standard" serialization
I've tried to use the builders available on the original collection, but I don't quite understand how that works enough to pull it off.
Thanks,
Dave
Upvotes: 2
Views: 160
Reputation: 3068
It would be easier to help here if we had a better idea of the problem you're trying to solve, e.g. why you don't want to use the standard object serialization.
That said, if you really do want to do reflection over Scala collection classes, you'll probably need to know a few things about how Scala currently compiles its classes and objects:
If you want the class for the List object (not for the List class), the name is scala.collection.immutable.List$
- note the final dollar sign.
If you want the singleton List object instance, that's stored as the field MODULE$
.
Most scala collection companion objects provide a newBuilder
method which creates an object that has a +=
($plus$eq
) method and a result
method that allow you to create a new collection.
So you could do something like:
scala> def buildByReflection[T](collectionClassName: String, items: Array[T]) = {
| val companionClass = Class.forName(collectionClassName + "$")
| val companion = companionClass.getField("MODULE$").get(null)
| val newBuilder = companionClass.getMethod("newBuilder")
| val builder = newBuilder.invoke(companion)
| val plusEq = builder.getClass.getMethod("$plus$eq", classOf[Object])
| for (item <- items) {
| plusEq.invoke(builder, item.asInstanceOf[AnyRef])
| }
| builder.getClass.getMethod("result").invoke(builder)
| }
buildByReflection: [T](collectionClassName: String,items: Array[T])java.lang.Object
scala> buildByReflection("scala.collection.immutable.List", Array(1, 2, 3))
res0: java.lang.Object = List(1, 2, 3)
Upvotes: 1