2016-06-21 3 views
1

Je travaille sur un serveur principal dans Play Framework dans Scala. Cependant, j'appelle une bibliothèque externe (écrite en java) qui retourne une liste Java (util.List). J'ai créé un écrit pour l'objet qui est contenu dans la liste, mais je ne sais pas comment écrire les écritures pour la liste réelle afin qu'elle puisse être générique (pas besoin d'écrire un "écrit" pour List et List, juste les écritures pour A et B). Je sais que je pourrais utiliser JavaConversions pour convertir la liste Java en Scala Seq (qui a déjà été écrit en écriture), mais comme la vitesse est essentielle, je ne voudrais pas faire de conversion supplémentaire.JSON écrit pour la liste Java

Répondre

2

Voici une implémentation possible

import play.api.libs.json.{JsArray, JsValue, Json, Writes} 
import scala.collection.JavaConverters._ 

implicit def jListWrites[A: Writes] = new Writes[java.util.List[A]] { 
    override def writes(o: util.List[A]): JsValue = { 
    JsArray(o.asScala.map(Json.toJson(_))) 
    } 
} 

Vous ne créez pas un seul Writes mais plutôt une méthode qui peut créez-les pour tout type défini Writes.

Vous dites que vous voulez éviter JavaConversions, mais comme vous pouvez le voir il est difficile que JsArray attend une Seq[JsValue] de toute façon si vous avez besoin de construire un scala Seq d'une façon ou d'une autre.

Ce que je présenté ici est plus ou moins équivalent à la conversion de java List à scala mutable.Buffer en utilisant asScala et en utilisant par défaut Writes pour Traversable.

Notez que les conversions ne sont probablement pas aussi expansives que vous le pensez, elles créent simplement un wrapper, aucune copie n'est nécessaire.

Voici le meilleur ce que je pouvais venir avec en termes de performance

implicit def jListWrites[A: Writes] = new Writes[java.util.List[A]] { 
    override def writes(o: util.List[A]): JsValue = { 
    val buffer = new Array[JsValue](o.size) 
    var i = 0 
    while (i < o.size) { 
     buffer(i) = Json.toJson(o.get(i)) 
     i += 1 
    } 

    JsArray(buffer) 
    } 
} 

Il faut 29 ms pour 1000000 Int s par rapport à 39 ms pour la mise en œuvre simple. Notez que Int est facile à convertir, si vos objets sont plus complexes, l'accélération sera plus petite.

Convertir 20000 de ceux case class C(num: Int, n2: Int, s: String) donne des résultats égaux (simple est encore plus rapide de 0,14 ms).

+0

Merci. Ceci est exactement ce que je cherchais. –

1

Vous pouvez coder un Writes qui réutilise l'existant pour Scala List

import java.util.{ List => JList } 
implicit def JListWrites[T](implicit sw: Writes[List[T]]): Writes[JList[T]]) = Write[JList[T]] { jlist => 
    sw.writes(jlist.asScala) 
}