2010-12-01 46 views
2

J'ai une instance d'une collection que je veux stocker en externe, puis restaurer dans le type de collection d'origine. Par exempleComment créer une nouvelle collection de façon réfléchie?

class Foo { 
    var x : List[Int] 
} 

val f = new Foo 
f.x = List(1, 2, 3) 

I "serialize" sur f, je veux créer une nouvelle pensivement Foo, f2 et remplir f2.x avec les résultats corrects.

Je peux créer le nouveau Foo en faisant classOf[Foo].newInstance, mais comment puis-je créer le type de collection correct et le remplir?

Remarque, je fais beaucoup d'hypothèses ici, remarquable: 1) Je sais que le type de fx, et je peux même sérialiser le type de ce 2) Je sérialisation le contenu de x dans quelque chose qui préserve les valeurs 3) Je ne veux utiliser aucune sérialisation "standard"

J'ai essayé d'utiliser les constructeurs disponibles sur la collection originale, mais je ne comprends pas assez comment cela fonctionne assez pour le retirer.

Merci,

Dave

+0

Le code pour la classe 'foo' ne compile pas ... vous ne devriez pas laisser de côté les membres abstraits si vous voulez une classe concrète. – axel22

+0

Ok, ce n'est pas le point cependant. dit la ligne ci-dessus lit: var x: List [Int] = null –

Répondre

1

Il serait plus facile d'aider ici si nous avions une meilleure idée du problème que vous essayez de résoudre, par exemple pourquoi vous ne voulez pas utiliser la sérialisation d'objet standard.

Cela dit, si vous voulez vraiment faire une réflexion sur les classes de collection Scala, vous aurez probablement besoin de connaître quelques petites choses sur la façon dont Scala compile actuellement ses classes et objets:

  • Si vous voulez la classe pour l'objet List (pas pour la classe List), le nom est scala.collection.immutable.List$ - notez le dernier signe du dollar.

  • Si vous voulez l'instance de l'objet Liste singleton, elle est stockée sous le champ MODULE$.

  • La plupart des objets de compagnie de collecte de scala fournissent une méthode newBuilder qui crée un objet qui a une méthode += ($plus$eq) et une méthode result qui vous permettent de créer une nouvelle collection.

Ainsi, vous pouvez faire quelque chose comme:

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)