override def read()

in common/scala/src/main/scala/org/apache/openwhisk/core/entity/Exec.scala [414:476]


    override def read(v: JsValue) = {
      require(v != null)

      val obj = v.asJsObject

      val kind = obj.fields.get("kind") match {
        case Some(JsString(k)) => k.trim.toLowerCase
        case _                 => throw new DeserializationException("'kind' must be a string defined in 'exec'")
      }

      lazy val optMainField: Option[String] = obj.fields.get("main") match {
        case Some(JsString(m)) => Some(m)
        case Some(_) =>
          throw new DeserializationException(s"if defined, 'main' be a string in 'exec' for '$kind' actions")
        case None => None
      }

      lazy val binary: Boolean = obj.fields.get("binary") match {
        case Some(JsBoolean(b)) => b
        case _                  => throw new DeserializationException("'binary' must be a boolean defined in 'exec'")
      }

      kind match {
        case ExecMetaDataBase.SEQUENCE =>
          val comp: Vector[FullyQualifiedEntityName] = obj.fields.get("components") match {
            case Some(JsArray(components)) => components map (FullyQualifiedEntityName.serdes.read(_))
            case Some(_)                   => throw new DeserializationException(s"'components' must be an array")
            case None                      => throw new DeserializationException(s"'components' must be defined for sequence kind")
          }
          SequenceExecMetaData(comp)

        case ExecMetaDataBase.BLACKBOX =>
          val image: ImageName = obj.fields.get("image") match {
            case Some(JsString(i)) => ImageName.fromString(i).get // throws deserialization exception on failure
            case _ =>
              throw new DeserializationException(
                s"'image' must be a string defined in 'exec' for '${Exec.BLACKBOX}' actions")
          }
          val native = execManifests.skipDockerPull(image)
          BlackBoxExecMetaData(image, optMainField, native, binary)

        case _ =>
          // map "default" virtual runtime versions to the currently blessed actual runtime version
          val manifest = execManifests.resolveDefaultRuntime(kind) match {
            case Some(k) => k
            case None    => throw new DeserializationException(s"kind '$kind' not in $runtimes")
          }

          manifest.attached
            .map { a =>
              val main = optMainField.orElse {
                if (manifest.requireMain.exists(identity)) {
                  throw new DeserializationException(s"'main' must be a string defined in 'exec' for '$kind' actions")
                } else None
              }

              CodeExecMetaDataAsAttachment(manifest, binary, main)
            }
            .getOrElse {
              CodeExecMetaDataAsString(manifest, binary, optMainField)
            }
      }
    }