代码之家  ›  专栏  ›  技术社区  ›  Chris Stewart

Cryptic Spray Json错误消息

  •  0
  • Chris Stewart  · 技术社区  · 10 年前

    我在尝试解析一些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类:

    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 。错误消息似乎很模糊。看起来spray试图将json字段包装在 Vector 而不是在 UnspentTXO case类。但我不确定为什么会发生这种情况。

    1 回复  |  直到 10 年前
        1
  •  2
  •   sarveshseri    10 年前

    你不能只打电话 convertTo[ Option[ Long ] ] convertTo[ List [ BitcointAddress ] ] .

    这就是为什么 convertTo 被定义,

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

    这意味着。。。仅限类型 T 为此 implicit 证据 typeclass JsonReader[ T ] 可以与一起使用 转换为 .

    除非您提供适当的 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格式。但即使如此,你也必须有一个 含蓄的 证据 typeclass JsonReader[ T ] 在您的范围内。