Я пытаюсь создать чтение и запись play-json для AST, который в основном выглядит так
abstract sealed trait Rule[A] {
def roomId: Option[Long] = None
def valid(in: A): Boolean
}
abstract sealed trait ValueRule[A, B] extends Rule[A] {
def value: B
}
abstract sealed trait NoValueRule[A] extends Rule[A]
case class OnlyDuringWorkHours(override val roomId: Option[Long] = None) extends NoValueRule[((ResStart, ResEnd), Center)] {
override def valid(in: ((ResStart, ResEnd), Center)): Boolean = true
}
case class MaxLeadTime(override val roomId: Option[Long] = None, override val value: Int) extends ValueRule[ResStart, Int] {
override def valid(in: ResStart): Boolean = true
}
case class MaxDuration(override val roomId: Option[Long] = None, override val value: String) extends ValueRule[(ResStart, ResEnd), String] {
override def valid(in: (ResStart, ResEnd)): Boolean = true
}
case class Rules(centerId: Long, ruleList: Seq[Rule[_]])
моя попытка сделать это выглядит так
object Rule {
implicit def ruleReads[R, V](implicit rReads: Reads[R], vReads: Reads[V] = null): Reads[Rule[R]] = {
val theVRead = Option(vReads)
val nvr = ???
if (Option(theVRead).isDefined) {
val vr = ???
__.read[ValueRule[R, V]](vr).map(x => x.asInstanceOf[Rule[R]]).orElse(__.read[NoValueRule[R]](nvr).map(x => x.asInstanceOf[Rule[R]]))
} else {
__.read[NoValueRule[R]](nvr).map(x => x.asInstanceOf[Rule[R]])
}
}
implicit def ruleWrites[R, V](implicit rWrites: Writes[R], vWrites: Writes[V] = null): Writes[Rule[R]] = Writes[Rule[R]]{
case nv: NoValueRule[R] => Json.writes[NoValueRule[R]].writes(nv)
case v: ValueRule[R, V] => Json.writes[ValueRule[R, V]].writes(v)
}
}
object ValueRule {
implicit def valueRuleReads[R, V](implicit rReads: Reads[R], vReads: Reads[V]): Reads[ValueRule[R, V]] = {
val mlt = Json.reads[MaxLeadTime]
val md = Json.reads[MaxDuration]
__.read[MaxDuration](md).map(x => x.asInstanceOf[ValueRule[R, V]])
.orElse(
__.read[MaxLeadTime](mlt).map(x => x.asInstanceOf[ValueRule[R, V]])
)
}
implicit def valueRuleWrites[R, V](implicit rWrites: Writes[R], vWrites: Writes[V]): Writes[ValueRule[R, V]] = Writes[ValueRule[R, V]]{
case mlt: MaxLeadTime => Json.writes[MaxLeadTime].writes(mlt)
case md: MaxDuration => Json.writes[MaxDuration].writes(md)
}
}
object NoValueRule {
implicit def noValueRuleReads[R](implicit rReads: Reads[R]): Reads[NoValueRule[R]] = {
val odwh = Json.reads[OnlyDuringWorkHours]
__.read[OnlyDuringWorkHours](odwh).map(x => x.asInstanceOf[NoValueRule[R]])
}
implicit def noValueRuleWrites[R](implicit rWrites: Writes[R]): Writes[NoValueRule[R]] = Writes[NoValueRule[R]]{
case odwh: OnlyDuringWorkHours => Json.writes[OnlyDuringWorkHours].writes(odwh)
}
}
object OnlyDuringWorkHours {
implicit val format: Format[OnlyDuringWorkHours] = Json.format[OnlyDuringWorkHours]
}
object MaxLeadTime {
implicit val format: Format[MaxLeadTime] = Json.format[MaxLeadTime]
}
object MaxDuration {
implicit val format: Format[MaxDuration] = Json.format[MaxDuration]
}
object Rules {
import play.api.libs.json.Reads._
import play.api.libs.functional.syntax._
implicit val rulesReads: Reads[Rules] = (
(JsPath \ "centerId").read[Long] and
(JsPath \ "ruleList").read[Seq[Rule]]
)(Rules.apply _)
implicit val rulesWrites: Writes[Rules] = (
(JsPath \ "centerId").write[Long] and
???
)(unlift(Rules.unapply))
implicit val format: Format[Rules] = Format(rulesReads, rulesWrites)
}
Это оставляет меня с двумя проблемами.
Во-первых, если я подключу выражения, которые я считаю правильными, в Rule.ruleReads для двух экземпляров ???
, Json.reads[NoValueRule[R]]
и Json.reads[ValueRule[R, V]]
соответственно, я получаю следующую ошибку компиляции.
cmd16.sc:8: type mismatch;
found : play.api.libs.json.JsResult[Helper.this.OnlyDuringWorkHours]
required: play.api.libs.json.JsResult[Helper.this.NoValueRule[R]]
val nvr = Json.reads[NoValueRule[R]]
^cmd16.sc:11: type mismatch;
found : play.api.libs.json.JsResult[Helper.this.MaxLeadTime]
required: play.api.libs.json.JsResult[Helper.this.ValueRule[R,V]]
val vr = Json.reads[ValueRule[R, V]]
^
во-вторых, если я оставлю ???
, чтобы эта часть скомпилировала его, а затем не смогла скомпилировать объект правил с
cmd17.sc:71: No Json deserializer found for type Seq[cmd17Wrapper.this.cmd16.wrapper.Rule]. Try to implement an implicit Reads or Format for this type.
(JsPath \ "ruleList").read[Seq[Rule]]
^
Я могу заставить правила читать/записывать формат и получать очень похожую ошибку
Я думаю, что проблема с 2 заключается в разнице между Правилами, содержащими Seq[Rule[_]]
, и моим определением неявного чтения, которое должно охватывать любое конкретное правило, но не правило, которое может быть чем угодно.
Любые идеи, как я могу заставить это работать? Я чувствую, что это должно быть возможно, но, возможно, это не так.
Rule
очень похожи по форме, поэтому очевидное решение — добавить в JSON некоторый явный дискриминатор типов. Это нормально? Или вы действительно хотите различать фактические типы по тонким различиям в JSON? - person SergGr   schedule 03.01.2018