I have a codebase with several layers of SPI in separate projects -
we'll call this these projects SPI (minimal interfaces), SPISupport
(convenience implementations of some common logic - in practice there
is yet another layer that ties you to some specific data storage
choices but simplifies things further). A frequent pattern is:
- SPI contains "interface A" and "class Something { @Inject A a; ..."
- SPISupport contains "abstract class AbstractA implements A" and
"final class HelperClass { @Inject AbstractA a; ..."
- TestHarness contains "ReferenceImplementation extends AbstractA {"
A test implementation then extends AbstractA over a HashMap - a thing
that really *has* to be a singleton with respect to the module that
creates it (but using a static would make it possible for unit tests
to cause side effects for each other).
bind (A.class).to(AImpl.class).in(Scopes.SINGLETON);
bind (AbstractA.class).to(AImpl.class).in(Scopes.SINGLETON);
Rather surprisingly, *two* instances of AImpl are created - so far I
have found no clean way to avoid this. Since SPI cannot know about
classes in SPISupport, this is rather a impasse.
Here is a simple test case:
interface Singleton {}
static abstract class A implements Singleton {}
static class B extends A {}
static class Thing { @Inject Singleton singleton; @Inject A a; }
@Test
public void testBindingPolymorphism() {
Module m = new AbstractModule() {
@Override
protected void configure() {
bind
(Singleton.class).to(B.class).in(Scopes.SINGLETON);
bind (A.class).to(B.class).in(Scopes.SINGLETON);
}
};
Thing t = Guice.createInjector(m).getInstance(Thing.class);
assertSame (t.a, t.singleton); // THIS WILL FAIL
}
I had a lovely "Aha!" moment when it it occurred to me that this was
my mistake, for binding to exact types, and the solution would look
like:
static class Thing {
@Inject Provider <? extends Singleton> singleton;
@Inject Provider <A> a;
}
Alas, this has the fatal problem that wildcard injection is illegal in
Guice - com.google.inject.internal.ComputationException. And
secondarily that core SPI classes should not have dependencies on
Guice anyway.
Given the test case above, is there some Guice-friendly way (i.e. not
blind casting) to ensure that only one instance of B is ever created
to satisfy injections of both Singleton and A?
It *is* possible to avoid ever injecting a subclass of any type whose
supertype might also be injected. However, part of a "convenience
implementation" of something is simplifying things - using a
composition-based approach to avoid inheritance issues with injection
does the opposite, in terms of increasing the conceptual surface area
of the API.
Thanks for any suggestions,
Tim
--
You received this message because you are subscribed to the Google Groups
"google-guice" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/google-guice?hl=en.