def builder()

in http-core/src/main/scala/com/twitter/finatra/http/marshalling/MessageBodyManager.scala [36:202]


  def builder(
    injector: Injector,
    defaultMessageBodyReader: DefaultMessageBodyReader,
    defaultMessageBodyWriter: DefaultMessageBodyWriter
  ): Builder = Builder(
    injector = injector,
    defaultMessageBodyReader = defaultMessageBodyReader,
    defaultMessageBodyWriter = defaultMessageBodyWriter
  )

  /**
   * Used to create a [[MessageBodyManager]] instance. Message body components can be
   * registered on the builder which backs the created [[MessageBodyManager]].
   *
   * Components that specify how to parse an incoming Finagle HTTP request body into a model
   * object [[MessageBodyReader]] and how to render a given type as a response [[MessageBodyWriter]].
   *
   *
   * @param injector the configured [[com.twitter.inject.Injector]] for the server.
   * @param defaultMessageBodyReader a default message body reader implementation.
   * @param defaultMessageBodyWriter a default message body writer implementation.
   */
  case class Builder private[marshalling] (
    injector: Injector,
    defaultMessageBodyReader: DefaultMessageBodyReader,
    defaultMessageBodyWriter: DefaultMessageBodyWriter,
    classTypeToReader: Map[Type, MessageBodyReader[Any]] = Map.empty,
    classTypeToWriter: Map[Type, MessageBodyWriter[Any]] = Map.empty,
    annotationTypeToWriter: Map[Type, MessageBodyWriter[Any]] = Map.empty) {

    /* Public */

    /**
     * Set the injector the [[MessageBodyManager]] uses to read from the object graph.
     */
    def withInjector(injector: Injector): Builder =
      this.copy(injector = injector)

    /**
     * Set the [[DefaultMessageBodyReader]] used when a reader is not found for a requested type.
     */
    def withDefaultMessageBodyReader(reader: DefaultMessageBodyReader): Builder =
      this.copy(defaultMessageBodyReader = reader)

    /**
     * Set the [[DefaultMessageBodyWriter]] used when a writer is not found for a requested type.
     */
    def withDefaultMessageBodyWriter(writer: DefaultMessageBodyWriter): Builder =
      this.copy(defaultMessageBodyWriter = writer)

    /**
     * Register a [[MessageBodyReader]] or [[MessageBodyWriter]] to its parameterized type.
     * E.g., a `MessageBodyReader[Foo]` will register the given reader for the `Foo` type.
     * @tparam Component the [[MessageBodyComponent]] to register.
     */
    def add[Component <: MessageBodyComponent: ClassTag](
    )(
      implicit tt: TypeTag[Component]
    ): Builder = {
      val componentTypeClazz: Class[_] =
        if (MessageBodyManager.isAssignableFrom[Component](classOf[MessageBodyReader[_]])) {
          classOf[MessageBodyReader[_]]
        } else {
          classOf[MessageBodyWriter[_]]
        }
      add[Component](
        TypeUtils.singleTypeParam(typeLiteral[Component].getSupertype(componentTypeClazz).getType))
    }

    /**
     * Register a [[MessageBodyReader]] or [[MessageBodyWriter]] to an explicitly given type.
     * E.g., given a `MessageBodyReader[Car]` and a type of `Audi` the `MessageBodyReader[Car]`
     * will be registered to the `Audi` type. This is useful when you want to register subtypes
     * to a reader/writer of their parent type.
     * @tparam Component the [[MessageBodyComponent]] to register. An instance of the component
     *                   will be obtained from the [[injector]].
     * @tparam T the type to associate to the registered [[MessageBodyComponent]].
     */
    def addExplicit[Component <: MessageBodyComponent: TypeTag, T: TypeTag](): Builder = {
      add[Component](typeLiteral[T].getType)(TypeUtils.asManifest[Component])
    }

    /**
     * Register a [[MessageBodyWriter]] to a given [[Annotation]], [[A]].
     * @tparam A the [[Annotation]] type to register against the given [[MessageBodyWriter]] type.
     * @tparam Writer the [[MessageBodyWriter]] type to associate to the given [[Annotation]]. An
     *                instance of the [[MessageBodyWriter]] will be obtained from the [[injector]].
     */
    def addWriterByAnnotation[A <: Annotation: Manifest, Writer <: MessageBodyWriter[_]: Manifest](
    ): Builder = {
      val messageBodyWriter = injector.instance[Writer]
      val annotation = manifest[A].runtimeClass.asInstanceOf[Class[A]]
      val requiredAnnotationClazz = classOf[MessageBodyWriterAnnotation]
      assert(
        Annotations.isAnnotationPresent[MessageBodyWriterAnnotation, A],
        s"The annotation: ${annotation.getSimpleName} is not annotated with the required ${requiredAnnotationClazz.getName} annotation."
      )
      this.copy(
        annotationTypeToWriter = annotationTypeToWriter + (annotation -> messageBodyWriter
          .asInstanceOf[MessageBodyWriter[Any]])
      )
    }

    /**
     * Register a [[MessageBodyWriter]] to a given [[MessageBodyComponent]].
     * @tparam Component the [[MessageBodyComponent]] type to register against the given [[MessageBodyWriter]] type.
     * @tparam Writer the [[MessageBodyWriter]] type to associate to the given [[MessageBodyComponent]].
     *                An instance of the [[MessageBodyWriter]] will be obtained from the [[injector]]
     */
    def addWriterByComponentType[
      Component <: MessageBodyComponent: Manifest,
      Writer <: MessageBodyWriter[_]: Manifest
    ](
    ): Builder = {
      val messageBodyWriter = injector.instance[Writer]
      val componentType = manifest[Component].runtimeClass.asInstanceOf[Class[Component]]
      this.copy(
        classTypeToWriter = classTypeToWriter + (componentType -> messageBodyWriter
          .asInstanceOf[MessageBodyWriter[Any]])
      )
    }

    /**
     * Create the [[MessageBodyManager]].
     */
    def build(): MessageBodyManager = {
      new MessageBodyManager(
        injector,
        defaultMessageBodyReader,
        defaultMessageBodyWriter,
        classTypeToReader,
        classTypeToWriter,
        annotationTypeToWriter
      )
    }

    /* Private */

    /* The given `genericType` is the parameterized type of the
       reader or writer, e.g., `T` for `MessageBodyWriter[T]` */
    private[this] def add[Component: Manifest](genericType: Type): Builder = {
      genericType match {
        case _: ParameterizedTypeImpl =>
          throw new IllegalArgumentException(
            "Adding a message body component with parameterized types, e.g. Map[String, String] is not supported.")
        case _ =>
          val messageBodyComponent = injector.instance[Component]
          addComponent(messageBodyComponent, genericType)
      }
    }

    private[this] def addComponent(messageBodyComponent: Any, typeToReadOrWrite: Type): Builder = {
      messageBodyComponent match {
        case reader: MessageBodyReader[_] =>
          this.copy(
            classTypeToReader =
              classTypeToReader + (typeToReadOrWrite -> reader.asInstanceOf[MessageBodyReader[Any]])
          )
        case writer: MessageBodyWriter[_] =>
          this.copy(
            classTypeToWriter =
              classTypeToWriter + (typeToReadOrWrite -> writer.asInstanceOf[MessageBodyWriter[Any]])
          )
      }
    }

  }