Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

diverging implicit expansion errors with Spray, Autowire and uPickle #44

Open
ozeebee opened this issue Nov 12, 2015 · 2 comments
Open

Comments

@ozeebee
Copy link

ozeebee commented Nov 12, 2015

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.

@alexmojaki
Copy link

I'm getting a somewhat similar error in my Play application:

ambiguous implicit values:
 both value derive$macro$30 of type => upickle.default.Writer[shared.IssueState]
 and value derive$macro$37 of type => upickle.default.Writer[shared.SideState]
 match expected type upickle.default.Writer[T1]

In /Users/alexhall/Dropbox/scala/debate/server/app/controllers/Application.scala:22
19    val requestText = request.body.asText.get
20    val requestJson = upickle.json.read(requestText).asInstanceOf[Js.Obj].value.toMap
21    val coreRequest: Core.Request[Value] = autowire.Core.Request(parts.split("/"), requestJson).asInstanceOf[Core.Request[Value]]
22    val future: Future[String] = AutowireServer.route[SharedApi](ApiImpl)(coreRequest).map(upickle.json.write(_)) 
23    val resultString: String = future.value.get.get
24    Ok(resultString)
25  }

@alexmojaki
Copy link

OK, I fixed my error by making sure that all classes to be pickled/unpickled had an unapply method. A more helpful error message would be nice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants