2016-06-21 2 views
1

Я работаю над бэкэнд-сервером в Play Framework в Scala. Однако я вызываю внешнюю библиотеку (написанную в java), которая возвращает список Java (util.List). Я создал запись для объекта, который содержится в списке, однако я не знаю, как писать записи для фактического списка, чтобы он мог быть общим (нет необходимости писать «записи» для списка и списка, просто записи для A и B).JSON Writes for Java List

Я знаю, что я мог бы использовать JavaConversions для преобразования списка Java в Scala Seq (у которого уже есть Writes), но поскольку скорость важна, я бы не хотел делать лишнее преобразование.

ответ

2

Вот возможная реализация

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(_))) 
    } 
} 

Вы не создать единый Writes, а скорее метод, который может создайте их для любого типа, который имеет Writes.

Вы сказали, что вы хотите избежать JavaConversions, но как вы можете видеть, что это трудно, как JsArray ожидает Seq[JsValue] в любом случае, так что вам нужно построить SCALA Seq один так или иначе.

Что показано здесь более или менее эквивалентно преобразования Java List в Скале mutable.Buffer используя asScala и использование по умолчанию Writes для Traversable.

Обратите внимание, что конверсии, вероятно, не столь экспансивны, как вы думаете, они просто создают оболочку, а не копирование.

Вот лучшее, что я мог бы прийти с точки зрения производительности

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

Это занимает 29 мс для 1000000 Int с по сравнению с 39 мс для прямой реализации. Обратите внимание, что Int легко конвертировать, если ваши объекты более сложны, ускорение будет меньше.

Преобразование 20000 из этих case class C(num: Int, n2: Int, s: String) дает равные результаты (прямое ускорение на 0,14 мс).

+0

Спасибо. Это именно то, что я искал. –

1

Вы можете закодировать Writes, что повторно использует существующий для 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) 
}