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]])
)
}
}
}