Open er-rishi opened 3 years ago
I've been running into the same issue and believe that it's a bug. Did you find a way around this?
If you are using spray-json, you should use https://github.com/sangria-graphql/sangria-spray-json/blob/main/src/main/scala/sangria/marshalling/sprayJson.scala somewhere. It's strange that it does not appear in the stack trace.
@yanns I've looked into the issue more, and I'm convinced it is a bug with sangria. I created a test case for it on my own fork, located here. I should note that although this test and the above issue use spray-json, I have been running into the same issue with circe.
The issue seems to stem from a lack of type safety within the default FromInput
implementations. The cast located here in SeqFromInput
is where that error is occurring. With a array of depth 1 ([SomeInputObject!]!
for example), this works fine, because the node
it is given is actually a Vector
. However, when it recursively calls itself, which it does when the depth is greater than 1 ([[SomeInputObject!]!]!
for example), node
is instead a representation of an array in whatever json library is being used. For spray-json, this is JsArray
, which explains the java.lang.ClassCastException: spray.json.JsArray cannot be cast to scala.collection.Seq
error. For circe, this is a Json.JArray
.
I have been able to circumvent this issue by creating my own implementation of SeqFromInput
, as well as optionInput
. Those are below:
case class SeqInput[T](delegate: FromInput[T]) extends FromInput.SeqFromInput[T](delegate) {
override def fromResult(node: marshaller.Node): Seq[T] = {
super.fromResult(nodeToVector(node).asInstanceOf[marshaller.Node])
}
private def nodeToVector(node: marshaller.Node): Vector[_] =
node match {
case json: Json =>
json.asArray
// the get or else will fail, but there's no way to recover
.getOrElse(json.asInstanceOf[Vector[_]])
case _ => node.asInstanceOf[Vector[_]]
}
}
case class OptInput[T](delegate: FromInput[T]) extends FromInput[Option[T]] {
override val marshaller: ResultMarshaller = delegate.marshaller
override def fromResult(node: marshaller.Node): Option[T] = {
node match {
case opt: Option[_] => opt.map(elem => delegate.fromResult(elem.asInstanceOf[delegate.marshaller.Node]))
case elem => Some(delegate.fromResult(elem.asInstanceOf[delegate.marshaller.Node]))
}
}
}
Clearly, these are circe specific and do not work in the general case. However, they help demonstrate what the issue is and function as a stopgap solution for now. Unfortunately, I am not too familiar with the sangria source code, so I'm not sure if I'd be able to fix this myself. It seems to me that a solution might involve having FromInput
be given a reference to an InputUnmarshaller
and then doing something similar to above.
Thanks for the detailed information. Yes, it seems you found something..
How to tackle this:
If someone wants to try this, please comment.
Related to #449
One of the input of the GQL query is the nested list of case class. For ex:
case class User (id: Int, name:String)
when I run the application I am getting the following error:
input request:
Any help will be appriciated. Thanks