Specs2 with Futures and Case Classes

670 views Asked by At

I have a lot of problems working with futures as an answer of using Scala Dispatch for asynchronous HTTP calls. I also used Case Class Matchers

lets suppose that I make a call here: http://ip.jsontest.com/ wich returns this json:

{

"ip": "x.xxx.xxx.xxx"

}

so I build my Specification as this

import dispatch._
import Defaults._

import org.json4s._
import org.json4s.jackson.JsonMethods._
import org.specs2.concurrent.ExecutionEnv
import org.specs2.mutable.Specification


import org.specs2.matcher.MatcherMacros
import scala.language.experimental.macros

import scala.concurrent.duration._



class TestDispatchJSON extends Specification  with MatcherMacros{

  implicit val formats = DefaultFormats

  case class Direction(ip: String)

  val translateAPI = url("http://ip.jsontest.com/")

  val response = Http( translateAPI OK as.String)

  val direction = for(json <- response ) yield parse( json ).extract[Direction]




  "The direction" should {

    "direction must be of class Direction" in { implicit ee: ExecutionEnv =>
      direction must matchA[Direction].ip("x.xxx.xxx.xxx").await(retries = 2, timeout = 10.seconds)
    }




  }


}

But it doesnt work, I get this error.

Testing started at 13:44 ...
13:44:41.170 [New I/O worker #1] DEBUG c.n.h.c.p.n.r.NettyConnectListener - Request using non cached Channel '[id: 0x702a0c8a, /172.16.10.142:5548 => ip.jsontest.com/64.233.184.121:80]':
DefaultHttpRequest(chunked: false)
GET / HTTP/1.1
Connection: keep-alive
Host: ip.jsontest.com
Accept: */*
User-Agent: Dispatch/0.11.3

13:44:41.335 [New I/O worker #1] DEBUG c.n.h.c.p.netty.handler.HttpProtocol - 

Request DefaultHttpRequest(chunked: false)
GET / HTTP/1.1
Connection: keep-alive
Host: ip.jsontest.com
Accept: */*
User-Agent: Dispatch/0.11.3

Response DefaultHttpResponse(chunked: true)
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=ISO-8859-1
Vary: Accept-Encoding
Date: Thu, 18 Jun 2015 11:44:41 GMT
Server: Google Frontend
Cache-Control: private
Alternate-Protocol: 80:quic,p=0
Accept-Ranges: none
Transfer-Encoding: chunked

13:44:41.337 [New I/O worker #1] DEBUG c.n.h.c.p.n.channel.ChannelManager - Adding key: http://ip.jsontest.com:80 for channel [id: 0x702a0c8a, /172.16.10.142:5548 => ip.jsontest.com/64.233.184.121:80]

No usable value for $outer
Can't find ScalaSig for class java.lang.Object
org.json4s.package$MappingException: No usable value for $outer
Can't find ScalaSig for class java.lang.Object
    at org.json4s.reflect.package$.fail(package.scala:96)
    at org.json4s.Extraction$ClassInstanceBuilder.org$json4s$Extraction$ClassInstanceBuilder$$buildCtorArg(Extraction.scala:462)
    at org.json4s.Extraction$ClassInstanceBuilder$$anonfun$14.apply(Extraction.scala:482)
    at org.json4s.Extraction$ClassInstanceBuilder$$anonfun$14.apply(Extraction.scala:482)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:245)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:245)
    at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
    at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
    at scala.collection.TraversableLike$class.map(TraversableLike.scala:245)
    at scala.collection.AbstractTraversable.map(Traversable.scala:104)
    at org.json4s.Extraction$ClassInstanceBuilder.org$json4s$Extraction$ClassInstanceBuilder$$instantiate(Extraction.scala:470)
    at org.json4s.Extraction$ClassInstanceBuilder$$anonfun$result$6.apply(Extraction.scala:515)
    at org.json4s.Extraction$ClassInstanceBuilder$$anonfun$result$6.apply(Extraction.scala:512)
    at org.json4s.Extraction$.org$json4s$Extraction$$customOrElse(Extraction.scala:524)
    at org.json4s.Extraction$ClassInstanceBuilder.result(Extraction.scala:512)
    at org.json4s.Extraction$.extract(Extraction.scala:351)
    at org.json4s.Extraction$.extract(Extraction.scala:42)
    at org.json4s.ExtractableJsonAstNode.extract(ExtractableJsonAstNode.scala:21)
    at com.elevenpaths.TestDispatchJSON$$anonfun$1.apply(TestDispatchJSON.scala:35)
    at com.elevenpaths.TestDispatchJSON$$anonfun$1.apply(TestDispatchJSON.scala:35)
    at scala.util.Success$$anonfun$map$1.apply(Try.scala:236)
    at scala.util.Try$.apply(Try.scala:191)
    at scala.util.Success.map(Try.scala:236)
    at scala.concurrent.Future$$anonfun$map$1.apply(Future.scala:235)
    at scala.concurrent.Future$$anonfun$map$1.apply(Future.scala:235)
    at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
    at scala.concurrent.impl.ExecutionContextImpl$AdaptedForkJoinTask.exec(ExecutionContextImpl.scala:121)
    at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
    at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.pollAndExecAll(ForkJoinPool.java:1253)
    at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1346)
    at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
Caused by: org.json4s.package$MappingException: Can't find ScalaSig for class java.lang.Object
    at org.json4s.reflect.ScalaSigReader$.findClass(ScalaSigReader.scala:42)
    at org.json4s.reflect.ScalaSigReader$.org$json4s$reflect$ScalaSigReader$$read$1(ScalaSigReader.scala:36)
    at org.json4s.reflect.ScalaSigReader$.org$json4s$reflect$ScalaSigReader$$read$1(ScalaSigReader.scala:36)
    at org.json4s.reflect.ScalaSigReader$.readField(ScalaSigReader.scala:38)
    at org.json4s.reflect.Reflector$ClassDescriptorBuilder$$anonfun$3.apply(Reflector.scala:66)
    at org.json4s.reflect.Reflector$ClassDescriptorBuilder$$anonfun$3.apply(Reflector.scala:65)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:245)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:245)
    at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
    at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
    at scala.collection.TraversableLike$class.map(TraversableLike.scala:245)
    at scala.collection.AbstractTraversable.map(Traversable.scala:104)
    at org.json4s.reflect.Reflector$ClassDescriptorBuilder.fields(Reflector.scala:65)
    at org.json4s.reflect.Reflector$ClassDescriptorBuilder.fields(Reflector.scala:78)
    at org.json4s.reflect.Reflector$ClassDescriptorBuilder.properties(Reflector.scala:82)
    at org.json4s.reflect.Reflector$ClassDescriptorBuilder.result(Reflector.scala:158)
    at org.json4s.reflect.Reflector$.createDescriptor(Reflector.scala:50)
    at org.json4s.reflect.Reflector$$anonfun$describe$1.apply(Reflector.scala:44)
    at org.json4s.reflect.Reflector$$anonfun$describe$1.apply(Reflector.scala:44)
    at org.json4s.reflect.package$Memo.apply(package.scala:39)
    at org.json4s.reflect.Reflector$.describe(Reflector.scala:44)
    at org.json4s.Extraction$.extract(Extraction.scala:349)
    at org.json4s.Extraction$ClassInstanceBuilder.org$json4s$Extraction$ClassInstanceBuilder$$buildCtorArg(Extraction.scala:450)
    ... 30 more

The direction should

Process finished with exit code 0

I also want a good method to work with futures inside Specs2, beacause I do not like the ExecutionEnvironment, please add imports yo your answers

1

There are 1 answers

0
Eric On BEST ANSWER

It looks like the json parsing itself doesn't work. The No usable value for $outer message indicates that reflection might not work with Direction as an inner class of the Specification. So you should move it outside as a top-level class.