2015-12-14 19 views
7

यह गतिशील डोमेन वस्तुओं में अक्का HTTP से एक बाहरी deserialize, अज्ञात लंबाई की, ByteString धारा करना संभव है?अक्का HTTP स्ट्रीमिंग JSON Deserialization

[ 
    { "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

स्पष्टीकरण के लिए, क्या आप इस JSON स्ट्रीम को प्राप्त करने या इस स्ट्रीम को प्रसारित करने का प्रयास कर रहे हैं? यदि प्रसारण, आपका आंतरिक प्रतिनिधित्व क्या है (उदा। इटरेटर, स्कैला स्ट्रीम, ...)? साथ ही, क्या संचार को एक ऐरे होना चाहिए या क्या यह अलग-अलग डोमेन ऑब्जेक्ट्स की स्ट्रीम हो सकता है? –

+0

@RamonJRomeroyVigil यह स्ट्रीम पूरी तरह से बाहरी होगी। – Martijn

+0

अपने विशेष मामले में आप '} 'बंद करने की प्रतीक्षा कर सकते हैं और टेक्स्ट के लिए अपनी पसंद के एक deserializer को कॉल कर सकते हैं। इसके लिए कुछ ऑपरेशन की आवश्यकता होती है और शायद बाइटस्ट्रिंग पर बफरिंग होती है, लेकिन वे काफी बुनियादी हैं। –

उत्तर

0

मुझे लगता है कि play-iteratees-extras आप मदद करनी चाहिए:


प्रसंग

मैं एक असीम लंबे HTTP endpoint है कि एक 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) // <------ this is the last jsArray closing tag 
    else None 

    } 
} 

ठीक है, इस मान में 10000 (या अधिक) वस्तुओं के जेएसएरे हैं। आइए केस क्लास को परिभाषित करें जिसमें हमारे सरणी में प्रत्येक ऑब्जेक्ट का डेटा होगा।

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

अब पार्सर लिखते हैं, कि प्रत्येक आइटम

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

कृपया पार्स, jsArray, jsValues और jsSimpleObject के लिए doc देखना होगा।

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

Encoding.decode() JsonIteratees से पैकेज CharString के रूप में बाइट्स डिकोड देगा: परिणाम निर्माता निर्माण करने के लिए। result मूल्य में Enumerator[Option[Item]] है और आप पार्सिंग प्रक्रिया शुरू करने के लिए इस गणनाकर्ता को कुछ एमेरेटी लागू कर सकते हैं।

कुल मिलाकर, मुझे नहीं पता कि आप बाइट्स कैसे प्राप्त करते हैं (समाधान इस पर भारी निर्भर करता है), लेकिन मुझे लगता है कि आपकी समस्या के संभावित समाधानों में से एक दिखाएं।

0

मुझे डोमेन ऑब्जेक्ट में ट्विटर स्ट्रीम (एक अनंत स्ट्रिंग) को पार्स करने की कोशिश करने में बहुत ही समान समस्या थी। मैं इसे Json4s उपयोग करते हुए, इस तरह हल:

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

तब मैं सिर्फ धारा बफ़र और एक ट्वीट को यह मैप किया गया:

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 अंदर विकल्प (या कस्टम वस्तुओं पर पूरा समर्थन हासिल है ऑब्जेक्ट, उदाहरण में जियो की तरह)। इसलिए, आप एक विकल्प डाल सकते हैं जैसा मैंने किया था, और यदि फ़ील्ड जेसन में नहीं आती है, तो इसे किसी भी पर सेट नहीं किया जाएगा।

उम्मीद है कि यह मदद करता है!

संबंधित मुद्दे