Atom Feed SITE FEED   ADD TO GOOGLE READER

Wanted: javax.interceptor extension for Guice

I'm feverishly preparing Guice for the 2.0 release later this summer, and tonight I scanned through our issues list. There's a whole bunch of good features that I won't get to before our release. So I'm looking for Guice users to help out with development!

Introducing javax.interceptor


javax.interceptor is a fairly-simple method interception package for modern Enterprise Java stacks. These examples show how it works. Create a class with an @Interceptors annotation:
@Interceptors(AuditInterceptor.class)
public class AccountBean implements Account {
private int balance = 0;

public void deposit(int amount) {
balance += amount;
}
public void withdraw(int amount) {
balance -= amount;
}
}
Then create the interceptor:
public class AuditInterceptor {
@AroundInvoke
public Object audit(InvocationContext invocationContext) throws Exception {
System.out.println("Invoking method: " + invocationContext.getMethod());
return invocationContext.proceed();
}
}

If everything works as intended, the interceptor's audit() method will intercept all calls to deposit() and withdraw().

Guice's MethodInterceptor


Guice has another API for this, MethodInterceptor. Guice uses Matchers to support arbitrary selection of interceptable methods.

Wanted: an Extension for javax.interceptor


I believe this feature could be implemented as an extension to Guice. The extension would certainly require some clever tricks, but it should not require changes to the Guice internals. Here's what I guess the implementation could look like:
public class JavaxInterceptorModule extends AbstractModule {
public void configure() {
JavaxInterceptor interceptor = new JavaxInterceptor();
injectMembers(interceptor);
bindInterceptor(Matchers,any(), new InterceptMethodsMatcher(), interceptor);
}

static class JavaxInterceptor {
/**
* Loop over all the injector's bindings, looking for @Interceptor.
* Then verify that the interceptor classes are either injectable (ie.
* they have bindings), or they have a no-arg constructor. This
* isn't strictly necessary, but it allows us to fail faster, which is
* always a Guicy thing to do.
*/
@Inject void initialize(Injector injector) { ... }

/**
* Validate that the target method is intercepted. We need to
* consider just-in-time bindings that might not have been
* checked during initialize(). We also need to check for the
* ExcludeClassInterceptors etc. annotations.
*
* <p>Instantiate all of the injectors for this method, then
* run 'em. We'll need our own implementation of InvocationContext
* to pass to the interceptors.
*/
Object invoke(MethodInvocation invocation) { ... }
}
}

Of course it's not this simple. The implementation needs be tested to be consistent with the Java EE implementations. It needs to have reasonable error handing. And there's nuances related to inheritance etc. It also needs thorough unit tests.

Recruiting Contributors


Does writing this code sound fun to you? If it does, we'd love your help. Post your interest on the bug! You'll need to checkout the Guice code, write the code and tests, and upload a patch. I'll code review the patch (a fairly involved process) and we'll iterate until it's perfect.

In return, you'll get to see your @author line in the Guice source code. You'll probably learn a lot about AOP, Guice and reflection. It's resume padding. And of course, coding is its own reward.

Bug pattern: multiple ways to represent the same data

There's a class of bugs that come up when one logical datatypes has representations in multiple classes. The best example of this is 1 vs. 1L. Both ones represent the same data. But new Integer(1) is not equal to new Long(1) according to the corresponding equals() methods.

Calling contains(1) on a List<Long> compiles just fine, it just won't ever return true. Similarly for Map.get() and Set.contains(). Anything that depends on equals() is broken if you mix different types to express 'one'.

The problem is that each defines an equals method that is local to its class. This is a fair design - but as a consequence these types should not be mixed.

A short catalog of tricky types


...that can cause you pain if you mix them. These types can all represent the same logical value. But if you mix them, you will certainly get burned:
  • "0" : Byte, Short, Integer, Long
  • "0.0" : Float, Double
  • "Jan 1, 1970 12:00.00am UTC" : Date, long, Calendar
  • "http://publicobject.com" : URI, URL
  • "integer type" : int.class, Integer.class
  • "ABC" : StringBuffer, StringBuilder, CharSequence, String
  • "natural order" : Comparators.naturalOrder(), null
  • "String[].class" : GenericArrayType, Class (both of which implement Type)


A shorter catalog of good types


Fortunately, in a few places the JDK has interfaces that dictate how equals and hashCode must be implemented. As a consequence, you can freely intermix these types without consequence:
  • Sets: HashSet, LinkedHashSet, TreeSet
  • Maps: ConcurrentHashMap, HashMap, Collections.emptyMap()
  • Lists: ArrayList, LinkedList, Vector, Arrays.asList

Defining this behaviour for interfaces is somewhat difficult - use these classes as a guide. All implementations must implement the spec exactly or behaviour will be unreliable.

Recommendations


Avoid creating classes that allow one logical datatype to be represented by different classes. If you must, consider writing an interface to specify equals and hashCode at that level.

Choose a preferred, canonical form for your data. For example, if you consider 'null' and 'empty string' to be equal, choose one form and stick to it. Throw IllegalArgumentExceptions to callers that use the wrong one. If you're using collections, always use the canonical type for inserts and lookups.

Use an smart IDE like IntelliJ IDEA. It'll warn you when you mix types.

An Aside...


It turns out that Guice 1.0 suffered an ugly bug because of this problem. You can represent arrays in two different ways using Java 5's Types API. Either as an instance of Class or as an instance of GenericArrayType. The two are equivalent but not equals(). As a consequence, some injections would incorrectly fail with 'missing bindings' exceptions.

Guice talk, tomorrow morning at Google I/O

Bob and I are giving a talk at Google's developer conference tomorrow. From the session summary:
Wed 11:15am - 12:15pm
Bob Lee, Jesse Wilson

Guice (pronounced 'juice') is a Jolt award-winnning, lightweight dependency injection framework for Java 5 and above. Put simply, Guice alleviates the need for factories and the use of new in your Java code. Think of Guice's @Inject as the new new. You will still need to write factories in some cases, but your code will not depend directly on them. Your code will be easier to change, unit test and reuse in other contexts.

Calling a method that always throws

Kasper complains that it's hard to call methods that always throw. In particular, code like this won't compile because findGetter is missing a return statement:
  public Method findGetter() throws CsvException {
try {
return type.getMethod("get"
+ fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1));
} catch(SecurityException e) {
noSuchGetter(e);
} catch (NoSuchMethodException e) {
noSuchGetter(e);
}
}

public void noSuchGetter(Exception cause) throws CsvException {
String message = String.format("Unable to lookup getter"
+ " for field %s on %s", fieldName, type.getName());
throw new CsvException(message, cause);
}

The problem is that noSuchGetter always throws, but javac doesn't consider that when building this code. Making that method private or final doesn't help -- javac does not look at the body of a method when deciding whether the callers are valid.

Adding return null; to the end of this method appeases the compiler, but it sure isn't pretty:
  public Method findGetter() throws CsvException {
try {
return type.getMethod("get"
+ fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1));
} catch(SecurityException e) {
noSuchGetter(e);
} catch (NoSuchMethodException e) {
noSuchGetter(e);
}
return null; /* never executes! (this method never returns null.) */
}

As Kasper explains, this workaround sucks! In particular, it suggests to the code reader that he should check for null when calling this method. We need to add a big ugly comment to flag what's going on. Another workaround is to throw AssertionErrors on unreachable lines. This is an improvement but we still have dead code in our program. This line won't ever execute, adding noise to code coverage reports.

Fortunately, there's a clever fix. Declare that noSuchGetter returns a RuntimeException and prefix call to it with throw:
  public Method findGetter() throws CsvException {
try {
return type.getMethod("get"
+ fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1));
} catch(SecurityException e) {
throw noSuchGetter(e);
} catch (NoSuchMethodException e) {
throw noSuchGetter(e);
}
}

public CsvException noSuchGetter(Exception cause)
throws CsvException {
String message = String.format("Unable to lookup getter"
+ " for field %s on %s", fieldName, type.getName());
throw new CsvException(message, cause);
}

Now the code reader can see that the noSuchGetter calls always throw without reading that method's body. And the compiler will complain if you add any code after that call. We can optionally tweak this so noSuchGetter returns CsvException rather than throwing it.

Methods that always throw should return what they throw. If the method always throws a RuntimeException, we'd return that type.

Overriding Bindings in Guice

In our functional tests, we prefer to launch an application that closely resembles the production one. This means using the production modules in a proper staging environment. Even with automating scripts, setting up the environment is time consuming and tedious - it requires database install and configuration, permissions, SSL certificates, and remote services to be running and available:
public class ProductionModule extends AbstractModule {
protected void configure() {
bind(LoginService.class).to(RemoteLoginService.class);
bind(DataStore.class).to(MySqlDatabase.class);
bind(BillerConnection.class).to(SecureBillerConnection.class);
bind(LoggingEngine.class).to(DistributedLoggingEngine.class);
}
}

Since proper functional tests are so labour intensive, we take shortcuts! We can make a decent approximation of production by replacing some production services with lightweight fakes. For example, all of our functional tests require a login server to authenticate users. But for most tests login isn't interesting and this is just a wasted effort. We'd rather just fake login for unrelated functional tests.

Modular Modules


The best solution to this problem is to split the login stuff into its own module:
public class ProductionLoginModule extends AbstractModule {
protected void configure() {
bind(LoginService.class).to(RemoteLoginService.class);
}
}

In the functional test server we can use a FakeLoginModule rather than the ProductionLoginModule. It provides the same bindings, but its entirely in-memory and configuration free. This approach is simple, manageable and maintainable. It's the best way to mix production and test code.

Overrides via Inheritance


There's also a quick-and-dirty approach to creating test versions of servers. Extract each offending binding to its own method, and override that method in a subclass:
public class ProductionModule extends AbstractModule {
protected void configure() {
bindLoginService();
bind(DataStore.class).to(MySqlDatabase.class);
bind(BillerConnection.class).to(SecureBillerConnection.class);
bind(LoggingEngine.class).to(DistributedLoggingEngine.class);
}
protected void bindLoginService() {
bind(LoginService.class).to(RemoteLoginService.class);
}
}

public class TestModule extends ProductionModule {
@Override protected void bindLoginService() {
bind(LoginService.class).to(FakeLoginService.class);
}
}

This does this trick, but it's not elegant. We end up with different subclasses for each combination of fake bindings. It's fragile and makes for more work to divide the module later.

New: overrideModule


Sam Berlin has contributed a feature to Guice that provides a simple mechanism to replace bindings. To use it, we create a module with binding overrides:
public class OverridesModule extends AbstractModule {
@Override protected void configure() {
bind(LoginService.class).to(FakeLoginService.class);
}
}

We can combine our original, unmodified ProductionModule with the overrides to create a third module:
    Module functionalTestModule 
= Guice.overrideModule(new ProductionModule(), new OverridesModule());

In this example, we get the DataStore, BillerConnection and LoggingEngine bindings from ProductionModule, but the FakeLoginService from OverridesModule. The bindings in the overriding module replace bindings of the same key from the production module.

It's not as clean as modular modules, but it is more convenient. In particular, this approach doesn't require changes to the production module - great if that's provided by another team or a third party. It's also handy for testing the module itself!

This code is in SVN now if you're interested. It uses the new commands API to get a lot done in a small amount of code.

Fair Warning: I've been blogging about a lot of new Guice APIs lately. These APIs aren't final. If you depend on unreleased APIs from Guice svn, be aware that those APIs will probably change for 2.0.

MapBinder checked in!

Building out the Multibindings extension, David P. Baker has written a new class that simplifies Map binding. MapBinder uses an API that's consistent with Multibinder:
public class SnacksModule extends AbstractModule {
protected void configure() {
MapBinder<String, Snack> mapBinder
= MapBinder.newMapBinder(binder(), String.class, Snack.class);
mapBinder.addBinding("twix").toInstance(new Twix());
mapBinder.addBinding("snickers").toProvider(SnickersProvider.class);
mapBinder.addBinding("skittles").to(Skittles.class);
}
}

Like Multibinder...


Keys must be non-null and unique. Values must be non-null. Values get resolved at injection-time, so they can be scoped. Bindings from different modules will be aggregated, which makes it usable for an application registry.

Unlike Multibinder...


For the example above, an extra binding is made for Map<String, Provider<Snack>>. This makes it so that if values are expensive to provide, you can get just the ones you need.

This API is available in Guice svn right now. The API is subject to change before version 2. I suspect we'll probably rename Multibinder to either SetBinder or MultiBinder. Any preferences?

Elite Guice 3: Private Bindings

In the first and second parts of this series, I discussed hooks for extending Guice. In this post I introduce private bindings.

Don't emulate Guice


The key to a good extension is tight integration with Guice. In particular, the extension shouldn't copy functionality from Guice; doing so can lead to subtle differences between the extension and Guice itself. The assisted inject extension reimplements constructor injection and that causes problems:
  • Standard Guice can inject private constructors, but I forgot to do configure this in assistedinject.
  • AOP doesn't work for assistedinject-created objects

These differences aren't dealbreakers, but they do make the extension harder to use, and they violate the principal of least surprise. A better assistedinject would have used Guice's constructor injection.

The Injector is just a bunch of bindings


In the Multibindings extension, we secretly create a binding for each element in the set. These bindings are implementation details of the extension, but they need to be bound in the shared injector.

We have to somehow create the bindings without a chance of conflicting with user-supplied bindings. If Multibinder and the user both bound the same key, injector creation would fail.

Private Annotations to the rescue


The fix is to create a binding annotation type with a narrow scope, such as package scope. Other code won't have access to this annotation, and therefore we can be confident that only our extension can create bindings with this annotation.

In the Multibindings extension, there's a custom annotation called @Element that's secretly applied to all elements. Each annotation instance is given a unique ID to ensure that the hosting keys are distinct. Unless they're using a tool that interrogates the Injector, the users of Multibinder never see these bindings. They're created internally and used internally. But they allow all of Guice's features to work naturally on the bound elements.

Implementing the annotation type is code-intensive, but there's thorough instructions that describe how equals, hashCode and even toString() should be implemented.

This technique is also used in InterceptingInjectorBuilder, in order to let InjectionController work its magic.

Why no Multibindings for Lists or Arrays?

The Multibindings code I checked in last week has been well received. There's even a screencast introducing the new code.

But there are missing features. We're still figuring out exactly what's the right balance of functionality and simplicity. One particular omission is the lack of support for Lists and arrays.

This is intentional. The deal breaker with Lists and arrays is that they imply an explicit order of their elements. But Multibinder has no idea how to order the elements. It could try to keep elements of the same module in the same order they were bound, but all bets are off when the bindings come from multiple modules. And it would be very annoying if reordering your modules changed the behaviour of your program.

But if you really want a List...


Its not to hard to make a List<String> binding using the Set<String> binding that Multibinder gives you.
    bind(new TypeLiteral<List<String>>() {})
.to(new Provider<List<String>>() {
@Inject Provider<Set<String>> setProvider;

public List<String> get() {
/* if we wanted to, we could sort the list somehow */
return Collections.unmodifiableList(
new ArrayList<String>(setProvider.get());
}
});

Using this technique, you could also bind Map<K, V> if you've got a binding to Set<Map.Entry<K, V>>. We're thinking about adding built-in support for Maps, but this will work until we do.

Elite Guice 2: Binding de-duplication

In part one, I showed how to initialize a Guice extension using the @Inject tag on a method. In this post I'm going to demonstrate a Guice for deduplicating bindings.

What is binding duplication?


One of the features of the Multibindings Extension is that there's no central coordination. Each module contributes its own bindings, and they all get amalgamated into a single collection. Suppose you have these modules:
public class CandybarModule extends AbstractModule {
protected void configure() {
Multibinder<Snack> multibinder = Multibinder.newSetBinder(binder(), Snack.class);
multibinder.addBinding().toInstance(new Twix());
multibinder.addBinding().toProvider(SnickersProvider.class);
}
}
public class ChipsModule extends AbstractModule {
protected void configure() {
Multibinder<Snack> multibinder = Multibinder.newSetBinder(binder(), Snack.class);
multibinder.addBinding().to(Pringles.class);
multibinder.addBinding().toInstance(new Doritos());
}
}

Out of this API, our Multibinder implementation needs to bind Set<Snack> exactly once. This is tricky! For example, suppose our newSetBinder method was implemented like this:
  public static <T> Multibinder<T> newSetBinder(Binder binder, Type type) {
binder.bind(getSetKey(type)).toProvider(getSetProvider(type));
return new Multibinder(type);
}

This won't work. We call newSetProvider from both the CandybarModule and the ChipsModule, and Guice complains because we're binding Set<Snack> twice. This is binding duplication.

If Guice had an duplicate-binding API


Guice doesn't have this API, but what we kind of find ourselves wanting is a way to query the binder for its bindings thus-far:
  public static <T> Multibinder<T> newSetBinder(Binder binder, Type type) {
if (!binder.getBindings().containsKey(getSetKey(type))) {
binder.bind(getSetKey(type)).toProvider(getSetProvider(type));
}
return new Multibinder(type);
}

This would work, but in general it's a pretty terrible idea. It makes it easy to write fragile modules - modules that depend on the order they are installed in. And it also changes the module from being static configuration (good!) to a dynamic-runtime configuration (bad!). So we're glad this API doesn't exist.

But in this one case, we really wish we could prevent our binding from being performed twice.

Modules as value objects


The solution to this problem is a bit surprising, but I think it's quite elegant. Guice conveniently allows the same module to be installed twice. This is necessary so that both your PizzaServletsModule and your PizzaDatabaseModule can install your PizzaDomainModule.

Rather than binding the Set<Snack> directly on the binder, we create special Module class whose only job is to create that binding. And then we give that module a proper equals() and hashCode() methods, so that any two instances that bind the same type are equal.

Our final code looks like this:
  public static <T> Multibinder<T> newSetBinder(Binder binder, Type type) {
binder.install(new MultibindingModule(getSetType(), getProviderType()));
return new Multibinder(type);
}

The Module trick allows us to decentralize the binding. And that means less configuration code, and that means less code. Hooray for Guice.

Elite Guice 1: Initialize your extension

I recently wrote some fairly, um, extreme code for the Guice Mutibindings extension. That code makes use of several tricks that you might find useful in your own Guice extensions. In this series I'm going to show-and-tell the various clever code tricks from Multibinder.java.

Initialize an extension


Guice doesn't have a plug-in API and it probably never will. But if it did, it would probably provide a mechanism for you to initialize your plugin:
public interface GuicePlugin {
void initialize(Injector injector) throws ConfigurationException;
}

This interface doesn't exist. But that's fine, because Guice does something better - it injects members into every bound instance and provider instance at injector-creation time. And where there is injection, there is initialization. There's two steps to getting Guice to call your initialize method:
  1. Bind an instance, or a provider instance.
    Usually your extension is going to bind something anyway. Multibinder binds its Set, AssistedInject binds its Factory, ThrowingProviders binds its ThrowingProvider. If you have absolutely nothing to bind, create a class and bind an instance of that.

    You must bind either an instance, a provider instance, or an eager singleton. These are the only things that get injected at injector-creation time.

  2. Create a @Inject initialize() method on the bound instance.
    This method gets called at injector-creation time. This is that important stage after all modules have been executed but before the Injector has been returned to its creator. Your initialize method can take any injectable objects as parameters - usually the Injector is a useful choice, since it allows your extension to review its complete set of bindings.

    The method can also throw exceptions to indicate that it's improperly configured. Guice 1.0 has a bug where sometimes these exceptions don't halt injection. But recent snapshots have fixed this problem and you can now reliably use exceptions to fail if your extension is misconfigured. AssistedInject uses this feature to fail if your assisted constructor cannot be injected.


Example


In Multibinder.java, we bind a provider instance for the set:
    public void configure(Binder binder) {
...
binder.bind(setKey).toProvider(setProviderInstance);
}

That provider has our initialize() method. In this case, the initialize method loops through all of the injector's bindings, collecting providers for the elements of the collection:
    /**
* Invoked by Guice at Injector-creation time to prepare providers for each
* element in this set. At this time the set's size is known, but its
* contents are only evaluated when get() is invoked.
*/
@Inject void initialize(Injector injector) {
providers = new ArrayList<Provider<T>>();
for (Map.Entry<Key, Binding> entry : injector.getBindings().entrySet()) {
if (keyMatches(entry.getKey())) {
Binding<T> binding = (Binding<T>) entry.getValue();
providers.add(binding.getProvider());
}
}
}

Hooray, our extension is initialized. In future posts I intend to discuss duplicate binding, private bindings, and perhaps annotation nesting.

Guice Multibindings extension checked in!

As previously alluded to, I've started work on the Multibindings API. I've checked in the initial implementation, and I'm pretty excited about it. You can grab it from svn.

This feature is ideal for lightweight plugin-type architectures, where you've got multiple modules each contributing Servlets, Actions, Filters, Components or even just names.

The Multibinder Javadoc:

An API to bind multiple values separately, only to later inject them as a complete collection. Multibinder is intended for use in your application's module:
public class SnacksModule extends AbstractModule {
protected void configure() {
Multibinder<Snack> multibinder
= Multibinder.newSetBinder(binder(), Snack.class);
multibinder.addBinding().toInstance(new Twix());
multibinder.addBinding().toProvider(SnickersProvider.class);
multibinder.addBinding().to(Skittles.class);
}
}

With this binding, a Set<Snack> can now be injected:
class SnackMachine {
@Inject
public SnackMachine(Set<Snack> snacks) { ... }
}

Create multibindings from different modules is supported. For example, it is okay to have both CandyModule and ChipsModule to both create their own Multibinder<Snack>, and to each contribute bindings to the set of snacks. When that set is injected, it will contain elements from both modules.

Elements are resolved at set injection time. If an element is bound to a provider, that provider's get method will be called each time the set is injected (unless the binding is also scoped).

Annotations are be used to create different sets of the same element type. Each distinct annotation gets its own independent collection of elements.

Elements must be distinct. If multiple bound elements have the same value, set injection will fail.

Elements must be non-null. If any set element is null, set injection will fail.