lihaoyi / autowire Goto Github PK
View Code? Open in Web Editor NEWMacros for simple/safe RPCs between Scala applications, including ScalaJS/ScalaJVM
Macros for simple/safe RPCs between Scala applications, including ScalaJS/ScalaJVM
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?
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])```
Under some circumstances, passing an Option results in autowire behaving incorrectly at runtime, I have created a minimal example.
In the middle of development on ~re-start mode, if you add a function to the shared trait and override it in the server then you would get weird errors in the test time. To compile it correctly you have to do:
sbt
clean
~re-start
The code that I am using is SPA tutorial (https://github.com/ochrons/scalajs-spa-tutorial)
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
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.
Please add a mechanism for authenticating clients, keep the sessions between calls (in case of HTTP example) and getting the identity of the caller.
is there a way (and or an example?) to stream a result through the autowire router? (for example with Slick 3.0.0 or any other reactive stream)
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
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))
)
}
}
}
}
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
Currently implicit arguments in method seems not working,for example
def impl(s:String)(implicit is:String):Unit
Is that feature 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?
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)
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?
Hi,
how can I do to deal with File transfer with autowire (download and updload) ? What do you recommand ?
Thanks
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
}
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]))
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.
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?
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.
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?
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]
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).
I setup a project according to README.md
, and I got error
type Writer is not a member of package upickle
As projects move on to Scala 2.12, autowire lib should provide support for it.
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?
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)
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
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?
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 :-)
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
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]
}
Would be nice for third party integration with the protocol if some standard protocol like JSON-RPC was used: http://www.jsonrpc.org/specification
Maybe the protocol could be specified by a pluggable protocol module?
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?
@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
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...?
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?
To avoid typos, Client should have some notion of the api path
https://github.com/lihaoyi/workbench-example-app/blob/autowire/example/js/src/main/scala/example/ScalaJSExample.scala#L13
https://github.com/lihaoyi/workbench-example-app/blob/autowire/example/jvm/src/main/scala/example/Server.scala#L50
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:
Cheers, Alen
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.
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}"]
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 {```
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
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
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
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?
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
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)
?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.