Giter VIP home page Giter VIP logo

autowire's People

Contributors

asakaev avatar benhutchison avatar benjaminjackman avatar clhodapp avatar cornerman avatar jhegedus42 avatar lihaoyi avatar lolgab avatar marcgrue avatar mathieuleclaire avatar nafg avatar olivierblanvillain avatar tindzk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

autowire's Issues

Can't Use API Factory Functions for Namespacing Purposes

In a similar vein as #7, I wish to have functions (or values) on my auto-wired API that serve as namespaces for more specific functionality. The following variant on the Minimal Example illustrates the intent:

import autowire._
import upickle._

trait MySpecificApi {
  def doThing(i: Int, s: String): Seq[String]
}

object MySpecificApiImpl extends MySpecificApi {
  def doThing(i: Int, s: String) = Seq.fill(i)(s)
}

trait MyApi {
  def mySpecificApi: MySpecificApi
}

object MyApiImpl extends MyApi {
  override val mySpecificApi: MySpecificApi = MySpecificApiImpl
}

object MyServer extends autowire.Server[String, upickle.Reader, upickle.Writer]{
  def write[Result: Writer](r: Result) = upickle.write(r)
  def read[Result: Reader](p: String) = upickle.read[Result](p)

  val routes = MyServer.route[MyApi](MyApiImpl)
}

object MyClient extends autowire.Client[String, upickle.Reader, upickle.Writer]{
  def write[Result: Writer](r: Result) = upickle.write(r)
  def read[Result: Reader](p: String) = upickle.read[Result](p)

  override def doCall(req: Request) = {
    println(req)
    MyServer.routes.apply(req)
  }
}

MyClient[MyApi].mySpecificApi.doThing(3, "lol").call().foreach(println)

This fails to compile with an error similar to:

Error:(27, 38) A$A36.this.MySpecificApi does not take parameters
  val routes = MyServer.route[MyApi](MyApiImpl)
                                    ^

Is this supported, and—in any case—is there any other preferred approach?

Bugs with Upickle 0.3.8

Hi,
I tested it with upickle 0.3.8 but it seems that it does not work yet, doesn'it ?
I have strange errors for one call in particular (but it works with a lot of others calls) :

/home/mathieu/work/cogit/openmole/openmole/gui/client/org.openmole.gui.client.core/src/main/scala/org/openmole/gui/client/core/ExecutionPanel.scala:70: type mismatch;
[error]  found   : upickle.default.Reader[(org.openmole.gui.ext.data.RunningData, org.openmole.gui.ext.data.RunningData)]
[error]  required: upickle.default.Aliases.R[(Seq[org.openmole.gui.ext.data.RunningEnvironmentData], Seq[org.openmole.gui.ext.data.RunningOutputData])]
[error]     (which expands to)  upickle.default.Reader[(Seq[org.openmole.gui.ext.data.RunningEnvironmentData], Seq[org.openmole.gui.ext.data.RunningOutputData])]
[error]             errorLevelSelector.content().map{_.level}.getOrElse(ErrorLevel())).call().andThen {
[error]

where RunningData is defined as:

case class RunningData(environmentsData: Seq[RunningEnvironmentData], outputsData: Seq[RunningOutputData])```

Support type parameters in autowire.Server

Goal would be to having something like this work:

object Router {
 def route[T](apiImpl: T, path: String, data: Array[Byte]): Future[_] = {
   AutowireRouter.route[T](apiImpl)(
    autowire.Core.Request(path.split("/"),
    Unpickle[Map[String, ByteBuffer]].fromBytes(ByteBuffer.wrap(data)))
  )
 }
}

According to @lihaoyi this will take a major refactoring of the macros

diverging implicit expansion errors with Spray, Autowire and uPickle

Hi there, I'm facing compile errors on the server-side while trying to integrate Autowire within my existing Spray code that uses uPickle for serialization.
Here's my UPickleJsonSupport trait mixed into my Spray HttpService:

trait UPickleJsonSupport {
    implicit def genericMarshaller[T: Writer]: Marshaller[T] =
        Marshaller.delegate(ContentTypes.`application/json`)(writeJs(_))

    implicit def jsValueMarshaller: Marshaller[Js.Value] =
        Marshaller.of[Js.Value](ContentTypes.`application/json`) {
            (value, contentType, context) => {
                val entity = HttpEntity(contentType, json.write(value))

                context.marshalTo(entity)
            }
        }

    implicit def entityUnmarshaller[T: Reader]: Unmarshaller[T] =
        Unmarshaller[T](ContentTypeRange(MediaTypes.`application/json`)) {
            case entity => read[T](entity.asString(HttpCharsets.`UTF-8`))
        }
}

Ok, this is for the integration with Spray marshalling and this works fine until I throw Autowire into the mix:
Here's my AutowireServer:

object AutowireServer extends autowire.Server[Js.Value, Reader, Writer] {
    def read[Result: Reader](p: Js.Value) = upickle.default.readJs[Result](p)
    def write[Result: Writer](r: Result) = upickle.default.writeJs(r)
}

And my Spray route definition (rest of the code omitted for brevity):

    def apiRoute = post {
        path("api" / Segments) { s =>
            extract(_.request.entity.asString) { e =>
                complete {
                    AutowireServer.route[Api](ApiImpl)(
                        autowire.Core.Request(
                            s,
                            upickle.json.read(e).asInstanceOf[Js.Obj].value.toMap
                        )
                    )
                }
            }
        }
    }

With this code, I've got a sh*tload of compile errors (all related to this problem), ending with these:

...
[error]  both value derive$macro$173 of type => upickle.default.Writer[upickle.Js.Value]
[error]  and value derive$macro$175 of type => upickle.default.Writer[upickle.Js.Value]
[error]  match expected type upickle.default.Writer[upickle.Js.Value]
[error] /Users/toto/someproject/jvm/src/main/scala/some/pkg/RouteProvider.scala:38: diverging implicit expansion for type upickle.default.Writer[T1]
[error] starting with macro method macroW in trait LowPriX
[error]           AutowireServer.route[Api](ApiImpl)(
[error]                                             ^
[error] 13 errors found

My current knowledge of scala (which is rather poor) does not allow me to find the root cause of the problem. Looks like a clash between implicits generated by the macros ???
Now, the problem may come from uPickle rather than Autowire but since uPickle was working before I added Autowire, I create the ticket here ;)

In the meantime, I will simply generate Spray's HttpEntity myself (thus skipping the Marshaller) by adding this transformation on the router result .map(v => HttpEntity(jsonContentType, upickle.json.write(v))) but I guess (and hope) it should be possible to combine both libs.

Thanks for your help.

Traits and inheritance

Not being a prononent of 'monolithic' APIs, I'd like to split my API up into several traits. As a consequence I can easily implement the logic in separate classes as well. On the server-side everything works out fine, but when compiling my Scala.JS client, I'm getting the following exception:

[error] scala.ScalaReflectionException: <none> is not a method
[error]         at scala.reflect.api.Symbols$SymbolApi$class.asMethod(Symbols.scala:228)
[error]         at scala.reflect.internal.Symbols$SymbolContextApiImpl.asMethod(Symbols.scala:82)
[error]         at autowire.Macros$$anonfun$8$$anonfun$apply$2.apply(Macros.scala:84)
[error]         at autowire.Macros$$anonfun$8$$anonfun$apply$2.apply(Macros.scala:73)
[error]         at autowire.Macros$Win.map(Macros.scala:26)
[error]         at autowire.Macros$Win.map(Macros.scala:25)
[error]         at autowire.Macros$$anonfun$8.apply(Macros.scala:73)
[error]         at autowire.Macros$$anonfun$8.apply(Macros.scala:49)
[error]         at autowire.Macros$Win.flatMap(Macros.scala:27)
[error]         at autowire.Macros$.clientMacro(Macros.scala:49)

If it wasn't clear what I'm trying to achieve, here is an example:

trait BookProtocol {
  def bookList(): Seq[BookListItem]
  ...
}

trait ArticleProtocol {
  ...
}

trait Protocol extends BookProtocol with ArticleProtocol

How to use it with unfiltered?

In the example, it's using spray on the server side.

I tried to use unfiltered, but not sure how to do it. Could you give some ideas?

Not sure how to write similar code with unfiltered for following code:

 post {
        path("api" / Segments){ s =>
          extract(_.request.entity.asString) { e =>
            complete {
              AutowireServer.route[Api](Server)(
                autowire.Core.Request(s, upickle.read[Map[String, String]](e))
              )
            }
          }
        }
      }

Hello Autowire

Hi,
very impressive work (again !) ! Do you have a simple example of autowire (meaning simpler than js-fiddle) to understand well all the concepts ?

Thanks
Mathieu

Default parameters not supported?

When I try interfaces like this:

trait Protocol {
val dictionary: protocol.Dictionary
val userRegistry: protocol.UserRegistry
}

trait UserRegistry {
def createUser(newUser: User): User
def lookupFirstNamePart(firstname: String, exact: Boolean = false): Seq[User]
}

and an implementation like this:

override def lookupFirstNamePart(firstnamePart: String, exact: Boolean = false)

the compile fails at line:

val router = AutowireServer.routeProtocol

with error: "value lookupFirstNamePart$default$2 is not a member of io.widok.server.Controllers"

Am I doing something wrong, or is the macro magic missing support for default values?

Can not assign server.route to a val and use that

Type parameters for client here worked

  case class objParam(url:String)
  def getAtw[t](): ClientProxy[t, ByteBuffer, Default.Pickler, Default.Pickler] ={ // ok
    val a=autowireJs
    a.atwParams=objParam(sharedOlogx.rpcAuthed_ologx_path)
    a[t]
  }
  object autowireJs2 extends autowire.Client[ByteBuffer, Pickler, Pickler]   {
    override def doCall(req: Request): Future[ByteBuffer] = {
      dom.ext.Ajax
        .post(
          url = sharedOlogx.rpcAuthed_ologx_path + "/" + req.path.mkString("/"),
          data = Pickle.intoBytes(req.args),
          responseType = "arraybuffer",
          headers = Map(("Content-Type", "application/octet-stream"))
        )
        .map(r => TypedArrayBuffer.wrap(r.response.asInstanceOf[ArrayBuffer]))
    }

but the server side do not work(it compiles,but get runtime error when client tries to do rpc call)

      object autowireServer extends autowire.Server[ByteBuffer, Pickler, Pickler]{
        override def read[R: Pickler](p: ByteBuffer) = Unpickle[R].fromBytes(p)

        override def write[R: Pickler](r: R) = Pickle.intoBytes(r)

        @inline
        final def run[t](apiImpl: t,  // damn! this can not be made generic
                   reqPathList: List[String],
                   reqBodyBytes: ByteString): Future[ByteBuffer] = {
          lg("atw reqPathList:"+reqPathList)
          this.route[t](apiImpl)( // the problem is route[t] 
            autowire.Core.Request(
              reqPathList,
              read[Map[String, ByteBuffer]](reqBodyBytes.asByteBuffer))
          )
        }

      }

even if i inline it

the error is

scala.MatchError: Request(List(rpcAuthedOlogx, tst),Map()) (of class autowire.Core$Request)
at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:254)
at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:252)
at jvmUtils$akkaHttpUtil$rpc_server$autowireServerCls$$anonfun$run$1.applyOrElse(jvmUtils.scala:246)

compiler issue with autowire macro

Hi,

I've been trying to adapt the spray-autowire example (https://github.com/lihaoyi/workbench-example-app/tree/autowire) so that we can use a servlet instead of spray for the server. While attempting this I've run into an issue with one of the macros from autowire.

I'm getting a stackoverflowexception when compiling the following code:

package example

import javax.servlet.annotation.WebServlet
import javax.servlet.http.{HttpServlet, HttpServletRequest, HttpServletResponse}
//import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.{ExecutionContext, Await, Future}
import scala.concurrent.duration._

@WebServlet(urlPatterns=Array("/api/*"))
class MyServlet extends HttpServlet {
  implicit val ec: ExecutionContext = ExecutionContext.fromExecutor(new scala.concurrent.forkjoin.ForkJoinPool)

  override def doGet(req: HttpServletRequest, resp: HttpServletResponse): Unit = {
    resp.getOutputStream.println("<p>Test</p>")
    val pathSegments: Array[String] = req.getPathInfo.split("/")
    pathSegments.foreach(s => d(resp, s"<p>${s}</p>"))
  }

  override def doPost(req: HttpServletRequest, resp: HttpServletResponse): Unit = {
    val pathSegments: Array[String] = req.getPathInfo.split("/")
    pathSegments.foreach(d(resp, _))

    var line: String = ""
    var message: String = ""
    do {
      line = req.getReader().readLine()
      message += line
    } while (line != null)

    val z:Future[String] = AutowireServer.route[Api](Server)(
      autowire.Core.Request(pathSegments, upickle.read[Map[String, String]](message))
    )
    val s: String = Await.result(z, 200.millis)
    d(resp, s)
  }

  def d(resp: HttpServletResponse, s: String): Unit = {
    resp.getOutputStream.println(s)
  }
}

Any ideas / suggestions for workarounds?

File transfer

Hi,
how can I do to deal with File transfer with autowire (download and updload) ? What do you recommand ?
Thanks

simple example does not compile when using type parameters : could not find implicit value for evidence parameter of type MyReader[T]

      trait MyApi {
        val subApiString: SubApi[String]
      }

      trait SubApi[T] {
        def fooFighter(s: T): String // does not compile
//        def fooFighterString(s:String): String // compiles fine
      }

      // server-side implementation, and router
      object MyApiImpl extends MyApi {

        override val subApiString: SubApi[String] = null
      }

Full code:
https://github.com/jhegedus42/autowire/blob/9662a1bf1c97e65fe16d29c2243dc440b86deb3b/autowire/shared/src/test/scala/autowire/UpickleTests.scala#L24

Gives:

Error:(54, 101) could not find implicit value for evidence parameter of type MyReader[T]
        val routes: PartialFunction[Core.Request[String], Future[String]] = MyServerObj.route[MyApi](MyApiImpl)
Error:(54, 101) not enough arguments for method read: (implicit evidence$2: MyReader[T])T.
Unspecified value parameter evidence$2.
        val routes: PartialFunction[Core.Request[String], Future[String]] = MyServerObj.route[MyApi](MyApiImpl)
Error:(54, 101) type mismatch;
 found   : T @unchecked
 required: String
        val routes: PartialFunction[Core.Request[String], Future[String]] = MyServerObj.route[MyApi](MyApiImpl)

Any idea how to solve this issue ?

I guess the macro should understand that T is a String, or put a context bound requiring a type class instance for T .

How can I do that ?

This is how the macro generated route looks like:

Warning:scala: (RES,(<empty> match {
  case autowire.Core.Request(Seq("autowire", "Test", "MyApi", "subApiString", "fooFighter"), (args$macro$1 @ _)) => autowire.Internal.doValidate({
    <synthetic> <artifact> val x$2 = autowire.Internal.read[String, T](args$macro$1, scala.util.Left(autowire.Error.Param.Missing("s")), "s", ((x$1) => MyServerObj.read[T](x$1)));
    Nil.$colon$colon(x$2)
  }) match {
    case scala.$colon$colon((s @ (_: T @unchecked)), Nil) => scala.concurrent.Future(MyApiImpl.subApiString.fooFighter(s)).map(((x$3) => MyServerObj.write(x$3)))
    case _ => $qmark$qmark$qmark
  }
  case autowire.Core.Request(Seq("autowire", "Test", "MyApi", "subApiString", "fooFighter"), (args$macro$2 @ _)) => autowire.Internal.doValidate({
    <synthetic> <artifact> val x$5 = autowire.Internal.read[String, T](args$macro$2, scala.util.Left(autowire.Error.Param.Missing("s")), "s", ((x$4) => MyServerObj.read[T](x$4)));
    Nil.$colon$colon(x$5)
  }) match {
    case scala.$colon$colon((s @ (_: T @unchecked)), Nil) => scala.concurrent.Future(MyApiImpl.subApiString.fooFighter(s)).map(((x$6) => MyServerObj.write(x$6)))
    case _ => $qmark$qmark$qmark
  }
  case autowire.Core.Request(Seq("autowire", "Test", "MyApi", "subApiString", "fooFighter"), (args$macro$3 @ _)) => autowire.Internal.doValidate({
    <synthetic> <artifact> val x$8 = autowire.Internal.read[String, T](args$macro$3, scala.util.Left(autowire.Error.Param.Missing("s")), "s", ((x$7) => MyServerObj.read[T](x$7)));
    Nil.$colon$colon(x$8)
  }) match {
    case scala.$colon$colon((s @ (_: T @unchecked)), Nil) => scala.concurrent.Future(MyApiImpl.subApiString.fooFighter(s)).map(((x$9) => MyServerObj.write(x$9)))
    case _ => $qmark$qmark$qmark
  }
  case autowire.Core.Request(Seq("autowire", "Test", "MyApi", "subApiString", "fooFighter"), (args$macro$4 @ _)) => autowire.Internal.doValidate({
    <synthetic> <artifact> val x$11 = autowire.Internal.read[String, T](args$macro$4, scala.util.Left(autowire.Error.Param.Missing("s")), "s", ((x$10) => MyServerObj.read[T](x$10)));
    Nil.$colon$colon(x$11)
  }) match {
    case scala.$colon$colon((s @ (_: T @unchecked)), Nil) => scala.concurrent.Future(MyApiImpl.subApiString.fooFighter(s)).map(((x$12) => MyServerObj.write(x$12)))
    case _ => $qmark$qmark$qmark
  }
}: autowire.Core.Router[String]))

How to support server-side injection of data into API calls?

Sorry if this has been addressed before (tried a few searches without luck):

I haven't been able to think of a good way to inject additional information into an autowired API call on the server side. Traditionally, we might use an additional parameter to our API function ... but the fact that, on the server side, the API service is being abstractly handled as follows:

AutowireServer.route[Api](service)(autowire.Core.Request(url, body))

combined with the fact that the additional parameter wouldn't exist on the client, seems to make this impossible or non-obvious.

Example use case: running an API command that has metadata as a parameter - the server needs to fill in the remote ip address as a field in the metadata, since the client can't be trusted to do this.

Can omission of .call() result in compile error

Hopefully this makes sense. If I'm doing anything stupid please let me know : )

I'm wondering if there's any way to have call() be required to compile. I've had a couple occasions already during development where I forgot to call it and finding out why ScalaJS blew up was fairly difficult.

trait MyApi {
  def now(): Future[Long]
}

val client = new Client(...)[MyApi]

client.now().call() map (l => println("Res: " + l))
client.now() map (l => println("Res: " + l)) // Any ideas on how to make this fail to compile?

Autowire RPC with REST fallback

I've been using autowire for a couple days now in an app that I'm building to familiarize myself with scalaJS.

I have working autowire RPC's in my app, but I was wondering if there was a way to use the server side endpoints as REST endpoints if my client app does not have an autowire client configured.

I totally understand if this is outside the scope of this library, but I was wondering if you or anyone else has explored this use case.

Value classes?

I have a class that takes a (case) value class as a parameter.
It causes a compile error, such as
Cannot materialize pickler for non-case class: Array[com.sample.Event]. If this is a collection, the error can refer to the class inside.

Am I doing something wrong, or are value classes not supported by Autowire?

Support Futures (ie sloww)

Any plans to add support for futures in autowire (or I guess, upickle)?

I threw together this hack which mostly seems to work, and lets me use a function like sloww from the test code:

  class FutureReader[T](implicit reader: Reader[T]) extends Reader[Future[T]] {
    def read: PartialFunction[Js.Value, Future[T]] = {
      case blah => Future.successful(reader.read(blah))
    }
  }

Called with:

implicit def iwishihada[T](implicit reader: Reader[T]): Reader[Future[T]] = new FutureReader[T]

Pickle type for traits in method arguments

Just encountered a problem when using traits as arguments in api methods with boopickle.

So, I defined the following Api in the backend with a corresponding route:

sealed trait Tret
case class Clars(id: Int) extends Tret

trait Api {
  def fun(x: Tret): Int
}

Then, when calling this method in the frontend: Client.wire[Api].fun(Clars(12)).call().
It generates the following code:

Client.wire.apply[api.Api].self.doCall(autowire.Core.Request.apply[java.nio.ByteBuffer](collection.this.Seq.apply[String]("api", "Api", "fun"), scala.this.Predef.Map.apply[String, java.nio.ByteBuffer](scala.this.Predef.ArrowAssoc[String]("x").->[java.nio.ByteBuffer](Client.wire.apply[api.Api].self.write[api.Clars](api.Clars.apply(12))

Specifically this part (Client.wire.apply[api.Api].self.write[api.Clars](api.Clars.apply(12))) is crucial when using boopickle. Our autowire.Server defines serialization as:

object AutowireServer extends autowire.Server[ByteBuffer, Pickler, Pickler] {
  def read[Result: Pickler](p: ByteBuffer) = Unpickle[Result].fromBytes(p)
  def write[Result: Pickler](r: Result) = Pickle.intoBytes(r)
}

With Clars as type parameter, it will pickle the parameter as a Clars and not as a Tret. This is why, boopickle is unable to deserialize this parameter in the backend and (probably?) explains why I end up with a NotImplementedError in the generated router code.

As a workaround, I can explicitly specify the type: Client.wire[Api].fun(Clars(12) : Tret).call().
But this is very easy to forget without the compiler noticing and it will only result in runtime errors.

Would it be possible to handle this in autowire when calling write? So, we could take the parameter type according to the signature of the called method (which would be Tret in this example).

Support Scala 2.12

As projects move on to Scala 2.12, autowire lib should provide support for it.

Time out

Hi! I haven't found where is the proper place to set the implicit timeout for sendReceive... so, if I'd like to have a timeout beyond the 60s default, what can I do?

Overloading methods

Apparently, methods cannot be overloaded. I have a trait with the following two methods:

def bookRead(id: String): Option[BookPage]
def bookRead(id: String, page: Int): Option[BookPage]

This results in:

[error] scala.ScalaReflectionException: value bookRead encapsulates multiple overloaded alternatives and cannot be treated as a method. Consider invoking `<offending symbol>.asTerm.alternatives` and manually picking the required method
[error]         at scala.reflect.api.Symbols$SymbolApi$class.asMethod(Symbols.scala:228)
[error]         at scala.reflect.internal.Symbols$SymbolContextApiImpl.asMethod(Symbols.scala:82)
[error]         at autowire.Macros$$anonfun$8$$anonfun$apply$2.apply(Macros.scala:84)
[error]         at autowire.Macros$$anonfun$8$$anonfun$apply$2.apply(Macros.scala:73)
[error]         at autowire.Macros$Win.map(Macros.scala:26)
[error]         at autowire.Macros$Win.map(Macros.scala:25)
[error]         at autowire.Macros$$anonfun$8.apply(Macros.scala:73)
[error]         at autowire.Macros$$anonfun$8.apply(Macros.scala:49)
[error]         at autowire.Macros$Win.flatMap(Macros.scala:27)
[error]         at autowire.Macros$.clientMacro(Macros.scala:49)

sbt compile hangs after adding autowire to a play 2.4.2 project

I've created a bare minimum play-scala project using activator, added autowire and upickle. Then added the necessary autowire.Server implementation. Sbt compile just hangs and doesnt quit, i had to kill the process. I might be doing something wrong here, although i've tried to stay as close as possible to the samples in this repo. Here's the controller.

package controllers

import play.api._
import play.api.mvc.Results._
import play.api.mvc._
import upickle.default.{Reader => UpickleReader, Writer => UpickleWriter}
import autowire._

class Application extends Controller {

  def index = Action {
    Ok(views.html.index("Your new application is ready."))
  }

  def something = Action.async { request =>
    AutowireRouter.route[TestApi](TestApiImpl)(autowire.Core.Request(
      "controllers/TestApi/getPeople".split(","),
      upickle.default.read[Map[String, String]](request.body.asText.getOrElse("")))).map{ people =>
      Ok(people)
    }.recover{case e => InternalServerError(e.getMessage)}
  }

}

case class TestModel(name: String, age: Int)

trait TestApi {
  val people: Seq[TestModel] = Seq(TestModel("a",1), TestModel("b",2), TestModel("c",3), TestModel("d",4))
  def getPeople(howMany: Int): Seq[TestModel]
}

object TestApiImpl extends TestApi {
  def getPeople(howMany: Int) = people.take(howMany)
}

object AutowireRouter extends Server[String, UpickleReader, UpickleWriter] {
  def read[Result: UpickleReader](input: String) = upickle.default.read[Result](input)
  def write[Result: UpickleWriter](result: Result) = upickle.default.write(result)
}

build.sbt

name := """tester"""

version := "1.0-SNAPSHOT"

lazy val root = (project in file(".")).enablePlugins(PlayScala)

scalaVersion := "2.11.6"

libraryDependencies ++= Seq(
  jdbc,
  cache,
  ws,
  specs2 % Test,
  "com.lihaoyi" %% "autowire" % "0.2.5",
  "com.lihaoyi" %% "upickle" % "0.3.4"
)

resolvers += "scalaz-bintray" at "http://dl.bintray.com/scalaz/releases"

// Play provides two styles of routers, one expects its actions to be injected, the
// other, legacy style, accesses its actions statically.
routesGenerator := InjectedRoutesGenerator

Asynchronous return values

I'm wondering whether it is a good idea to design a protocol with blocking logic. I'm using a similar setup as in the workbench-example-app. Spray enables us to return responses encapsulated in a Future. I would like to use ReactiveMongo, but if I would need to wait before returning the result, I will have synchronous behaviour anyway. What's your take on that?

exception during macro expansion after importing widok packages

I'm experimenting with an autowire-based scalajs client. It works as expected as long as i stick to plain scalajs/dom. Now i want to try adding widok (https://widok.github.io/) to the party..

For me, just adding widok as a sbt-dependency to the javascript project (crossproject) and importing org.widok._ causes autowire to fail compilation with the following error:

[error] /Users/janne/projects/private/gb/example/js/src/main/scala/example/ScalaJSExample.scala:40: exception during macro expansion:
[error] java.lang.AssertionError: assertion failed
[error] at scala.Predef$.assert(Predef.scala:151)
[error] at upickle.Macros$.macroRImpl(Macros.scala:32)
[error] Client[Api].chapters().call().map { c =>
[error] ^

I don't know if this issue belongs to autowire or widok.. or upickle? Filing it here anyway.

Let me know if I can do anything to assist with logs or debugging. I'm really looking forward to getting these really promising technologies working together :-)

Case classes

Hi,
You say in the doc: "case classes and such don't come by default". But what do we need to do to deal with them ?

Thanks !
Mathieu

Router generation fails if API has a function with no parentheses

Minified example:

trait CustomerAPI {
  def load: Seq[Customer]
}

val customerAPI = new CustomerAPIService
val router = Router.route[CustomerAPI](customerAPI)

This does't compile and gives a "weird" error:

not enough arguments for method apply: (idx: Int)admin.shared.Customer in trait SeqLike.
[error] Unspecified value parameter idx.
[error]   val router = Router.route[CustomerAPI](customerAPI)
[error]                                         ^

It seems to somehow go into the trait and get the load function, for which you would have to call apply with an index.

Adding parentheses to the load function fixes the problem.

trait CustomerAPI {
  def load(): Seq[Customer]
}

Compilation issues

Although the compilation works fine in sbt, there are a couple of warnings. In IntelliJ, though, the project cannot be imported properly as it isn't able to resolve the dependencies.

[info] Updating {file:/Users/tim/dev/autowire/}jvm...
[warn] Binary version (0.9.0-SNAPSHOT) for dependency org.scala-lang#scala-pickling_2.10;0.9.0-SNAPSHOT
[warn]  in com.lihaoyi#autowire_2.10;0.2.3 differs from Scala binary version in project (2.10).
[info] Resolving org.scala-lang#scala-library;2.10.4 ...
[info] Compiling 3 Scala sources to /Users/tim/dev/autowire/js/target/scala-2.10/test-classes...
[info] Resolving org.jsawn#jawn-parser_2.10;0.5.4 ...
[warn]  module not found: org.jsawn#jawn-parser_2.10;0.5.4
[warn] ==== local: tried
[warn]   /Users/tim/.ivy2/local/org.jsawn/jawn-parser_2.10/0.5.4/ivys/ivy.xml
[warn] ==== public: tried
[warn]   http://repo1.maven.org/maven2/org/jsawn/jawn-parser_2.10/0.5.4/jawn-parser_2.10-0.5.4.pom
[warn] ==== sonatype-snapshots: tried
[warn]   https://oss.sonatype.org/content/repositories/snapshots/org/jsawn/jawn-parser_2.10/0.5.4/jawn-parser_2.10-0.5.4.pom
[warn] ==== Typesafe Repo: tried
[warn]   http://repo.typesafe.com/typesafe/releases/org/jsawn/jawn-parser_2.10/0.5.4/jawn-parser_2.10-0.5.4.pom
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[warn]  ::::::::::::::::::::::::::::::::::::::::::::::
[warn]  ::          UNRESOLVED DEPENDENCIES         ::
[warn]  ::::::::::::::::::::::::::::::::::::::::::::::
[warn]  :: org.jsawn#jawn-parser_2.10;0.5.4: not found
[warn]  ::::::::::::::::::::::::::::::::::::::::::::::

Also, is it intended that you're using an outdated version of Scala?

Strange exception "autowire.Error$InvalidInput" with no message

@lihaoyi I am trying to get autowire to work.

My url is http://0.0.0.0:8000/service/v1/dagr/api/DagrApi/query, body is

{
	"name" : "task"
}

and the stacktrace (server-site) is

[ERROR] [06/29/2017 10:49:41.513] [dagr-server-akka.actor.default-dispatcher-6] [akka.actor.ActorSystemImpl(dagr-server)] Error during processing of request: 'autowire.Error$InvalidInput (No error message supplied)'. Completing with 500 Internal Server Error response. To change default exception handling behavior, provide a custom ExceptionHandler.
autowire.Error$InvalidInput
	at autowire.Internal$.doValidate(Internal.scala:49)
	at dagr.webservice.DagrApiService$$anonfun$1.applyOrElse(DagrApiService.scala:120)
	at dagr.webservice.DagrApiService$$anonfun$1.applyOrElse(DagrApiService.scala:120)
	at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:34)
	at dagr.webservice.DagrApiService.$anonfun$queryRoute$3(DagrApiService.scala:120)
	at akka.http.scaladsl.server.util.ApplyConverterInstances$$anon$1.$anonfun$apply$1(ApplyConverterInstances.scala:14)
	at akka.http.scaladsl.server.ConjunctionMagnet$$anon$2.$anonfun$apply$3(Directive.scala:162)
	at akka.http.scaladsl.server.directives.BasicDirectives.$anonfun$mapRouteResult$2(BasicDirectives.scala:61)
	at akka.http.scaladsl.server.directives.FutureDirectives.$anonfun$onComplete$3(FutureDirectives.scala:37)
	at akka.http.scaladsl.util.FastFuture$.$anonfun$transformWith$1(FastFuture.scala:37)
	at akka.http.scaladsl.util.FastFuture$.strictTransform$1(FastFuture.scala:41)
	at akka.http.scaladsl.util.FastFuture$.transformWith$extension1(FastFuture.scala:45)
	at akka.http.scaladsl.util.FastFuture$.transformWith$extension0(FastFuture.scala:37)
	at akka.http.scaladsl.server.directives.FutureDirectives.$anonfun$onComplete$2(FutureDirectives.scala:37)
	at akka.http.scaladsl.server.directives.BasicDirectives.$anonfun$textract$2(BasicDirectives.scala:154)
	at akka.http.scaladsl.server.directives.BasicDirectives.$anonfun$mapRouteResult$2(BasicDirectives.scala:61)
	at akka.http.scaladsl.server.directives.BasicDirectives.$anonfun$textract$2(BasicDirectives.scala:154)
	at akka.http.scaladsl.server.directives.BasicDirectives.$anonfun$mapRequestContext$2(BasicDirectives.scala:43)
	at akka.http.scaladsl.server.directives.BasicDirectives.$anonfun$textract$2(BasicDirectives.scala:154)
	at akka.http.scaladsl.server.RouteConcatenation$RouteWithConcatenation.$anonfun$$tilde$2(RouteConcatenation.scala:47)
	at akka.http.scaladsl.util.FastFuture$.strictTransform$1(FastFuture.scala:41)
	at akka.http.scaladsl.util.FastFuture$.transformWith$extension1(FastFuture.scala:45)
	at akka.http.scaladsl.util.FastFuture$.flatMap$extension(FastFuture.scala:26)
	at akka.http.scaladsl.server.RouteConcatenation$RouteWithConcatenation.$anonfun$$tilde$1(RouteConcatenation.scala:44)
	at akka.http.scaladsl.server.directives.ExecutionDirectives.$anonfun$handleExceptions$2(ExecutionDirectives.scala:32)
	at akka.http.scaladsl.server.directives.BasicDirectives.$anonfun$mapRouteResultWith$2(BasicDirectives.scala:67)
	at akka.http.scaladsl.server.directives.BasicDirectives.$anonfun$textract$2(BasicDirectives.scala:154)
	at akka.http.scaladsl.server.directives.BasicDirectives.$anonfun$mapRouteResult$2(BasicDirectives.scala:61)
	at akka.http.scaladsl.server.directives.BasicDirectives.$anonfun$textract$2(BasicDirectives.scala:154)
	at akka.http.scaladsl.server.directives.BasicDirectives.$anonfun$mapRouteResultWith$2(BasicDirectives.scala:67)
	at akka.http.scaladsl.server.directives.BasicDirectives.$anonfun$textract$2(BasicDirectives.scala:154)
	at akka.http.scaladsl.server.directives.ExecutionDirectives.$anonfun$handleExceptions$2(ExecutionDirectives.scala:32)
	at akka.http.scaladsl.server.Route$.$anonfun$asyncHandler$1(Route.scala:79)
	at akka.stream.impl.fusing.MapAsync$$anon$24.onPush(Ops.scala:1169)
	at akka.stream.impl.fusing.GraphInterpreter.processPush(GraphInterpreter.scala:747)
	at akka.stream.impl.fusing.GraphInterpreter.processEvent(GraphInterpreter.scala:710)
	at akka.stream.impl.fusing.GraphInterpreter.execute(GraphInterpreter.scala:616)
	at akka.stream.impl.fusing.GraphInterpreterShell.runBatch(ActorGraphInterpreter.scala:471)
	at akka.stream.impl.fusing.GraphInterpreterShell.receive(ActorGraphInterpreter.scala:423)
	at akka.stream.impl.fusing.ActorGraphInterpreter.akka$stream$impl$fusing$ActorGraphInterpreter$$processEvent(ActorGraphInterpreter.scala:603)
	at akka.stream.impl.fusing.ActorGraphInterpreter$$anonfun$receive$1.applyOrElse(ActorGraphInterpreter.scala:618)
	at akka.actor.Actor.aroundReceive(Actor.scala:502)
	at akka.actor.Actor.aroundReceive$(Actor.scala:500)
	at akka.stream.impl.fusing.ActorGraphInterpreter.aroundReceive(ActorGraphInterpreter.scala:529)
	at akka.actor.ActorCell.receiveMessage(ActorCell.scala:526)
	at akka.actor.ActorCell.invoke(ActorCell.scala:495)
	at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:257)
	at akka.dispatch.Mailbox.run(Mailbox.scala:224)
	at akka.dispatch.Mailbox.exec(Mailbox.scala:234)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)

Branch (if you want to check out): https://github.com/fulcrumgenomics/dagr/tree/nh_akka_http

Command:
java -Xmx8G -jar dagr/webservice/target/scala-2.12/dagr-webservice-0.2.1-SNAPSHOT.jar --webservice true --host 0.0.0.0 --port 8000 SleepyPipeline -j -n 10 -s 42

Server pushes through autowire?

Autowire is a very cool piece of technology, making it very easy to communicate from Scala.js to a Scala-based server process (personally, I use Play).

It would be cool if it also supported the reverse case as well: "calls" / "pushes" / "updates" coming from the server to the client (using Play websockets, Atmosphere, or whatever one wants to use).

Of course this is a feature-request, but I suspect (or hope) it is something that autowire is already capable of when correctly set-up...?

The addition of dependency to autowire causing problem with compilation

adding dependency "com.lihaoyi" %% "autowire" % "0.2.3" make compilation fails with error:

object creation impossible, since method PerRunReporting in trait Reporting of type => this.PerRunReporting is not defined
[error] val g = new scala.tools.nsc.Global(settings,reporter){
[error] ^

scala version: 2.11.1

The last version of autowire which works for me is 0.1.2

do you have any temporary workaround I can use?

Nested traits

Hi

I'm not sure if I should classify this as general advice, a bug or a feature request, but here goes:

I've just tried creating an API of nested traits. The reason I wanted this is to avoid having multiple routers on the server side and multiple clients on the client side while still "namespacing" the API and therefore avoid putting all methods in the same trait. I figure it's less messy. Anyway, here's some example code:

trait Calculator {
  def add(a: Int, b: Int): Int
  def slowAdd(a: Int, b: Int): Future[Int]

  trait Multiplication {
    def times(a: Int, b: Int): Int
    def slowTimes(a: Int, b: Int): Future[Int]
  }

  def multiplication: Multiplication
}

object CalculatorImpl extends api.Calculator {
  def add(a: Int, b: Int): Int = a + b
  def slowAdd(a: Int, b: Int): Future[Int] = Future.successful(a + b)

  object multiplication extends Multiplication {
    def slowTimes(a: Int, b: Int): Future[Int] = Future.successful(a * b)
    def times(a: Int, b: Int): Int = a * b
  }
}

This fails compiling:

[error] /home/alen/projects/skim/jvm/app/controllers/Api.scala:22: api.CalculatorImpl.multiplication.type does not take parameters
[error]     val calculator = Server.route[Calculator](CalculatorImpl)

So, the questions here are:

  1. Should I not bother and just have multiple clients for each distinct API?
  2. What is the parameter that is trying to get passed?
  3. Is this a potential feature in the future?
  4. Is this a bug?

Cheers, Alen

Custom header

Hi as I may need to use OAuth facilities I would like to ask if I could add some custom headers to the request from client side or not.

Seems to add escaping not needed to serialized format

From my testing of scalajs-transport, it seems like Autowire (or uPickle) adds escaping of "-s and even backslashes:

["{"req":{"path":["shared","Api","echo"],"args":{"s":""Test from client""}},"id":1}"]

["{"res":""Received on server: Test from client"","id":1}"]

Possible issue using ClassTag in autowire calls

I had a working API that looked like

final case class OneShot(id: CommandId, body: String, meta: SysCmdMetaData)
extends Command[SysCmdMetaData]

def exec(data: List[OneShot]): Future[List[RunResult]]

with the js implementation of exec being:

  def exec(cmds: List[OneShot]): Rx[List[RunResult]] = {
    println("Verifying outer exec is called")
    AutowireClient[Api].exec(cmds).call().toRx.map {
      case Some(attempt) => attempt match {
        case Success(output) => output
        case Failure(err) =>
          List(RunResult.fakeResult(s"Error: ${err.getCause}!", NONFATAL_APP_ERR))
      }
      case None => List(RunResult.fakeResult(""))
    }
  }

In an attempt to generify things a bit, I changed the API's exec signature to:

  def exec[M <: CommandMetaData : ClassTag, C <: Command[M] : ClassTag]
  (data: List[C]): Future[List[RunResult]]

and the implementation to:

  def exec[M <: CommandMetaData : ClassTag, C <: Command[M] : ClassTag]
  (cmds: List[C]): Rx[List[RunResult]] = {
    println("Verifying outer exec is called")
    AutowireClient[Api].exec[M, C](cmds).call().toRx.map {
      case Some(attempt) => attempt match {
        case Success(output) => output
        case Failure(err) =>
          List(RunResult.fakeResult(s"Error: ${err.getCause}!", NONFATAL_APP_ERR))
      }
      case None => List(RunResult.fakeResult(""))
    }
  }

This results in the compile error:

You can't call the .call() method on autowire.`package`.unwrapClientProxy[model.Api, java.nio.ByteBuffer, boopickle.Default.Pickler, boopickle.Default.Pickler](client.AutowireClient.apply[model.Api]).exec[M, C](cmds)(evidence$1, evidence$2), only on autowired function calls.
[error]     AutowireClient[Api].exec[M, C](cmds).call().toRx.map {```

Serialization library

Hi,
I really need to serialize Classes not depending to a sealed trait. Upickle, unfortunately, cannot do this. Is it planned to implement this in upickle or is there an alternative library achieving this working in autowire ?

Thanks
Mathieu

Autowire 0.1.4: HTTP ERROR 500

Hi,
after upgrading successfully upickle to 2.1 (https://github.com/mathieuleclaire/scalaTraJSTagsWireRx), I tried upgrading autowire to 0.1.4, and after modifying the minor API changes, my application fails when I launch web page with that message :

HTTP ERROR 500

Problem accessing /. Reason:

    scala.tools.nsc.Global$gen$.mkBlock(Lscala/collection/immutable/List;)Lscala/reflect/internal/Trees$Tree;

Caused by:

org.fusesource.scalate.TemplateException: scala.tools.nsc.Global$gen$.mkBlock(Lscala/collection/immutable/List;)Lscala/reflect/internal/Trees$Tree;
    at org.fusesource.scalate.TemplateEngine.compileAndLoad(TemplateEngine.scala:732)
    at org.fusesource.scalate.TemplateEngine.compileAndLoadEntry(TemplateEngine.scala:699)
    at org.fusesource.scalate.TemplateEngine.liftedTree1$1(TemplateEngine.scala:419)
    at org.fusesource.scalate.TemplateEngine.load(TemplateEngine.scala:413)
    at org.fusesource.scalate.TemplateEngine.load(TemplateEngine.scala:483)
    at org.scalatra.scalate.ScalateSupport$class.org$scalatra$scalate$ScalateSupport$$renderScalateErrorPage(ScalateSupport.scala:148)
    at org.scalatra.scalate.ScalateSupport$class.renderUncaughtException(ScalateSupport.scala:139)
    at fr.iscpif.app.MyScalatraServlet.renderUncaughtException(MyScalatraServlet.scala:19)
    at org.scalatra.ScalatraBase$$anonfun$executeRoutes$2$$anonfun$apply$5.apply(ScalatraBase.scala:182)
    at org.scalatra.ScalatraBase$$anonfun$executeRoutes$2$$anonfun$apply$5.apply(ScalatraBase.scala:179)
    at org.scalatra.ScalatraBase$class.org$scalatra$ScalatraBase$$cradleHalt(ScalatraBase.scala:206)
    at org.scalatra.ScalatraBase$$anonfun$executeRoutes$2.apply(ScalatraBase.scala:176)
    at org.scalatra.ScalatraBase$$anonfun$executeRoutes$2.apply(ScalatraBase.scala:175)
    at org.scalatra.ScalatraBase$class.org$scalatra$ScalatraBase$$cradleHalt(ScalatraBase.scala:206)
    at org.scalatra.ScalatraBase$class.executeRoutes(ScalatraBase.scala:175)
    at org.scalatra.ScalatraServlet.executeRoutes(ScalatraServlet.scala:49)
    at org.scalatra.ScalatraBase$$anonfun$handle$1.apply$mcV$sp(ScalatraBase.scala:113)
    at org.scalatra.ScalatraBase$$anonfun$handle$1.apply(ScalatraBase.scala:113)
    at org.scalatra.ScalatraBase$$anonfun$handle$1.apply(ScalatraBase.scala:113)
    at scala.util.DynamicVariable.withValue(DynamicVariable.scala:58)
    at org.scalatra.DynamicScope$class.withResponse(DynamicScope.scala:80)
    at org.scalatra.ScalatraServlet.withResponse(ScalatraServlet.scala:49)
    at org.scalatra.DynamicScope$$anonfun$withRequestResponse$1.apply(DynamicScope.scala:60)
    at scala.util.DynamicVariable.withValue(DynamicVariable.scala:58)
    at org.scalatra.DynamicScope$class.withRequest(DynamicScope.scala:71)
    at org.scalatra.ScalatraServlet.withRequest(ScalatraServlet.scala:49)
    at org.scalatra.DynamicScope$class.withRequestResponse(DynamicScope.scala:59)
    at org.scalatra.ScalatraServlet.withRequestResponse(ScalatraServlet.scala:49)
    at org.scalatra.ScalatraBase$class.handle(ScalatraBase.scala:111)
    at org.scalatra.ScalatraServlet.org$scalatra$servlet$ServletBase$$super$handle(ScalatraServlet.scala:49)
    at org.scalatra.servlet.ServletBase$class.handle(ServletBase.scala:43)
    at fr.iscpif.app.MyScalatraServlet.org$scalatra$scalate$ScalateSupport$$super$handle(MyScalatraServlet.scala:19)
    at org.scalatra.scalate.ScalateSupport$class.handle(ScalateSupport.scala:130)
    at fr.iscpif.app.MyScalatraServlet.handle(MyScalatraServlet.scala:19)
    at org.scalatra.ScalatraServlet.service(ScalatraServlet.scala:54)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:669)
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:455)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137)
    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:560)
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231)
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1072)
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:382)
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193)
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1006)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135)
    at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:255)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)
    at org.eclipse.jetty.server.Server.handle(Server.java:365)
    at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:485)
    at org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:926)
    at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:988)
    at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:635)
    at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235)
    at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82)
    at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:628)
    at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:52)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)
    at java.lang.Thread.run(Thread.java:744)
Caused by: java.lang.NoSuchMethodError: scala.tools.nsc.Global$gen$.mkBlock(Lscala/collection/immutable/List;)Lscala/reflect/internal/Trees$Tree;
    at scala.tools.nsc.ast.parser.TreeBuilder.makeBlock(TreeBuilder.scala:110)
    at scala.tools.nsc.ast.parser.Parsers$Parser.block(Parsers.scala:1689)
    at scala.tools.nsc.ast.parser.Parsers$Parser.blockExpr(Parsers.scala:1678)
    at scala.tools.nsc.ast.parser.Parsers$Parser.simpleExpr(Parsers.scala:1597)
    at scala.tools.nsc.ast.parser.Parsers$Parser.prefixExpr(Parsers.scala:1565)
    at scala.tools.nsc.ast.parser.Parsers$Parser.postfixExpr(Parsers.scala:1548)
    at scala.tools.nsc.ast.parser.Parsers$Parser.parseOther$1(Parsers.scala:1446)
    at scala.tools.nsc.ast.parser.Parsers$Parser.expr0(Parsers.scala:1500)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$expr$1.apply(Parsers.scala:1350)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$expr$1.apply(Parsers.scala:1350)
    at scala.tools.nsc.ast.parser.Parsers$Parser.withPlaceholders(Parsers.scala:1195)
    at scala.tools.nsc.ast.parser.Parsers$Parser.expr(Parsers.scala:1350)
    at scala.tools.nsc.ast.parser.Parsers$Parser.expr(Parsers.scala:1348)
    at scala.tools.nsc.ast.parser.Parsers$Parser.parseIf$1(Parsers.scala:1357)
    at scala.tools.nsc.ast.parser.Parsers$Parser.expr0(Parsers.scala:1362)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$expr$1.apply(Parsers.scala:1350)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$expr$1.apply(Parsers.scala:1350)
    at scala.tools.nsc.ast.parser.Parsers$Parser.withPlaceholders(Parsers.scala:1195)
    at scala.tools.nsc.ast.parser.Parsers$Parser.expr(Parsers.scala:1350)
    at scala.tools.nsc.ast.parser.Parsers$Parser.statement(Parsers.scala:1323)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$blockStatSeq$1.apply(Parsers.scala:3110)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$blockStatSeq$1.apply(Parsers.scala:3092)
    at scala.tools.nsc.ast.parser.Parsers$Parser.checkNoEscapingPlaceholders(Parsers.scala:464)
    at scala.tools.nsc.ast.parser.Parsers$Parser.blockStatSeq(Parsers.scala:3092)
    at scala.tools.nsc.ast.parser.Parsers$Parser.block(Parsers.scala:1689)
    at scala.tools.nsc.ast.parser.Parsers$Parser.blockExpr(Parsers.scala:1678)
    at scala.tools.nsc.ast.parser.Parsers$Parser.simpleExpr(Parsers.scala:1597)
    at scala.tools.nsc.ast.parser.Parsers$Parser.prefixExpr(Parsers.scala:1565)
    at scala.tools.nsc.ast.parser.Parsers$Parser.postfixExpr(Parsers.scala:1548)
    at scala.tools.nsc.ast.parser.Parsers$Parser.parseOther$1(Parsers.scala:1446)
    at scala.tools.nsc.ast.parser.Parsers$Parser.expr0(Parsers.scala:1500)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$expr$1.apply(Parsers.scala:1350)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$expr$1.apply(Parsers.scala:1350)
    at scala.tools.nsc.ast.parser.Parsers$Parser.withPlaceholders(Parsers.scala:1195)
    at scala.tools.nsc.ast.parser.Parsers$Parser.expr(Parsers.scala:1350)
    at scala.tools.nsc.ast.parser.Parsers$Parser.statement(Parsers.scala:1323)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$blockStatSeq$1.apply(Parsers.scala:3110)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$blockStatSeq$1.apply(Parsers.scala:3092)
    at scala.tools.nsc.ast.parser.Parsers$Parser.checkNoEscapingPlaceholders(Parsers.scala:464)
    at scala.tools.nsc.ast.parser.Parsers$Parser.blockStatSeq(Parsers.scala:3092)
    at scala.tools.nsc.ast.parser.Parsers$Parser.block(Parsers.scala:1689)
    at scala.tools.nsc.ast.parser.Parsers$Parser.blockExpr(Parsers.scala:1678)
    at scala.tools.nsc.ast.parser.Parsers$Parser.simpleExpr(Parsers.scala:1597)
    at scala.tools.nsc.ast.parser.Parsers$Parser.prefixExpr(Parsers.scala:1565)
    at scala.tools.nsc.ast.parser.Parsers$Parser.postfixExpr(Parsers.scala:1548)
    at scala.tools.nsc.ast.parser.Parsers$Parser.parseOther$1(Parsers.scala:1446)
    at scala.tools.nsc.ast.parser.Parsers$Parser.expr0(Parsers.scala:1500)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$expr$1.apply(Parsers.scala:1350)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$expr$1.apply(Parsers.scala:1350)
    at scala.tools.nsc.ast.parser.Parsers$Parser.withPlaceholders(Parsers.scala:1195)
    at scala.tools.nsc.ast.parser.Parsers$Parser.expr(Parsers.scala:1350)
    at scala.tools.nsc.ast.parser.Parsers$Parser.statement(Parsers.scala:1323)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$blockStatSeq$1.apply(Parsers.scala:3110)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$blockStatSeq$1.apply(Parsers.scala:3092)
    at scala.tools.nsc.ast.parser.Parsers$Parser.checkNoEscapingPlaceholders(Parsers.scala:464)
    at scala.tools.nsc.ast.parser.Parsers$Parser.blockStatSeq(Parsers.scala:3092)
    at scala.tools.nsc.ast.parser.Parsers$Parser.block(Parsers.scala:1689)
    at scala.tools.nsc.ast.parser.Parsers$Parser.blockExpr(Parsers.scala:1678)
    at scala.tools.nsc.ast.parser.Parsers$Parser.simpleExpr(Parsers.scala:1597)
    at scala.tools.nsc.ast.parser.Parsers$Parser.prefixExpr(Parsers.scala:1565)
    at scala.tools.nsc.ast.parser.Parsers$Parser.postfixExpr(Parsers.scala:1548)
    at scala.tools.nsc.ast.parser.Parsers$Parser.parseOther$1(Parsers.scala:1446)
    at scala.tools.nsc.ast.parser.Parsers$Parser.expr0(Parsers.scala:1500)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$expr$1.apply(Parsers.scala:1350)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$expr$1.apply(Parsers.scala:1350)
    at scala.tools.nsc.ast.parser.Parsers$Parser.withPlaceholders(Parsers.scala:1195)
    at scala.tools.nsc.ast.parser.Parsers$Parser.expr(Parsers.scala:1350)
    at scala.tools.nsc.ast.parser.Parsers$Parser.expr(Parsers.scala:1348)
    at scala.tools.nsc.ast.parser.Parsers$Parser.funDefRest(Parsers.scala:2605)
    at scala.tools.nsc.ast.parser.Parsers$Parser.funDefOrDcl(Parsers.scala:2566)
    at scala.tools.nsc.ast.parser.Parsers$Parser.defOrDcl(Parsers.scala:2451)
    at scala.tools.nsc.ast.parser.Parsers$Parser.nonLocalDefOrDcl(Parsers.scala:2463)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$templateStat$1$$anonfun$applyOrElse$3.apply(Parsers.scala:3020)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$templateStat$1$$anonfun$applyOrElse$3.apply(Parsers.scala:3020)
    at scala.tools.nsc.ast.parser.Parsers$Parser.joinComment(Parsers.scala:701)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$templateStat$1.applyOrElse(Parsers.scala:3020)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$templateStat$1.applyOrElse(Parsers.scala:3015)
    at scala.tools.nsc.ast.parser.Parsers$Parser.statSeq(Parsers.scala:2947)
    at scala.tools.nsc.ast.parser.Parsers$Parser.templateStats(Parsers.scala:3014)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$templateStatSeq$1.apply(Parsers.scala:3001)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$templateStatSeq$1.apply(Parsers.scala:2978)
    at scala.tools.nsc.ast.parser.Parsers$Parser.checkNoEscapingPlaceholders(Parsers.scala:464)
    at scala.tools.nsc.ast.parser.Parsers$Parser.templateStatSeq(Parsers.scala:2978)
    at scala.tools.nsc.ast.parser.Parsers$Parser.templateBody(Parsers.scala:2907)
    at scala.tools.nsc.ast.parser.Parsers$Parser.templateBodyOpt(Parsers.scala:2914)
    at scala.tools.nsc.ast.parser.Parsers$Parser.templateOpt(Parsers.scala:2878)
    at scala.tools.nsc.ast.parser.Parsers$Parser.objectDef(Parsers.scala:2763)
    at scala.tools.nsc.ast.parser.Parsers$Parser.tmplDef(Parsers.scala:2702)
    at scala.tools.nsc.ast.parser.Parsers$Parser.topLevelTmplDef(Parsers.scala:2683)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$topStat$1$$anonfun$applyOrElse$2.apply(Parsers.scala:2970)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$topStat$1$$anonfun$applyOrElse$2.apply(Parsers.scala:2970)
    at scala.tools.nsc.ast.parser.Parsers$Parser.joinComment(Parsers.scala:701)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$topStat$1.applyOrElse(Parsers.scala:2970)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$topStat$1.applyOrElse(Parsers.scala:2963)
    at scala.tools.nsc.ast.parser.Parsers$Parser.statSeq(Parsers.scala:2947)
    at scala.tools.nsc.ast.parser.Parsers$Parser.topStatSeq(Parsers.scala:2962)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$compilationUnit$1.topstats$1(Parsers.scala:3160)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$compilationUnit$1.topstats$1(Parsers.scala:3152)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$compilationUnit$1.apply(Parsers.scala:3166)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$compilationUnit$1.apply(Parsers.scala:3128)
    at scala.tools.nsc.ast.parser.Parsers$Parser.checkNoEscapingPlaceholders(Parsers.scala:464)
    at scala.tools.nsc.ast.parser.Parsers$Parser.compilationUnit(Parsers.scala:3128)
    at scala.tools.nsc.ast.parser.Parsers$SourceFileParser$$anonfun$parseStartRule$1.apply(Parsers.scala:146)
    at scala.tools.nsc.ast.parser.Parsers$SourceFileParser$$anonfun$parseStartRule$1.apply(Parsers.scala:146)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$parse$1.apply(Parsers.scala:354)
    at scala.tools.nsc.ast.parser.Parsers$Parser$$anonfun$parse$1.apply(Parsers.scala:354)
    at scala.tools.nsc.ast.parser.Parsers$Parser.parseRule(Parsers.scala:347)
    at scala.tools.nsc.ast.parser.Parsers$Parser.parse(Parsers.scala:354)
    at scala.tools.nsc.ast.parser.Parsers$UnitParser.smartParse(Parsers.scala:243)
    at scala.tools.nsc.ast.parser.SyntaxAnalyzer.scala$tools$nsc$ast$parser$SyntaxAnalyzer$$initialUnitBody(SyntaxAnalyzer.scala:87)
    at scala.tools.nsc.ast.parser.SyntaxAnalyzer$ParserPhase.apply(SyntaxAnalyzer.scala:99)
    at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:430)
    at scala.tools.nsc.Global$GlobalPhase$$anonfun$run$1.apply(Global.scala:397)
    at scala.tools.nsc.Global$GlobalPhase$$anonfun$run$1.apply(Global.scala:397)
    at scala.collection.Iterator$class.foreach(Iterator.scala:743)
    at scala.collection.AbstractIterator.foreach(Iterator.scala:1177)
    at scala.tools.nsc.Global$GlobalPhase.run(Global.scala:397)
    at scala.tools.nsc.Global$Run.compileUnitsInternal(Global.scala:1625)
    at scala.tools.nsc.Global$Run.compileUnits(Global.scala:1610)
    at scala.tools.nsc.Global$Run.compileSources(Global.scala:1605)
    at scala.tools.nsc.Global$Run.compile(Global.scala:1703)
    at org.fusesource.scalate.support.ScalaCompiler.compile(ScalaCompiler.scala:100)
    at org.fusesource.scalate.TemplateEngine.compileAndLoad(TemplateEngine.scala:757)
    ... 59 more

issues with accessor methods

I've been doing some scalajs hacking lately, and had a look at autowire the other day.
I exported a trait with an accessor method (no parameters), and that made my project stop compiling.

It really took me a while to figure out why, so i made a PR with a failing (that is, doesnt compile) test, so we can work it out. See #35

Does autowire works with generic methods?

Hi, may I know if autowire works with methods that takes in type parameters?

For example

def generateData[T](implicit generator: Gen[T]): T = ???

If it does not, what is the recommended way?

write methods for each type I want to use?

route does not compile for some complicated return value

import scala.concurrent.ExecutionContext.Implicits._

import upickle.default._
import upickle._
import autowire._

final case class NestedData(field1: Map[String, String], field2: Double)

sealed trait Result

final case class Result1(reason: String, suggestions: Seq[NestedData]) extends Result
final case class Result2() extends Result


trait MyApi {

  def rpcMethod(): Result

}

object MyServer extends autowire.Server[String, upickle.default.Reader, upickle.default.Writer]{
  def write[Result: Writer](r: Result) = upickle.default.write(r)
  def read[Result: Reader](p: String) = upickle.default.read[Result](p)

  val routes = route (??? : MyApi)
}
libraryDependencies += "com.lihaoyi" %% "autowire" % "0.2.6"

libraryDependencies += "com.lihaoyi" %% "upickle" % "0.4.3"
MyApi.scala:25: diverging implicit expansion for type upickle.default.Writer[T1]
starting with macro method macroW in trait LowPriX
  val routes = route (??? : MyApi)
                     ^
one error found

ClientCallable.call() signature

This is a bit of a nitpick but when call() is expanded it includes a call to Future.map which requires an execution context. My IDE kept deleting the import because it didn't know it needed it. Would it be possible to change the signature of call() to something like call(implicit executor: ExecutionContext)?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.