开发者

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 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)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜