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.

Reply via email to