as stated in the title, I'm not able to marshal List[A]
into the proper Json (Array of Objects).
I'm using AKKA-Http and Spray-Json.
I defined two case classes:
final case class Item(id: String, pid: String, title: String)
final case class Items(items: List[Item])
And on that call GET http://localhost:8080/item
received:
class ItemEndpoint extends Directives with ItemJsonSupport {
val route: Route = {
path("item") {
get {
parameters("page".?, "size".?) {
(page, size) => (page, size) match {
case (_, _) =>
onSuccess(Server.requestHandler ? GetItemsRequest){
case response: Items =>
complete(response)
case _ =>
complete(StatusCodes.InternalServerError)
}
}
}
}
}
}
}
GetItemsRequest
is called. The latter is defined as
case class GetItemsRequest
And the RequestHandler
as
class RequestHandler extends Actor with ActorLogging {
var items : Items = _
def receive: Receive = {
case GetItemsRequest =>
items = itemFactory.getItems
sender() ! items
}
}
Where getItems
performs a query on Cassandra
via Spark
def getItems() : Items = {
val query = sc.sql("SELECT * FROM mydb")
Items(query.map(row => Item(row.getAs[String]("item"),
row.getAs[String]("pid"), row.getAs[String]("title")
)).collect().toList)
}
returning Items
containing List[Item]
. All the objects are printed correctly (some of them have null fields).
Using ItemJsonFormatter
trait ItemJsonSupport extends SprayJsonSupport with DefaultJsonProtocol {
implicit val itemFormat: RootJsonFormat[Item] = jsonFormat3(Item)
implicit val itemsFormat: RootJsonFormat[Items] = jsonFormat1(Items)
}
Leads to the following error:
[simple-rest-system-akka.actor.default-dispatcher-9] [akka.actor.ActorSystemImpl(simple-rest-system)] Error during processing of request: 'requirement failed'. Completing with 500 Internal Server Error response. To change default exception handling behavior, provide a custom ExceptionHandler. java.lang.IllegalArgumentException: requirement failed
I tried catching the exception and work on it but I haven't obtained more intel on the problem.
I followed AKKA DOCS on marshalling.
When doing the same thing, but getting only 1 item, it works just fine, I obtain a json containing all Item
's parameters well formatted.
{
"id": "78289232389",
"pid": "B007ILCQ8I",
"title": ""
}
Even looking at other related Q/A I was not able to find an answer, so What's Causing this? How can I fix it?
All the objects are printed correctly (some of them have null fields).
The exception could be thrown because getItems
is returning Item
objects that have one or more null field values.
One way to handle this is to replace nulls with empty strings:
def rowToItem(row: Row): Item = {
Item(Option(row.getAs[String]("item")).getOrElse(""),
Option(row.getAs[String]("pid")).getOrElse(""),
Option(row.getAs[String]("title")).getOrElse(""))
}
def getItems(): Items = {
val query = sc.sql("SELECT * FROM mydb")
Items(query.map(row => rowToItem(row)).collect().toList)
}