codahale/dropwizard — pull request #106 by nicktelford (2012-06-01 10:16:29+00:00)
Title: Enable mix-in Bundles for ScalaServices

It'd be nice to be able to mix-in `Bundles` to `ScalaServices`. Such Bundles would use a self-type annotation to define their requirements on the `Service` implementation:

```scala
trait GraphiteReportingBundle {
self: ScalaService[_ <: GraphiteReportingConfiguration] =>

self.addBundle(new GraphiteReportingBundle)

class GraphiteReportingBundle
extends ConfiguredBundle[GraphiteReportingConfiguration] {

def initialize(c: GraphiteReportingConfiguration, e: Environment) {
GraphiteReporter.enable(/*...*/)
env.addHealthCheck(new GraphiteHealthCheck(/*...*/)
}
}
}
```

Unfortunately, this fails at runtime with:

IllegalAccessError: tried to access method AbstractService.addBundle(LConfiguredBundle;)V from class GraphiteReportingBundle$class

Because `AbstractService.addBundle` is a protected method and traits can only access the public methods on their self-type.

To address this, I've added two public proxy methods to `ScalaService`:

```scala
def withBundle(bundle: Bundle)
def withBundle(bundle: ConfiguredBundle[_ >: T])
```

These methods allow Service mix-ins to add the bundle like this:

```scala
trait GraphiteReportingBundle {
self: ScalaService[_ <: GraphiteReportingConfiguration] =>

self.withBundle(new GraphiteReportingBundle)

/* snip */
}
```

Since these proxies are only added to `ScalaService`, it doesn't leak in to Java projects that don't support/require/want mix-in composition of bundles.