How do I reflectively create a new collection?
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
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 aresult
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)
精彩评论