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 ServerResource that does just that:
SelfInjectingServerResource.java
Notice that
SelfInjectingServerResource uses 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
SelfInjectingServerResource class and providing an implementation of its nested
MembersInjector interface to perform the injection.
SelfInjectingServerResourceModule.java
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:
SelfInjectingServerResourceModuleTest.java
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 overridedoInit
finder
call in this case, even with added Restlet support, because the
Restlet signatures expect a ServerResource subclass.)
So I'm stuck with my mistake for the foreseeable future.
But no one else need be, now.