override def read()

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


    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
      }

      kind match {
        case Exec.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")
          }
          SequenceExec(comp)

        case Exec.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 (codeOpt: Option[Attachment[String]], binary) = obj.fields.get("code") match {
            case None                                => (None, false)
            case Some(JsString(i)) if i.trim.isEmpty => (None, false)
            case Some(code)                          => (Some(attFmt[String].read(code)), isBinary(code, obj))
          }
          val native = execManifests.skipDockerPull(image)
          BlackBoxExec(image, codeOpt, 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(Messages.invalidRuntimeError(kind, runtimes))
          }

          manifest.attached
            .map { _ =>
              // java actions once stored the attachment in "jar" instead of "code"
              val code = obj.fields.get("code").orElse(obj.fields.get("jar")).getOrElse {
                throw new DeserializationException(
                  s"'code' must be a string or attachment object defined in 'exec' for '$kind' actions")
              }

              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
              }

              CodeExecAsAttachment(manifest, attFmt[String].read(code), main, isBinary(code, obj))
            }
            .getOrElse {
              val code: String = obj.fields.get("code") match {
                case Some(JsString(c)) => c
                case _ =>
                  throw new DeserializationException(s"'code' must be a string defined in 'exec' for '$kind' actions")
              }
              CodeExecAsString(manifest, code, optMainField)
            }
      }
    }