-
Notifications
You must be signed in to change notification settings - Fork 406
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
finatra-http: Simplify ExceptionMapper configuration and usage
Problem `ExceptionMapper` configuration and usage is more cumbersome than it should be. We created a specialized `ExceptionMapper` in the form of the `DefaultExceptionMapper` which was meant to be invoked as a backstop for HTTP exception handling but how you replace this default and/or other default mappers like the JsonParseExceptionMapper or CaseClassExceptionMapper is not ideal as overriding the default (which is internal to the framework) or the other mappers (which we also want to be internal to the framework) is currently tied into the binding of the `DefaultExceptionMapper` to the `FinatraDefaultExceptionMapper` in the `ExceptionMapperModule`. If users want to just swap out the configuration of these two additional `ExceptionMapper`s it is difficult as they have to swap the entire `ExceptionMapperModule` by overriding the `exceptionMapperModule` in the `HttpServer`. Further complicating the issue is that the narrow visbility of the `FinatraDefaultExceptionMapper` means that users cannot easily re-use it as the default when replacing the entire `ExceptionMapperModule`, so you either play package visibility games or duplicate a version. Neither are ideal usage patterns. Solution We are dropping the need for a specialized `DefaultExceptionMapper` (which was simply an `ExceptionMapper[Throwable]`). Instead we now allow the configuration of mappers in the `ExceptionManager` to be much more flexible. Previously, the framework tried to prevent a user from registering a mapper over a given exception type multiple times and specialized a "default" `ExceptionMapper` to invoke on an exception type of `Throwable`. The `ExceptionManager` will now accept any mapper. If a mapper is added over a type already added, the previous mapper will be overwritten. The last registered mapper for an exception type wins. The framework adds three mappers to the manager by default. If a user wants to swap out any of these defaults they simply need add their own mapper to the manager for the exception type to map. E.g., by default the framework will add: `Throwable` -> com.twitter.finatra.http.internal.exceptions.ThrowableExceptionMapper `JsonParseException` -> com.twitter.finatra.http.internal.exceptions.json.JsonParseExceptionMapper `CaseClassMappingException` -> com.twitter.finatra.http.internal.exceptions.json.CaseClassExceptionMapper The manager walks the exception type hierarchy starting at the given exceptiontype and moving up the inheritence chain until it finds mapper configured for the type. In this manner an `ExceptionMapper[Throwable]` will be the last mapper invoked and performs as the "default". Thus, to change the "default" mapper, simply adding a new mapper over the `Throwable` type will suffice, i.e., `ExceptionMapper[Throwable]` to the `ExceptionManager`. There are multiple ways to add a mapper. Either through the HttpRouter: ``` override def configureHttp(router: HttpRouter): Unit = { router .exceptionMapper[MyDefaultExceptionMapper] ... } ``` Or in a module which is then added to the Server, e.g., ``` object MyExceptionMapperModule extends TwitterModule { override def singletonStartup(injector: Injector): Unit = { val manager = injector.instance[ExceptionManager] manager.add[MyDefaultExceptionMapper] manager.add[OtherExceptionMapper] } } ``` ``` override val modules = Seq( MyExceptionMapperModule, ...) ``` This also means we can simplify the `HttpServer` as we no longer need to expose any "framework" module for overridding the default `ExceptionMappers`. So the "def exceptionMapperModule" has also been removed. Result Users will no longer need provide an entire `ExceptionMapperModule` just to configure a custom JsonParseExceptionMapper or CaseClassExceptionMapper. Instead users can just add their own mapper for the exception type directly to the `ExceptionManager` and any other configure mapper will be replaced (including the framework defaults). RB_ID=868614 TBR=true
- Loading branch information
Showing
21 changed files
with
258 additions
and
121 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 2 additions & 1 deletion
3
http/src/main/scala/com/twitter/finatra/http/exceptions/DefaultExceptionMapper.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
package com.twitter.finatra.http.exceptions | ||
|
||
trait DefaultExceptionMapper extends ExceptionMapper[Throwable] | ||
@deprecated("Specially typing a default exception mapper is no longer necessary. Extend ExceptionMapper[Throwable] directly.", "2016-09-07") | ||
trait DefaultExceptionMapper extends ExceptionMapper[Throwable] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
http/src/main/scala/com/twitter/finatra/http/exceptions/ExceptionMapperCollection.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.twitter.finatra.http.exceptions | ||
|
||
import scala.collection.mutable.ArrayBuffer | ||
|
||
/** | ||
* Represents a collection of [[com.twitter.finatra.http.exceptions.ExceptionMapper]]s | ||
* which is a Traversable[Manifest[ExceptionMapper[_\]\]\]. | ||
*/ | ||
class ExceptionMapperCollection extends Traversable[Manifest[ExceptionMapper[_]]] { | ||
|
||
private[this] val manifests = ArrayBuffer[Manifest[ExceptionMapper[_]]]() | ||
|
||
/** | ||
* Add a [[com.twitter.finatra.http.exceptions.ExceptionMapper]] by type [[T]] | ||
* @tparam T - ExceptionMapper type T which should subclass [[com.twitter.finatra.http.exceptions.ExceptionMapper]] | ||
*/ | ||
def add[T <: ExceptionMapper[_]: Manifest]: Unit = { | ||
val m: Manifest[T] = manifest[T] | ||
manifests += m.asInstanceOf[Manifest[ExceptionMapper[_]]] | ||
} | ||
|
||
override def foreach[U](f: (Manifest[ExceptionMapper[_]]) => U): Unit = manifests.foreach(f) | ||
|
||
override def seq: Traversable[Manifest[ExceptionMapper[_]]] = manifests.seq | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.