I am following this. I have defined JsonFormat for my custom case class as:
object RecipeJsonProtocol extends DefaultJsonProtocol {
implicit val recipeFormat = jsonFormat4(Recipe.apply)
}
...and then used it as following in same file:
import RecipeJsonProtocol._
def postRecipe(recipe: Recipe): Callback = {
val json = recipe.toJson.toString()
Ajax.post(url = "....", data = json).onComplete {
case Success(xhr) => println("....")
case Failure(t) => println("An error has occurred: " + t.getMessage)
}
Callback.empty
}
But this is throwing error as:
[error] Referring to non-existent class spray.json.package$
What's wrong here?
Related
I have found that scala compiler report compile error differently depends on whether it is used in compile-time or run-time.
E.g. for a simple implicit not found case, in compile time the report is:
newSource1.scala:6: error: type mismatch;
L|R
f(new L)
^
In runtime, when the same code was evaluated and the error message was captured directly:
class TestCase(code: String, extra: String) {
def toolbox(extra: String): ToolBox[universe.type] = {
ToolBox(cm).mkToolBox(options = s"$opts $extra")
}
def compile(): Any = {
import SpecHelpers._
val tb = toolbox(extra)
tb.eval(tb.parse(code))
}
def compileError(): String =
Try(compile()) match {
case Failure(ee) =>
ee match {
case te: ToolBoxError =>
te.message.linesIterator.toList.drop(2).mkString("\n")
case t =>
throw t
}
case Success(_) =>
sys.error("compiling succeeded")
}
}
the line number and location cursor is omitted:;
implicit error;
!I e: F[Arg]
Is there a way to add the missing part back?
You can specify frontEnd for ToolBox (default frontEnd is mkSilentFrontEnd())
val tb = cm.mkToolBox(
frontEnd = new FrontEnd {
override def display(info: Info): Unit = println(info)
},
options = "-Xlog-implicits -Vimplicits -Vimplicits-verbose-tree -d out"
// with `-d out` toolbox keeps `.class` files in directory `out`
// rather than in memory, so you can decompile `.class` files
// if you want to investigate auto-generated code
)
tb.compile(tb.parse(
"""implicit val i: Int = 1
|implicitly[String]""".stripMargin))
//Info(source-<toolbox>,line-2,offset=34,implicit error;
//!I e: String,ERROR)
//Exception in thread "main" java.lang.ExceptionInInitializerError
// at App.main(App.scala)
//Caused by: scala.tools.reflect.ToolBoxError: reflective compilation has failed:
//
//implicit error;
//!I e: String
// at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.throwIfErrors(ToolBoxFactory.scala:332)
// at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.wrapInPackageAndCompile(ToolBoxFactory.scala:214)
// at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.compile(ToolBoxFactory.scala:268)
// at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.$anonfun$compile$13(ToolBoxFactory.scala:445)
// at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$withCompilerApi$.apply(ToolBoxFactory.scala:371)
// at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.compile(ToolBoxFactory.scala:438)
// at App$.<clinit>(App.scala:20)
// ... 1 more
I'm working through a slight variation of Sangria's Getting Started, using Akka HTTP. I'm attempting to use json4s-jackson as the serializaltion lib, but am running in to some trouble getting the response I want.
Specifically, the serialized response I get is the JSON version of the (StatusCode, Node) tuple:
{
"_1": {
"allowsEntity": true,
"defaultMessage": "OK",
"intValue": 200,
"reason": "OK"
},
"_2": {
"data": {
"foo": {
"id": "1",
"name": "Foo"
}
}
}
}
The data portion is correct, but obviously I just want that and not the first element of the serialized tuple.
I'm using akka-http-json4s, so my trait with route looks like:
case class GraphQlData(query: String, operation: Option[String])
trait FooController {
import de.heikoseeberger.akkahttpjson4s.Json4sSupport._
implicit val serialization = jackson.Serialization
implicit val formats = DefaultFormats
val fooRoutes = post {
entity(as[GraphQlData]) { data =>
QueryParser.parse(data.query) match {
// query parsed successfully, time to execute it!
case Success(queryAst) =>
complete {
Executor
.execute(
SchemaDefinition.FooSchema,
queryAst,
new FooService,
operationName = data.operation
)
.map(OK -> _)
.recover {
case error: QueryAnalysisError => BadRequest -> error.resolveError
case error: ErrorWithResolver => InternalServerError -> error.resolveError
}
}
// can't parse GraphQL query, return error
case Failure(error) =>
complete(BadRequest -> error.getMessage)
}
}
}
implicit def executionContext: ExecutionContext
}
For the life of me I can't figure out what's wrong. I've been looking at sangria-akka-http-example but it seems to be exactly the same, with the exception of using spray-json instead of json4s.
Ideas? Thanks!
Ah, figured it out. I neglected to add
import sangria.marshalling.json4s.jackson._
to the trait defining the route. Adding it does the trick.
Just wanted to provide a quick update to this answer for the full GraphQLRequest. Now the variables are included in the request.
import de.heikoseeberger.akkahttpjson4s.Json4sSupport
import org.json4s._
import org.json4s.JsonAST.JObject
import sangria.marshalling.json4s.jackson._
case class GQLRequest(query: String, operationName: Option[String], variables: JObject)
trait SomeJsonSupport extends Json4sSupport {
implicit val serialization = jackson.Serialization
implicit val formats = DefaultFormats
}
trait GraphQLResource extends SomeJsonSupport{
implicit val timeout:Timeout
implicit val system:ActorSystem
import system.dispatcher
def graphqlRoute: Route =
(post & path("graphql")) {
entity(as[GQLRequest]) { requestJson =>
println(s"This is the requestJson = $requestJson")
graphQLEndpoint(requestJson)
}
} ~
get {
println(s"This is working")
getFromResource("graphiql.html")
}
def graphQLEndpoint(requestJson: GQLRequest): Route = {
val route = QueryParser.parse(requestJson.query) match {
case Success(query) =>
println(s"This is the query $query")
val vars = requestJson.variables match {
case jObj:JObject => jObj
case _ => JObject(List.empty)
}
val futureJValue = Executor.execute(clientSchema,
query,
NclhGqlRequest(this),
operationName = requestJson.operationName,
variables = vars)
val futureTupleStatusCodeJValue = futureJValue.map(OK -> _).recover {
case error: QueryAnalysisError => BadRequest -> error.resolveError
case error: ErrorWithResolver => InternalServerError -> error.resolveError
}
complete(futureTupleStatusCodeJValue)
case Failure(error) =>
complete(BadRequest, error.getMessage)
}
route
}
I'm using Play Framework 2.5 and trying to test one of my DAO class based on the example here.
But my class under test has dependency injection and I wonder how to mock it.
I tried to do something but it seems a bit clumsy, and I would like help to improve it.
Here is my code :
class MyController #Inject()(val mydao: MyDAOClass) extends Controller {
def getData = Action { request =>
mydao.fetchData
}
}
class MyDAOClass #Inject()(ws: WSClient) {
def urls(): List[String] = { List("url1", "url2") }
// fetch data on different servers and should merge it.
def fetchData(): Future[List[String]] = {
val futures: List[Future[WSResponse]] = urls map { url =>
ws.url(url + "/some/data").withRequestTimeout(10000.millis).get()
}
futures map { future =>
future onComplete {
case Success(resp) => println(resp.json)
case Failure(t) => println("An error has occured: " + t.printStackTrace)
}
}
Future(List())
}
}
Here is my test code :
trait DAOTrait {
def urls: List[String]
}
class MyDAOClass extends PlaySpec with MockitoSugar {
"MyDAOClass" should {
"get a list of data" in {
Server.withRouter() {
case GET(p"/url1/some/data") => Action {
Results.Ok(Json.arr(Json.obj("name" -> "data1")))
}
} { implicit port =>
val mockMyDAOClass = mock[DAOTrait]
when(mockMyDAOClass.urls) thenReturn List("url1")
implicit val materializer = Play.current.materializer
WsTestClient.withClient { client =>
val mydao = new MyDAOClass(client) {
override def urls = mockMyDAOClass.urls
}
val result = Await.result(
mydao.fetchData(), 10.seconds)
result mustEqual List("data1")
}
}
}
}
}
The code is not finished in MyDAOClass, but it is enough to start implementing tests.
1) How to mock class that have dependency injection ?
2) When testing this code I have the following exception in MyDAOClass case Failure(t)
java.net.ConnectException: http://localhost:40183
at org.asynchttpclient.netty.channel.NettyConnectListener.onFailure(NettyConnectListener.java:137)
at org.asynchttpclient.netty.request.NettyChannelConnector$1.onFailure(NettyChannelConnector.java:106)
at org.asynchttpclient.netty.SimpleChannelFutureListener.operationComplete(SimpleChannelFutureListener.java:28)
at org.asynchttpclient.netty.SimpleChannelFutureListener.operationComplete(SimpleChannelFutureListener.java:20)
at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:683)
at io.netty.util.concurrent.DefaultPromise.notifyListeners0(DefaultPromise.java:604)
at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:564)
at io.netty.util.concurrent.DefaultPromise.tryFailure(DefaultPromise.java:425)
at io.netty.channel.nio.AbstractNioChannel.doClose(AbstractNioChannel.java:462)
at io.netty.channel.socket.nio.NioSocketChannel.doClose(NioSocketChannel.java:236)
at io.netty.channel.AbstractChannel$AbstractUnsafe.doClose0(AbstractChannel.java:611)
at io.netty.channel.AbstractChannel$AbstractUnsafe.close(AbstractChannel.java:590)
at io.netty.channel.AbstractChannel$AbstractUnsafe.close(AbstractChannel.java:534)
at io.netty.channel.nio.NioEventLoop.closeAll(NioEventLoop.java:576)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:361)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:112)
at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.nio.channels.ClosedChannelException
but it should return Result.Ok instead.
3) Any advice welcome.
The following piece of code does not work:
FileSystems.getDefault.getPath is from the java.nio package
Update:
Method createCalculation is:
Note: MyLocation is a case class that extends MyMessage
def creatCalculation(myPlace: MyLocation): MyMessage = {
if (some test) {
//--- some code
} else
MyError("My Calculation already done")
MyAck //returning the case object MyAck which is of type MyMessage
}
//Req is the class from: net.liftweb.http.Req
val someVal: PartialFunction[Req, () => Box[LiftResponse]] {
case "create" :: Nil JsonPostAndApproval s =>
postResponse(s, (j: JValue, p: Permissions, r: Req) => {
createCalculation(fromJValue[MyLocation](j) = {
case "MyAck" => {
val myCalculator: Calculator = new Calculator(FileSystems.getDefault.getPath(fromJsonVal[MyLocation](s._1).path))
val resultsMap = myCalculator.foreach( (p) => Map[String, Int])
for( (myKey, myValue) <- resultsMap) {
printf("key: %s, value: %s\n", myKey, myValue)
}
}
})
} ) ("Failed to calculate")
}
The compiler complains like this:
[error] C:\Users\lulu\ExampleHandler.scala:129: missing arguments for
method fromJValue in package json;
[error] follow this method with `_' if you want to treat it as a partially applied function
[error] createCalculation(fromJsonVal[MyLocation](j) = {
[error] ^
This is the method definition for fromJsonVal
/**
* Routine to convert JValue to native type
*
* #param in JValue to convert
* #tparam T native type to extract
* #return extracted native type
*/
def fromJsonVal[T: Manifest](in: JValue): T = in.extract[T]
JValue is from net.liftweb/json and is:
sealed abstract class JValue()extends java.lang.Object with net.liftweb.json.Diff.Diffable {
<>
}
Update: the compiler is reporting an error is in this line of code
How do you think I should correct this compile error?
createCalculation(fromJValue[MyLocation](j) = {
Without the full picture, I think the error is merely from you trying to assign an output to a method AND a missing parens. Without the full picture, my guess would be that you are looking for something more like:
createCalculation(fromJValue[MyLocation](j)) match {
case "MyAck"....
Note the double paren after j
When compiling this specification:
import org.specs.Specification
import org.specs.matcher.extension.ParserMatchers
class ParserSpec extends Specification with ParserMatchers {
type Elem = Char
"Vaadin DSL parser" should {
"parse attributes in parentheses" in {
DslParser.attributes must(
succeedOn(stringReader("""(attr1="val1")""")).
withResult(Map[String, AttrVal]("attr1" -> AttrVal("val1", "String"))))
}
}
}
I get the following error:
ParserSpec.scala:21
error: scala is not an enclosing class
withResult(Map[String, AttrVal]("attr1" -> AttrVal("val1", "String"))))
^
I don't understand the error message here at all. Why could it appear?
Scala version is 2.8.1, specs version is 1.6.7.2.
DslParser.attributes has type Parser[Map[String, AttrVal]] and the combinators succeedOn and withResult are defined as follows:
trait ParserMatchers extends Parsers with Matchers {
case class SucceedOn[T](str: Input,
resultMatcherOpt: Option[Matcher[T]]) extends Matcher[Parser[T]] {
def apply(parserBN: => Parser[T]) = {
val parser = parserBN
val parseResult = parser(str)
parseResult match {
case Success(result, remainingInput) =>
val succParseMsg = "Parser "+parser+" succeeded on input "+str+" with result "+result
val okMsgBuffer = new StringBuilder(succParseMsg)
val koMsgBuffer = new StringBuilder(succParseMsg)
val cond = resultMatcherOpt match {
case None =>
true
case Some(resultMatcher) =>
resultMatcher(result) match {
case (success, okMessage, koMessage) =>
okMsgBuffer.append(" and ").append(okMessage)
koMsgBuffer.append(" but ").append(koMessage)
success
}
}
(cond, okMsgBuffer.toString, koMsgBuffer.toString)
case _ =>
(false, "Parser succeeded", "Parser "+parser+": "+parseResult)
}
}
def resultMust(resultMatcher: Matcher[T]) = this.copy(resultMatcherOpt = Some(resultMatcher))
def withResult(expectedResult: T) = resultMust(beEqualTo(expectedResult))
def ignoringResult = this.copy(resultMatcherOpt = None)
}
def succeedOn[T](str: Input, expectedResultOpt: Option[Matcher[T]] = None) =
SucceedOn(str, expectedResultOpt)
implicit def stringReader(str: String): Reader[Char] = new CharSequenceReader(str)
}
This message can occur while the compiler is really trying to signal a type error or a type inference failure. It's a bug (or family of bugs) in scalac.
To locate the problem, progressively add in explicit types and type arguments; break complex expressions into smaller subexpressions.
For bonus points, produce a standalone example and file a bug.