2015-02-27 4 views
0

Я получаю следующее сообщение об ошибке при попытке разобрать некоторые JSON:Cryptic Spray сообщение Json ошибка

[info] The future returned an exception of type: spray.httpx.PipelineException, with message: 
Vector("eba760a81b177051b0520418b4e10596955adb98196c15367a2467ab66a19b5c", 600, "AN51SPP6iZBHFJ3aux1jtn6MMMD13Gh3t7", 500, 
["1BXVXP82f7x9YWdWuCaCYwad8ZoYayyRYt"], "76a91473758c13a91699376abb8fe76931bdd9bdc04ee388ac", false) 
(of class scala.collection.immutable.Vector). (AddressUnspentTXORequestTest.scala:14) 

, и я не совсем уверен, что это значит. Вот кусок JSON, что я пытаюсь разобрать:

[ 
    { 
    "transaction_hash": "eba760a81b177051b0520418b4e10596955adb98196c15367a2467ab66a19b5c", 
    "output_index": 1, 
    "value": 600, 
    "asset_id": "AN51SPP6iZBHFJ3aux1jtn6MMMD13Gh3t7", 
    "asset_quantity": 500, 
    "addresses": [ 
     "1BXVXP82f7x9YWdWuCaCYwad8ZoYayyRYt" 
    ], 
    "script_hex": "76a91473758c13a91699376abb8fe76931bdd9bdc04ee388ac", 
    "spent": false, 
    "confirmations": 31674 
    }, 
    { 
    "transaction_hash": "1f9f6224bee8813135aba622693c78a33b3460e4efdb340174f87fdd8c9d4148", 
    "output_index": 1, 
    "value": 600, 
    "asset_id": "AS6tDJJ3oWrcE1Kk3T14mD8q6ycHYVzyYQ", 
    "asset_quantity": 200000, 
    "addresses": [ 
     "1BXVXP82f7x9YWdWuCaCYwad8ZoYayyRYt" 
    ], 
    "script_hex": "76a91473758c13a91699376abb8fe76931bdd9bdc04ee388ac", 
    "spent": false, 
    "confirmations": 35895 
    } 
] 

и здесь дело класс, который я пытаюсь разобрать его в:

case class UnspentTXO(transaction_hash: String, output_index: Int, value: Long, 
    asset_id: Option[String], asset_quantity: Option[Long], addresses: List[BitcoinAddress], 
    script_hex: String, spent: Boolean) 

Способ инициирования запроса здесь:

def getUnspentTXOs(address: Address): Future[List[UnspentTXO]] = { 
    val pipeline: HttpRequest => Future[List[UnspentTXO]] = 
     sendReceive ~> unmarshal[List[UnspentTXO]] 
    pipeline(Get(host + path + address.value + "/unspents")) 
    } 

и, наконец, это как я разборе, что JSon запрос:

override def read(value: JsValue): UnspentTXO = { 

    val Seq(transaction_hash, output_index, locked_satoshies, asset_id, asset_quantity, addresses, script_hex, spent) = 
    value.asJsObject.getFields("transaction_hash", "value", "asset_id", "asset_quantity", "addresses", "script_hex", "spent") 

    val assetId = asset_id match { 
    case JsString(s) => Some(s) 
    case JsNull => None 
    case _ => throw new RuntimeException("Asset id should be of type JsString or JsNull, got something else") 
    } 

    val assetQuantity = asset_quantity match { 
    case JsNumber(n) => Some(n.toLong) 
    case JsNull => None 
    case _ => throw new RuntimeException("Asset quantity should be JsNull or a JsNumber") 
    } 

    // convert JsArray to List[ BitcoinAdress ] 
    val addressList = addresses match { 
    case ja: JsArray => { 
     ja.elements.toList.map(e => BitcoinAddress(e.convertTo[String])) 
    } 
    case _ => throw new RuntimeException("address list should be of type JsArray, got something else") 
    } 

    UnspentTXO(transaction_hash.convertTo[String], output_index.convertTo[Int], locked_satoshies.convertTo[Long], 
    assetId, assetQuantity, addressList, 
    script_hex.convertTo[String], spent.convertTo[Boolean]) 

} 

Я думаю, проблема может заключаться в том, что запрос возвращает json-массив, а не только объект JSON, поэтому я не уверен, правильно ли я обрабатываю его внутри моего getUnspentTXOs. Сообщение об ошибке кажется очень расплывчатым. Кажется, что спрей пытается обернуть json-поля внутри Vector вместо внутреннего класса UnspentTXO. Я не уверен, почему это происходит.

ответ

2

Вы не можете просто позвонить convertTo[ Option[ Long ] ] и convertTo[ List [ BitcointAddress ] ].

Это как convertTo определяется,

def convertTo[T :JsonReader]: T = jsonReader[T].read(this) 

Что означает ... только типы T, для которых implicit свидетельство typeclassJsonReader[ T ] доступно может использоваться с convertTo.

Если вы не предоставите соответствующие доказательства implicit typeclass, вам придется специально обрабатывать несколько случаев.

Кроме этого, spray-json просто слишком минималистично ... так что так JsObject просто обертка на вершине Map[ String, JsValue] и getFields определяется как,

def getFields(fieldNames: String*): immutable.Seq[JsValue] = 
    fieldNames.flatMap(fields.get)(collection.breakOut) 

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

Следовательно, необходимо указать дополнительные значения, которые должны быть указаны на карте. Или нам придется сопоставлять шаблоны для каждого возможного случая (что может привести ко многим случаям).

override def read(value: JsValue): UnspentTXO = { 

    val jsObject = value.asJsObject 

    // get only non-optional values here 
    val Seq(transaction_hash, output_index, locked_satoshies, addresses, 
      script_hex, spent) = 
    jsObject.getFields("transaction_hash", "output_index", "value", "addresses", "script_hex", "spent") 

    // Assuming you have imported spray.json._, simple types will work. 

    // have to handle options differently 
    // or 2 optional values would mean 4 patterns-matchings of sequences like above. 

    // jsObject.fields is just a Map[ String, JsValue ] 

    val assetId = jsObject.fields.get("asset_id") match { 
    case Some(JsString(s)) => Some(s) 
    case None => None 
    } 

    val assetQuantity = jsObject.fields.get("asset_quantity") match { 
    case Some(JsNumber(n)) => Some(n.toLong) 
    case None => None 
    } 

    // convert JsArray to List[ BitcoinAdress ] 
    val addressList = addresses match { 
    case ja : JsArray => { 
     ja.elements.toList.map(BitcoinAddress(_.convertTo[ String ])) 
    } 
    } 

    UnspentTXO(transaction_hash.convertTo[ String ], output_index.convertTo[ Int ], 
    locked_satoshies.convertTo[ Long ], assetId, assetQuantity, 
    addressList, script_hex.convertTo[ String ], spent.convertTo[ Boolean ]) 

} 

Другой способ получить convertTo[ Option[ T ] ] и convertTo[ List[ T ] ] рабочий является импортирование spray.json.DefaultJsonProtocol._ который обеспечивает JSON-формат для наиболее широко используемых типов. Но даже тогда у вас должно быть implicit доказательство typeclass JsonReader[ T ] в вашем объеме.

+0

Это не сработало, я обновил OP до того, что у меня есть в методе 'read'. Я все еще получаю ту же ошибку. –

+0

Исправлено это сейчас ... Я действительно не думал, что 'spray-json' будет такой тонкой оберткой из голых костей. –

+0

Так что это все еще не работает.Несколько вещей, которые следует отметить, это то, что 'JsArray [JsValue]' дает мне ошибку, говоря, что 'JsArray' нельзя параметризовать. Я использую спрей-json versoin '1.3.1', если это помогает. –