Как я могу десериализовать из JSON с помощью Scala, используя * не-case* классы?
Я пишу приложение Scala, которое нужно сериализовать и десериализовать из JSON. Некоторые из объектов JSON имеют более 22 полей, поэтому я не могу использовать case-классы (и я также не могу изменить формат). Все библиотеки JSON Scala, которые мне удалось найти, работают (легко) только с классами case, а не с обычными классами.
Учитывая это, каков самый простой способ десериализации большого объекта JSON (с более чем 22 полями) в не-case-классе Scala? Это не обязательно должно быть полностью автоматически, но в идеале я ищу что-то менее болезненное, чем десериализация карты [String, Any] и выполнение всего вручную.
3 ответа
Обновление: К счастью, теперь можно делать то, что я хотел, используя Json4s и Джексона, используя полевой сериализатор, следующим образом:
implicit val formats = DefaultFormats + FieldSerializer[MyNonCaseClass]()
val myNonCaseClassObject = Serialization.read[MyNonCaseClass](jsonString)
Как указано ниже, вот более полный пример:
import org.json4s.jackson.Serialization
import org.json4s._
import scala.util.Try
object JSONUtil {
implicit val formats = DefaultFormats + FieldSerializer[MyNonCaseClass]() + FieldSerializer[MyOtherNonCaseClass](ignore("someUnwantedFieldName") orElse ignore("anotherFieldToIgnore")) + ...
def toJSON(objectToWrite: AnyRef): String = Serialization.write(objectToWrite)
def fromJSONOption[T](jsonString: String)(implicit mf: Manifest[T]): Option[T] = Try(Serialization.read(jsonString)).toOption
}
Тогда использование это:
val jsonString = JSONUtil.toJSON(myObject)
val myNewObject: Option[MyClass] = JSONUtil.fromJSONOption[MyClass](aJsonString)
Вам нужен FieldSerializer для каждого не относящегося к делу класса, который вы хотите сериализовать. Кроме того, при определении ваших классов все, что может отсутствовать в JSON, должно быть определено как Option.
SBT:
"org.json4s" %% "json4s-jackson" % "3.2.6"
Это возможно сделать без использования тематических классов, используя библиотеку The Play JSON с обобщениями
Как я пил кофе и ничего не делал. Я позволил себе написать пример для вас. Полное решение заключается в следующем:
Прежде всего, это ваш класс:
import play.api.libs.json._
import play.api.libs.json.Json._
class TestJSON(
val field1: String,
val field2: String,
val field3: String,
val field4: String,
val field5: String,
val field6: String,
val field7: String,
val field8: String,
val field9: String,
val field10: String,
val field11: String,
val field12: String,
val field13: String,
val field14: String,
val field15: String,
val field16: String,
val field17: String,
val field18: String,
val field19: String,
val field20: String,
val field21: String,
val field22: String,
val field23: String) {
}
object TestJSON {
//
// JSON BINDING/UNBINDING
//
implicit def modalityReads: Reads[TestJSON] = new Reads[TestJSON] {
def reads(json: JsValue): TestJSON =
new TestJSON(
field1 = (json \ "field1").as[String],
field2 = (json \ "field2").as[String],
field3 = (json \ "field3").as[String],
field4 = (json \ "field4").as[String],
field5 = (json \ "field5").as[String],
field6 = (json \ "field6").as[String],
field7 = (json \ "field7").as[String],
field8 = (json \ "field8").as[String],
field9 = (json \ "field9").as[String],
field10 = (json \ "field10").as[String],
field11 = (json \ "field11").as[String],
field12 = (json \ "field12").as[String],
field13 = (json \ "field13").as[String],
field14 = (json \ "field14").as[String],
field15 = (json \ "field15").as[String],
field16 = (json \ "field16").as[String],
field17 = (json \ "field17").as[String],
field18 = (json \ "field18").as[String],
field19 = (json \ "field19").as[String],
field20 = (json \ "field20").as[String],
field21 = (json \ "field21").as[String],
field22 = (json \ "field22").as[String],
field23 = (json \ "field22").as[String])
}
implicit def modalityWrites: Writes[TestJSON] = new Writes[TestJSON] {
def writes(ts: TestJSON) = JsObject(Seq(
"field1" -> JsString(ts.field1),
"field2" -> JsString(ts.field2),
"field3" -> JsString(ts.field3),
"field4" -> JsString(ts.field4),
"field5" -> JsString(ts.field5),
"field6" -> JsString(ts.field6),
"field7" -> JsString(ts.field7),
"field8" -> JsString(ts.field8),
"field9" -> JsString(ts.field9),
"field10" -> JsString(ts.field10),
"field11" -> JsString(ts.field11),
"field12" -> JsString(ts.field12),
"field13" -> JsString(ts.field13),
"field14" -> JsString(ts.field14),
"field15" -> JsString(ts.field15),
"field16" -> JsString(ts.field16),
"field17" -> JsString(ts.field17),
"field18" -> JsString(ts.field18),
"field19" -> JsString(ts.field19),
"field20" -> JsString(ts.field20),
"field21" -> JsString(ts.field21),
"field22" -> JsString(ts.field22),
"field23" -> JsString(ts.field23)))
}
}
Ваш контроллер должен выглядеть так:
import play.api._
import play.api.mvc._
import play.api.libs.json.Json._
import play.api.Play.current
import models.TestJSON
object Application extends Controller {
def getJson = Action {
implicit request =>
Ok(
toJson(
Seq(
toJson(
new TestJSON(
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
"13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23")),
toJson(new TestJSON(
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
"13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23")))))
}
}
Ваш файл маршрута (просто направьте действие):
GET /getJson controllers.Application.getJson
И вот, момент истины...
curl localhost:9000/getJson
[{"field1":"1","field2":"2","field3":"3","field4":"4","field5":"5","field6":"6",
"field7":"7","field8":"8","field9":"9","field10":"10","field11":"11","field12":"
12","field13":"13","field14":"14","field15":"15","field16":"16","field17":"17","
field18":"18","field19":"19","field20":"20","field21":"21","field22":"22","field
23":"23"},{"field1":"1","field2":"2","field3":"3","field4":"4","field5":"5","fie
ld6":"6","field7":"7","field8":"8","field9":"9","field10":"10","field11":"11","f
ield12":"12","field13":"13","field14":"14","field15":"15","field16":"16","field1
7":"17","field18":"18","field19":"19","field20":"20","field21":"21","field22":"2
2","field23":"23"}]
Это должно работать и наоборот. В настоящее время я работаю над проектом, который использует его для сборки и разборки огромных деревьев, поэтому он должен работать для вас. Дай мне знать.
Ура!
PS: не волнуйтесь, мне потребовалось около 10 минут, чтобы сгенерировать код. Я только что сопоставил List.range(1,24) и "передал" его для печати кода.
Проверьте Lift JSON API.
Ключ в том, что все, что анализируется, возвращается как подкласс JValue
, Объект как
{
"a": [1, 2],
"b": "hello"
}
Будет проанализирован как
JObject(List(
JField("a", JArray(List(JInt(1), JInt(2)))),
JField("b", JString("hello"))
))
Lift API предоставляет несколько полезных методов, таких как \
что позволит вам получить доступ к таким вещам, как Map
, Там также есть extractOpt[A]
метод, который будет стараться превратить проанализированный JSON в любой A
ты хочешь. Поиграйте с ними, чтобы почувствовать это.