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!"))