Как настроить неявное преобразование json для Spray + Akka Actor

Я разработчик Java и новичок в scala.

Я реализую некоторый API для отдыха, который использует спрей и акка. API должен предоставлять какой-то пользовательский CRUD. Я буду использовать только создать пользователя в этом вопросе ...

trait DefaultJsonFormats extends DefaultJsonProtocol with SprayJsonSupport with MetaMarshallers {}

class RegistrationService(registration: ActorRef)
   (implicit executionContext: ExecutionContext) 
                      extends Directives with DefaultJsonFormats {
implicit val timeout = Timeout(2.seconds)
implicit val userFormat = jsonFormat3(User)
implicit val registerFormat = jsonFormat1(Register)
implicit val registeredFormat = jsonFormat1(Registered)

  val route =
    path("register") {
      post {  handleWith { ru: Register => (registration ? ru).mapTo[Registered] } }
}

//------ Актер

object RegistrationActor {
  case class User(id:String, name:String)
  case class Register(user: User)
  case class Registered(status: String)
  case object NotRegistered
}

class RegistrationActor(implDef: String) extends Actor {
 def receive: Receive = {
    case Register(user)=>
        val status=// create user real code with return status
        sender ! new Registered(status)
 } }

При таком подходе json-сериализация и дезиарелизация довольно раздражают. Для каждого объекта, который мне нужно иметь дело с API, я должен определить соответствующий формат.

implicit val userFormat = jsonFormat3(User)
implicit val registerFormat = jsonFormat1(Register)
implicit val registeredFormat = jsonFormat1(Registered) 

Я хотел бы избежать такого определения и использовать какой-то общий конвертер json и возвращать объекты pojo, поэтому преобразование будет происходить под капотом

Вопрос в том, как я могу изменить этот код для использования по умолчанию конвертера Gson / Jackson / Spray по умолчанию и избежать определения неявного ... jsonFormats?


person Julias    schedule 12.10.2015    source источник


Ответы (1)


Для каждого объекта, который мне нужно иметь дело с API, я должен определить соответствующий формат.

Это нормально сделать это один раз в классе "JsonProtocol" и при необходимости импортировать его. вместо того, чтобы каждый раз определять новые форматы:

import MyJsonProtocol._

val route =
  path("register") {
    post {  handleWith { ru: Register => (registration ? ru).mapTo[Registered] } }

как я могу изменить этот код для использования по умолчанию конвертера Gson / Jackson / Spray по умолчанию и избежать определения неявного ... jsonFormats?

Вам нужно будет объявить неявный маршаллер от Registered до HttpResponse (или промежуточное значение, например String), который поддерживался Джексоном вместо spray-json, а затем импортировать этот маршаллер вместо SprayJsonSupport.

Взгляните на реализация SprayJsonSupport, чтобы узнать, как это сделать. Это довольно просто, если вам удобны неявные преобразования.

Вы также можете увидеть, как это делается, в Json4sSupport в Spray - эта черта реализует Marshaller[T, String] для ВСЕХ типов T. Затем во время выполнения библиотека Json4s попытается сериализовать объект в JSON.

При таком подходе сериализация и дезиаризация json довольно раздражает.

Есть два основных преимущества подхода spray-jsons перед подходом Джексона:

  • Нет отражения, поэтому он быстрее во время выполнения
  • Это не определение форматов JSON во время выполнения, поэтому любые проблемы обнаруживаются во время компиляции.
person Rich    schedule 12.10.2015
comment
Спасибо, я просмотрел пример JsonProtocol - и он делает то же самое, что и я, о котором идет речь (например, неявный val userFormat = jsonFormat3 (User) ...). Я искал версию кода, в которой маршалинг будет происходит автоматически в блоке handle_with {} - person Julias; 13.10.2015
comment
он делает то же самое - да, верно; он просто более пригоден для повторного использования. Я искал версию кода, где - я не понимаю, что вы здесь имеете в виду. Дайте мне знать, если я смогу уточнить ответ для вас. - person Rich; 13.10.2015
comment
Я видел подход с Json4sSupport и определение маршрута, например: pathPrefix (register) {pathEnd {post {entity (as [Register]) {ru = ›requestContext =› ... В этом подходе преобразование произошло в пределах --as - оператор, и не было необходимости определять jsonFormat1 (...) Но я не могу найти способ сделать это с помощью handleWith - person Julias; 13.10.2015
comment
В этом подходе преобразование происходило с помощью оператора --as--, и не было необходимости определять jsonFormat1 (...) - да, потому что Json4sSupport определяет неявный Marshaller[T, String] для ВСЕХ типов T. Вы можете сделать то же самое для Джексона или просто использовать Json4s, если это соответствует вашим потребностям. Тот же маршаллер можно использовать с handleWith. - person Rich; 13.10.2015