To celebrate the release of Guice 2.0, I'd like to showcase my favourite parts of the new code. In this N-part series, I'll go deep into the implementation details to explain the clever and interesting code within the project. I'll focus on general techniques that you can use in your own applications.
Background: Getting sources
When you invoke methods on a Binder
(or invoke them indirectly, via AbstractModule
), Guice captures the caller's source. This is used to create javac-like error messages in the event of a configuration problem. For example, the following binding is illegal because Executor
is an interface without an implementation:
class BadModule extends AbstractModule {
protected void configure() {
bind(Executor.class);
}
}`</pre>When this faulty module is used to create an injector, Guice reports the problem with the source line where it occurred:
<pre>Exception in thread "main" com.google.inject.CreationException: Guice creation errors:
1) No implementation for java.util.concurrent.Executor was bound.
at com.publicobject.blog.Scratch$1.configure(Scratch.java:18)
1 error</pre>
To obtain the offending source line, Guice grabs a stacktrace using `new Throwable().getStackTrace()` and scans through its frames to find the logical source. It has to ignore some classes: `AbstractModule.java`, `RecordingBinder.java`, etc.
The stacktrace grabbing trick is _extremely_ cool, but it's not sufficient. Guice can't always know the full set of classes that it should skip. Extensions like [Multibinder](http://code.google.com/p/google-guice/wiki/Multibindings) create bindings on their user's behalf and need to omit additional classes from the trace (`RealMultibinder.java`, `Multibinder.java`). And [Provider Methods](http://code.google.com/p/google-guice/wiki/ProvidesMethods) specify their source as a method name instead of relying on a stack trace.
We need an API to specify which classes to skip in stacktraces, and another API to specify a source object directly.
### Binder Sources
The difficulty in finding a nice API for configuring sources is that it's naturally temporal. We want to specify a source, use it for a binding or two, and then reset it back:
<pre class="prettyprint">` public void configure(Binder binder) {
Method method = ...
**Object previous = binder.getSource();
binder.setSource(method);**
try {
binder.bind(method.getGenericReturnType())
.toProvider(new ProviderMethod(method));
} finally {
**binder.setSource(previous);**
}
}`</pre>
Yuck.
Taking inspiration from [List.subList()](http://java.sun.com/javase/6/docs/api/java/util/List.html#subList(int,%20int)), our approach is to instead return a _new_ binder that works with the provided source:
<pre class="prettyprint">` public void configure(Binder binder) {
Method method = ...
**Binder sourcedBinder = binder.withSource(method);**
**sourcedBinder**.bind(method.getGenericReturnType())
.toProvider(new ProviderMethod(method));
}`</pre>
Every binding, injection or configuration applied to `sourcedBinder` will use the user-specified source. But the passed-in binder is untouched. With some inlining and the binder's existing embedded DSL, the whole thing can be a single statement:
<pre class="prettyprint">` public void configure(Binder binder) {
Method method = ...
**binder.withSource(method)**
.bind(method.getGenericReturnType())
.toProvider(new ProviderMethod(method));
}
This new API is cute and fits nicely with the existing code.