More recently, I argued (and Restlet's Jérôme Louvel seemed to accept the argument) that Restlet needs a uniform way to create a non-standard Finder for all the Restlet classes that have methods accepting a
Class<? extends ServerResource>in place of a Restlet. This would make the use of the Guice extension invisible when wiring up the routing structure: Currently you have to convert the resource type to a Restlet explicity,
router.attach("/path/to/resource", finderFactory.finder(MyResource.class));and the extra support would let you write:
router.attach("/path/to/resource", MyResource.class);It's all very gratifying, except I realized suddenly this week that for most people who just want to inject their ServerResource subclasses it's completely unnecessary. It's much simpler to define doInit() to inject the resource's members, and then you can just use the second, simpler form above. I wrote an abstract base class extending
ServerResourcethat does just that:
SelfInjectingServerResourceuses only the standard @Inject annotation and nothing specific to Guice. In order to make it actually work with Guice, you need to tell Guice that you want self-injecting server resources. The following class is a Guice Module that accomplishes this by requesting static injection of the
SelfInjectingServerResourceclass and providing an implementation of its nested
MembersInjectorinterface to perform the injection.
Install this module when creating the top-level injector, make sure that the server resources you want injected inherit from
SelfInjectingServerResource, and it just works. Here's a JUnit test class that shows a trivial example of the idea in practice:
We'd like this technique to co-exist with other techniques that manage resource injection differently (e.g., the current Guice extension), without worrying about whether it's OK to extend
SelfInjectingServerResource, so this code uses an atomic boolean to prevent multiple injections. (AtomicBoolean is probably overkill, but it can't hurt to be safe.)
[Deleted obsolete discussion of how to use prior to adoption as part of Restlet.]
I said that the old Guice extension was unnecessary for most users, but there are a few things the old code does that the new code doesn't do:
- It does constructor injection, letting you have final fields with injected values.
- It lets you create a Finder for a resource interface, decoupling the target of the routing from the resource implementation.
- It lets you use qualifiers when looking up resource types, further decoupling the target of an attachment from the implementation.
- It doesn't require inheritance from a common abstract base class.
- You don't have to remember to call
super.doInit()when you override
findercall in this case, even with added Restlet support, because the Restlet signatures expect a
ServerResourcesubclass.) So I'm stuck with my mistake for the foreseeable future. But no one else need be, now.
Update (2013 July 9)
I got rid of my dependency on #2 above, and I am now using the new approach exclusively, and I strongly recommend others do the same.
Further update (2014 Sep 1)
The Restlet Guice extension package docs discuss how to use each of three approaches, so you aren't forced to use the approach that I prefer.