package play.api.libs.json
import scala.collection._
import play.api.data.validation.ValidationError
case class JsResultException(errors: Seq[(JsPath, Seq[ValidationError])]) extends RuntimeException("JsResultException(errors:%s)".format(errors))
sealed trait JsValue extends JsReadable {
override def toString = Json.stringify(this)
def validate[A](implicit rds: Reads[A]) = rds.reads(this)
}
object JsValue {
import scala.language.implicitConversions
implicit def jsValueToJsLookup(value: JsValue): JsLookup = JsLookup(JsDefined(value))
}
case object JsNull extends JsValue
case class JsBoolean(value: Boolean) extends JsValue
case class JsNumber(value: BigDecimal) extends JsValue
case class JsString(value: String) extends JsValue
case class JsArray(value: Seq[JsValue] = List()) extends JsValue {
def ++(other: JsArray): JsArray =
JsArray(value ++ other.value)
def :+(el: JsValue): JsArray = JsArray(value :+ el)
def append(el: JsValue): JsArray = this.:+(el)
def +:(el: JsValue): JsArray = JsArray(el +: value)
def prepend(el: JsValue): JsArray = this.+:(el)
}
case class JsObject(private val underlying: Map[String, JsValue]) extends JsValue {
lazy val fields: Seq[(String, JsValue)] = underlying.toSeq
lazy val value: Map[String, JsValue] = underlying match {
case m: immutable.Map[String, JsValue] => m
case m => m.toMap
}
def fieldSet: Set[(String, JsValue)] = fields.toSet
def keys: Set[String] = underlying.keySet
def values: Iterable[JsValue] = underlying.values
def ++(other: JsObject): JsObject = JsObject(underlying ++ other.underlying)
def -(otherField: String): JsObject = JsObject(underlying - otherField)
def +(otherField: (String, JsValue)): JsObject = JsObject(underlying + otherField)
def deepMerge(other: JsObject): JsObject = {
def merge(existingObject: JsObject, otherObject: JsObject): JsObject = {
val result = existingObject.underlying ++ otherObject.underlying.map {
case (otherKey, otherValue) =>
val maybeExistingValue = existingObject.underlying.get(otherKey)
val newValue = (maybeExistingValue, otherValue) match {
case (Some(e: JsObject), o: JsObject) => merge(e, o)
case (Some(e: JsArray), o: JsArray) => e ++ o
case _ => otherValue
}
otherKey -> newValue
}
JsObject(result)
}
merge(this, other)
}
override def equals(other: Any): Boolean = other match {
case that: JsObject => (that canEqual this) && fieldSet == that.fieldSet
case _ => false
}
def canEqual(other: Any): Boolean = other.isInstanceOf[JsObject]
override def hashCode: Int = fieldSet.hashCode()
}
object JsObject {
def apply(fields: Seq[(String, JsValue)]): JsObject = new JsObject(mutable.LinkedHashMap(fields: _*))
}