I think play-iteratees-extras should help you. This library allows you to parse Json using the Enumerator / Iteratee template and, of course, does not wait to receive all the data.
For example, so as not to create an "infinite" byte stream representing a "infinite" Json array.
import play.api.libs.iteratee.{Enumeratee, Enumerator, Iteratee} var i = 0 var isFirstWas = false val max = 10000 val stream = Enumerator("[".getBytes) andThen Enumerator.generateM { Future { i += 1 if (i < max) { val json = Json.stringify(Json.obj( "prop" -> Random.nextBoolean(), "prop2" -> Random.nextBoolean(), "prop3" -> Random.nextInt(), "prop4" -> Random.alphanumeric.take(5).mkString("") )) val string = if (isFirstWas) { "," + json } else { isFirstWas = true json } Some(Codec.utf_8.encode(string)) } else if (i == max) Some("]".getBytes)
Well, this value contains a jsArray of 10,000 (or more) objects. Allows you to define a case class that will contain the data of each object in our array.
case class Props(prop: Boolean, prop2: Boolean, prop3: Int, prop4: String)
Now write a parser that will parse each element
import play.extras.iteratees._ import JsonBodyParser._ import JsonIteratees._ import JsonEnumeratees._ val parser = jsArray(jsValues(jsSimpleObject)) ><> Enumeratee.map { json => for { prop <- json.\("prop").asOpt[Boolean] prop2 <- json.\("prop2").asOpt[Boolean] prop3 <- json.\("prop3").asOpt[Int] prop4 <- json.\("prop4").asOpt[String] } yield Props(prop, prop2, prop3, prop4) }
Please see the doc for jsArray , jsValues and jsSimpleObject . To create a result handler:
val result = stream &> Encoding.decode() ><> parser
Encoding.decode() from the JsonIteratees package will decode the bytes as a CharString . result value is of type Enumerator[Option[Item]] , and you can apply some iteratee to this enumerator to start the parsing process.
In general, I donβt know how you get bytes (the solution depends a lot on this), but I think this is one of the possible solutions to your problem.