All Downloads are FREE. Search and download functionalities are using the official Maven repository.

renesca.json.protocols.ParameterProtocol.scala Maven / Gradle / Ivy

package renesca.json.protocols

import renesca.parameter._
import spray.json._

object ParameterProtocol extends DefaultJsonProtocol {

  implicit object JsonPropertyKeyFormat extends RootJsonFormat[PropertyKey] {
    override def write(pv: PropertyKey) = JsString(pv.name)

    override def read(value: JsValue): PropertyKey = value match {
      case JsString(str) => PropertyKey(str)
      case json          => deserializationError(s"Can not deserialize property key of type $json")
    }
  }

  implicit object JsonPrimitivePropertyValueFormat extends RootJsonFormat[PrimitivePropertyValue] {
    override def write(pv: PrimitivePropertyValue) = pv match {
      case LongPropertyValue(value)    => JsNumber(value)
      case DoublePropertyValue(value)  => JsNumber(value)
      case StringPropertyValue(value)  => JsString(value)
      case BooleanPropertyValue(value) => JsBoolean(value)
      case NullPropertyValue           => JsNull
    }

    override def read(value: JsValue) = value match {
      case JsString(str)                     => StringPropertyValue(str)
      case JsNumber(num) if num.isValidLong  => LongPropertyValue(num.toLong)
      case JsNumber(num) if !num.isValidLong => DoublePropertyValue(num.toDouble)
      case JsBoolean(bool)                   => BooleanPropertyValue(bool)
      case JsNull                            => NullPropertyValue
      case json                              => deserializationError(s"Can not deserialize property value of type $json")
    }
  }

  implicit object JsonPropertyValueFormat extends RootJsonFormat[PropertyValue] {
    override def write(pv: PropertyValue) = pv match {
      case x: PrimitivePropertyValue => x.toJson
      case apv: ArrayPropertyValue   => apv.elements.toJson
    }

    override def read(value: JsValue) = value match {
      case x@(_: JsString | _: JsNumber | _: JsBoolean | JsNull) => x.convertTo[PrimitivePropertyValue]
      case jsArray: JsArray                                      =>
        try {
          val elements = jsArray.convertTo[Seq[PrimitivePropertyValue]]
          elements.head match {
            case x: LongPropertyValue    => LongArrayPropertyValue(elements.asInstanceOf[Seq[LongPropertyValue]]: _*)
            case x: DoublePropertyValue  => DoubleArrayPropertyValue(elements.asInstanceOf[Seq[DoublePropertyValue]]: _*)
            case x: StringPropertyValue  => StringArrayPropertyValue(elements.asInstanceOf[Seq[StringPropertyValue]]: _*)
            case x: BooleanPropertyValue => BooleanArrayPropertyValue(elements.asInstanceOf[Seq[BooleanPropertyValue]]: _*)
            case NullPropertyValue       => deserializationError(s"Can not deserialize null-arrays: $jsArray")
          }
        } catch {
          case e: ClassCastException =>
            deserializationError(s"Can not deserialize property array of type $jsArray")
        }
      case json                                                  => deserializationError(s"Can not deserialize property value of type $json")
    }
  }

  implicit object JsonArrayParameterValueFormat extends RootJsonFormat[ArrayParameterValue] {

    override def write(apv: ArrayParameterValue) = apv match {
      case ArrayParameterValue(elements) => JsArray(elements map (_.toJson): _*)
    }

    override def read(value: JsValue) = value match {
      case JsArray(elements) => ArrayParameterValue(elements.toArray map (_.convertTo[ParameterValue]))
      case json              => deserializationError(s"Can not deserialize ArrayParameterValue from: $json")
    }
  }

  implicit object JsonParameterValueFormat extends RootJsonFormat[ParameterValue] {

    // Parameters can be arbitrarily nested maps and arrays
    // therefore we need to call write and read recursively
    override def write(pv: ParameterValue) = pv match {
      case pv: PropertyValue                        => pv.toJson
      case arrayParameterValue: ArrayParameterValue => arrayParameterValue.toJson
      case MapParameterValue(keyValuePairs)         => JsObject(keyValuePairs.map { case (key, value) => (key.name, write(value)) })
    }

    override def read(jsvalue: JsValue) = jsvalue match {
      case x@(_: JsString | _: JsNumber | _: JsBoolean | JsNull) => x.convertTo[PropertyValue]
      case jsArray: JsArray                                      => jsArray.convertTo[ArrayParameterValue]
      case JsObject(keyValuePairs)                               => MapParameterValue(keyValuePairs.map { case (key, value) => (PropertyKey(key), read(value)) })
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy