как сериализовать массив типов Scala в массив JSON в ответе HTTP с помощью Spray?

Я новичок в работе со спреем, немного разбираюсь в Scala, и, хотя документация по спрею в целом очень хороша, я не могу найти подходящего примера для моей проблемы. Я пытаюсь сделать что-то очень простое: сериализовать (или упорядочить) массив Scala моего типа в массив json, используя либо json4s, либо spray-json. В этом примере я использую spray-json со следующей записью в build.sbt:

libraryDependencies ++= Seq(
  "io.spray" %%  "spray-json" % "1.3.2"
)

В приведенном ниже коде возникает следующая ошибка компилятора:

[error] /Users/scott/integration/src/main/scala/com/anomaly/rest/AnomalyService.scala:101: type mismatch;
[error]  found   : Array[com.anomaly.model.KDEOutlier]
[error]  required: spray.httpx.marshalling.ToResponseMarshallable
[error]             complete(outlierService.getOutliersOverTime(startTime, endTime))

/* request handling actor and service */

package com.anomaly.rest

import akka.actor.Actor
import akka.event.slf4j.SLF4JLogging
import spray.routing._
import spray.http._
import spray.json._
import DefaultJsonProtocol._
import MediaTypes._

import anomaly.model.KDEOutlier
import anomaly.dal.KDEOutliersDAO

class AnomalyServiceActor extends Actor with AnomalyService {
  def actorRefFactory = context
  def receive = runRoute(anomaliesRoute)
}

trait AnomalyService extends HttpService with SLF4JLogging {
  val outlierService = KDEOutliersDAO
  val anomaliesRoute = respondWithMediaType(MediaTypes.`application/json`) {
    path("anomalies/overtime ") {
      get {
        parameters('startTime.as[Long], 'endTime.as[Long]) { (startTime, endTime) =>
            complete(outlierService.getOutliersOverTime(startTime, endTime))
        }
      }
    }
  }
}


/* model */

package com.anomaly.model
import java.util.Date

case class KDEOutlier(date: Long, score: Double)


/* dao service called by request handler service */

package com.anomaly.dal

import java.util.Date
import com.anomaly.model.KDEOutlier
import com.anomaly.model.KDERawOutlier

object KDEOutliersDAO {  
    def getOutliersOverTime(startTime: Long, endTime: Long): Array[KDEOutlier] = {
        Array(KDEOutlier(Date.UTC(2013,5,2,0,0,0),0.7695), KDEOutlier(Date.UTC(2013,5,3,0,0,0),0.7648),
                KDEOutlier(Date.UTC(3,5,4,0,0,0),0.7645), KDEOutlier(Date.UTC(2013,5,5,0,0,0),0.7638),
                KDEOutlier(Date.UTC(2013,5,6,0,0,0),0.8549), KDEOutlier(Date.UTC(2013,5,7,0,0,0),0.9562),
                KDEOutlier(Date.UTC(2013,5,9,0,0,0),0.7574), KDEOutlier(Date.UTC(2013,5,10,0,0,0),0.7543))
    }
}

person scott    schedule 23.12.2015    source источник


Ответы (1)


Вам также необходимо определить неявные RootJsonFormat (например, jsonFormat2(KDEOutlier)) и import spray.httpx.SprayJsonSupport._:

package com.anomaly.rest

import com.scalakata._

import akka.actor.Actor
import akka.event.slf4j.SLF4JLogging
import spray.routing._
import spray.http._
import spray.json._
import spray.httpx.SprayJsonSupport._
import DefaultJsonProtocol._
import MediaTypes._
import java.util.Date

case class KDEOutlier(date: Long, score: Double)

class AnomalyServiceActor extends Actor with AnomalyService {
  def actorRefFactory = context
  def receive = runRoute(anomaliesRoute)
}

trait AnomalyService extends HttpService with SLF4JLogging {

  implicit val outlierFormat = jsonFormat2(KDEOutlier)

  val anomaliesRoute = respondWithMediaType(MediaTypes.`application/json`) {
    path("anomalies/overtime ") {
      get {
        parameters('startTime.as[Long], 'endTime.as[Long]) { (startTime, endTime) => {
          val result = Array(KDEOutlier(Date.UTC(2013,5,2,0,0,0),0.7695), KDEOutlier(Date.UTC(2013,5,3,0,0,0),0.7648),
                KDEOutlier(Date.UTC(3,5,4,0,0,0),0.7645), KDEOutlier(Date.UTC(2013,5,5,0,0,0),0.7638),
                KDEOutlier(Date.UTC(2013,5,6,0,0,0),0.8549), KDEOutlier(Date.UTC(2013,5,7,0,0,0),0.9562),
                KDEOutlier(Date.UTC(2013,5,9,0,0,0),0.7574), KDEOutlier(Date.UTC(2013,5,10,0,0,0),0.7543))
          complete(result)
        }                                                     }
      }
    }
  }
}

Вы можете попробовать этот фрагмент на http://scalakata.com.

person Arnout Engelen    schedule 23.12.2015
comment
Спасибо, я также добавил этот импорт. Я все еще получаю ту же ошибку компилятора, что и выше. - person scott; 23.12.2015
comment
ОК - у вас есть неявный экземпляр RootJsonFormat[KDEOutlier] в области видимости? например jsonFormat2(KDEOutlier)? - person Arnout Engelen; 23.12.2015
comment
Да, пробовал это ниже, ни способ jsonFormat2 не работал (фактически выдавал дополнительную ошибку к уже показанной), ни закомментированная строка: - person scott; 24.12.2015
comment
object AnomalyJsonProtocol extends DefaultJsonProtocol { неявный объект outlierResultFormat extends RootJsonFormat[KDEOutlier] { // def write(o: KDEOutlier) = JsArray(JsNumber(o.date), JsNumber(o.score)) def write(o: KDEOutlier) = jsonFormat2( KDEOutlier) } } - person scott; 24.12.2015
comment
Также пробовал: объект AnomalyJsonProtocol extends DefaultJsonProtocol { implicit val outlierFormat = jsonFormat2(KDEOutlier) } (тоже не сработало) } - person scott; 24.12.2015
comment
Обновил ответ примером - это работает для вас? - person Arnout Engelen; 24.12.2015