Неявно сгенерировать сериализатор и десериализатор классов case с помощью play-json

Я использую play-json для сопоставления Json с классами case или перечислениями. Я ищу умный способ неявного создания Formats, поскольку мой проект содержит много определений типов.


На данный момент я создал простую функцию для генерации Formats для Enums:

def formatEnum[E <: Enumeration](enum: E) = Format(Reads.enumNameReads(enum), Writes.enumNameWrites)

Но он принимает неявный аргумент, поэтому его нельзя использовать в качестве неявного преобразователя.


Я попытался сделать то же самое для case-классов:

implicit def caseFormat[A] = Json.format[A]

Но я получаю сообщение об ошибке «Не найдена функция unapply или unapplySeq», поскольку Json.format - это макрос, проверяющий структуру класса.

Затем я попытался создать свой макрос таким образом:

import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context

implicit def caseFormat[A](): Format[A] = macro impl[A]

def impl[A: c.WeakTypeTag](c: Context)(): c.Expr[Reads[A]] = {
    import c.universe._
    val TypeRef(pre, sym, args) = weakTypeTag[A].tpe
    val t = args.head
    val expr =  q"Json.format[$t]"
    c.Expr[Reads[A]](expr)
}

Но компилятор не находит неявное Format, хотя есть неявное def, которое должно генерировать значение.


Конечно, я могу просто определить многие неявные val, но я думаю, что есть более разумный способ сделать это.


person WalkerTR    schedule 26.11.2016    source источник
comment
Вы можете принять ответ, если он поможет?   -  person phantomastray    schedule 02.12.2016


Ответы (1)


Предполагая, что у вас много классов case, и вы хотите сериализовать их с помощью json на лету без необходимости писать play-json writer.

import play.api.libs.json._
import scala.reflect.runtime.{universe => ru}
implicit class writeutil[T: ru.TypeTag](i: T) {
    implicit val writer = Json.writes[T]

    def toJson() = Json.toJson(i)
}

def toInstance[T: ru.TypeTag](s: String): Option[T] = {
    implicit val reader = Json.reads[T]
    Json.fromJson[T](Json.parse(s)) match {
        case JsSuccess(r: T, path: JsPath) => Option(r)
        case e: JsError => None
    }
}

Оптимальной реализацией было бы повторное использование устройства чтения / записи путем кэширования и поиска. Вы также можете узнать больше о play-json.

Вы можете использовать это как:

case class Entity(a: String, b: Int)
val e = Entity("Stack", 0)

e.toJson()
person phantomastray    schedule 26.11.2016
comment
Не работает. Получить scala.ScalaReflectionException: type T is not a class - person Vladislav; 28.01.2018