2015-12-14 21 views
7

dinamik alan nesneleri Akka HTTP Bilinmeyen, uzunluğu, ByteString akımının bir dış serisini mümkün mi?Akka HTTP Akış JSON Seri kaldırma

[ 
    { "prop": true, "prop2": false, "prop3": 97, "prop4": "sample" }, 
    { "prop": true, "prop2": false, "prop3": 97, "prop4": "sample" }, 
    { "prop": true, "prop2": false, "prop3": 97, "prop4": "sample" }, 
    { "prop": true, "prop2": false, "prop3": 97, "prop4": "sample" }, 
    { "prop": true, "prop2": false, "prop3": 97, "prop4": "sample" }, 
    ... 
] <- Never sees the daylight 
+0

Açıklama için, bu JSON akışını almaya veya bu yayını yayınlamaya mı çalışıyorsunuz? Eğer yayın yapıyorsanız dahili sunumunuz nedir (örn. Iterator, scala Stream, ...)? Ayrıca, iletişimin bir Dizi olması mı yoksa bireysel alan nesnelerinin bir akışı olabilir mi? –

+0

@RamonJRomeroyVigil Bu akış tamamen dış olacaktır. – Martijn

+0

Özel durumunuzda '' 'seçeneğini kapatmak için bekleyebilir ve aradığınız metin için istediğiniz bir desperizer öğesini çağırabilirsiniz. Bu, bazı işlemleri gerektirir ve muhtemelen ByteString'de arabelleğe almayı gerektirir, ancak bunlar oldukça basittir. –

cevap

0

sana yardım gerekir play-iteratees-extras düşünüyorum:


Bağlam ben Büyümeye devam eden JSON Array verir bir sonsuz uzun HTTP son nokta diyoruz. Bu kütüphane, Enumerator/Iteratee modeli ile Json'u ayrıştırmayı ve elbette tüm verileri almayı beklemez. Örneğin, 'sonsuz' Json dizisini temsil eden 'sonsuz' dilde bir bayt akışı inşa etmemiz gerekir.

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) // <------ this is the last jsArray closing tag 
    else None 

    } 
} 

Tamam, bu değer 10000 (veya daha fazla) nesnenin jsArray öğesini içerir. Dizimizdeki her bir nesnenin verilerini içerecek vaka sınıfını tanımlayalım.

case class Props(prop: Boolean, prop2: Boolean, prop3: Int, prop4: String) 

Şimdi ayrıştırıcı yazmak, o jsArray, jsValues ve jsSimpleObject için doc bkz Öğeleri

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

Lütfen ayrıştırmak olacaktır. paket CharString olarak bayt deşifre edecek

val result = stream &> Encoding.decode() ><> parser 

Encoding.decode() JsonIteratees gelen: Sonuç yapımcı oluşturmak. result değeri Enumerator[Option[Item]] tipindedir ve ayrıştırma işlemine başlamak için bu numaralayıcıya bazı yinelemeyi uygulayabilirsiniz.

Toplamda, baytları nasıl aldığınızı bilmiyorum (çözüm büyük ölçüde buna bağlıdır), ancak sorunun olası çözümlerinden birini gösterdiğinizi düşünüyorum.

0

Twitter Akışı'nı (sonsuz bir dizeyi) bir etki alanı nesnesine ayrıştırmaya çalışırken çok benzer bir sorun yaşadım. bunun böyle, Json4s kullanılarak çözülmüştür:

case class Tweet(username: String, geolocation: Option[Geo]) 
case class Geo(latitude: Float, longitude: Float) 
object Tweet{ 
    def apply(s: String): Tweet = { 
     parse(StringInput(s), useBigDecimalForDouble = false, useBigIntForLong = false).extract[Tweet] 
    } 
} 

Sonra ben sadece akışını ara belleğe ve bir Tweetle eşledikten:

val reader = new BufferedReader(new InputStreamReader(new GZIPInputStream(inputStream), "UTF-8")) 
var line = reader.readLine() 
while(line != null){ 
    store(Tweet.apply(line)) 
    line = reader.readLine() 
} 

Json4s içindeki Seçeneği (veya özel nesneler üzerinde tam desteği vardır Nesne, örnekte Geo gibi). Bu nedenle, yaptığım gibi bir Seçeneği koyabilirsiniz ve eğer alan Json'a gelmezse, Yok olarak ayarlanır.

Umut eder!