JSON mappnig неожиданный случай

Раньше я пользовалась import com.fasterxml.jackson в моем приложении. Поскольку я использовал akka http, я хотел попробовать жить с Marshal/Unmarshal и spray.json.toJson.compactPrint, Без дополнительной упаковки (com.fasterxml.jackson) зависимость.

Но я застрял на простом случае

старый рабочий код:

...
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule

val obj: AnyRef = new Object()
val mapper = new ObjectMapper()
mapper.registerModule(DefaultScalaModule)

val json = mapper.writeValueAsString(obj)

новый код:

import spray.json._

val obj: AnyRef = new Object()
val json = obj.toJson.compactPrint

Это вызывает исключение

Не удается найти класс типов JsonWriter или JsonFormat для AnyRef на obj.toJson.compactPrint

Помогите, пожалуйста!

UPD:

это реальная часть кода - для лучшего понимания, что мне нужно, он работает хорошо. Картограф com.fasterxml.jackson не имеет ограничений для записи AnyRef в строку json

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule

object mapper {
  private val _mapper = new ObjectMapper()
  _mapper.registerModule(DefaultScalaModule)

  def get: ObjectMapper = _mapper
}

import akka.actor.{Actor, Props, ReceiveTimeout}
import akka.http.scaladsl.model.{ContentTypes, HttpEntity, HttpResponse}

object RequestHandler {
  def props(ctx: ImperativeRequestContext): Props = Props(new RequestHandler(ctx))
}

class RequestHandler(ctx: ImperativeRequestContext) extends Actor {

  import context._

  import concurrent.duration._

  setReceiveTimeout(30.second)

  def receive: Receive = {
    case ReceiveTimeout =>
      ctx.complete(HttpResponse(500, entity = "timeout"))
      stop(self)

    case x: AnyRef =>
      ctx.complete(HttpEntity(ContentTypes.`application/json`, mapper.get.writeValueAsString(x)))

      stop(self)
  }

}

1 ответ

Я не уверен, на что именно вы жалуетесь. Библиотека JSON Spray, как это обычно для библиотеки Scala, более безопасна, чем Джексон. в частности toJson работает на основе типа времени компиляции, а не типа времени выполнения. И, очевидно, нет безопасного способа превратить любой AnyRef (ака Object) в JSON, потому что за этой переменной может быть любой объект любого типа. Рассмотрим следующий пример:

val obj: AnyRef = new Thread()
val json = obj.toJson.compactPrint

Для распыления JSON этот код выглядит точно так же, как ваш пример. Очевидно, вы не можете написать Thread в JSON. Разница в том, что с Джексоном вы получите какую-то ошибку во время выполнения. С Spray JSON он даже не скомпилируется. Если вы используете определенные типы, которые можно безопасно преобразовать в JSON - Spray JSON подойдет вам.

Если вопрос заключается в том, что вы хотите иметь какой-то универсальный метод, который принимает аргументы, и в качестве одного из шагов выполняется преобразование в JSON, тогда вы должны использовать универсальные методы и ограничения для указания этого типа, как в:

def foo[T : JsonWriter](bar : T) = {
    //do something

    bar.toJson.compactPrint

    //do something more
}

Обновление: более реалистичный пример

Вот пример, который компилируется для меня и работает так, как я ожидал:

import spray.json._
import DefaultJsonProtocol._ 

case class Foo(i: Int)
implicit val fooFormat = jsonFormat1(Foo)

case class Bar(ii: Int, ss: String)
implicit val barFormat = jsonFormat2(Bar)

def printJson[T: JsonWriter](obj: T):Unit = {
  println(obj.toJson.compactPrint)
}

printJson(Foo(42))
printJson(Bar(123, "this works!"))
Другие вопросы по тегам