xiaodududu / google-guice

Automatically exported from code.google.com/p/google-guice
Apache License 2.0
0 stars 0 forks source link

Multiple interface implementation at runtime #476

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
In my team we try use GUICE as much as possible for the benefits of a
cleaner dependencies model. However, one aspect we still have issues with
is when we have multiple implementation for a single interface, and the
decision of which implementation to pick is a runtime decision. 

In the user guide, you clearly documented an example for using the @Named
to pick an implementation at construction time, However In our case that
decision is based on some attributes in some request object we get at runtime. 

Our solution to this has been by building registries that holds Map
<String, to the Impl> and that Map gets built using request*Injection in
GUICE when it loops over all bindings for specific interfaces that we know
have multiple impl. 

At some point our code base got clouded with many boiler plate registries
for each type. So today I decided to create a generalized registry (code
and example below) that will cater to any interface.

My question are:

1) Is there any code to address this multiple implementation issue now or
in the future natively in guice? I am just worried I am going overboard
with the code below

2) @Named cannot be set at class Level, it will be nice if we can mark
these implementation as such and just bound them normally without the
annotedWith() in a guice module, is that possible?

Example Code 
==============
    public static void main(String[] args) {

        Injector injector = Guice.createInjector(new AbstractModule() {

            /**
             * @see com.google.inject.AbstractModule#configure()
             */
            @Override
            protected void configure() {

                 requestInjection(GUICERegistry.class);

bind(GreetingDAO.class).annotatedWith(Names.named("mean")).to(MeanGreetingDAO.cl
ass).in(Singleton.class);

bind(GreetingDAO.class).annotatedWith(Names.named("polite")).to(PoliteGreetingDA
O.class).in(Singleton.class);
            }
        });

        GUICERegistry registry = injector.getInstance(GUICERegistry.class);
// The goal is to have a single registry, like this one

        GreetingDAO dao = registry.findByAnnotation(GreetingDAO.class,
"mean"); // This is retrieving at runtime instead of in construction time
        System.out.println(dao.getGreeting());

        GreetingDAO dao2 = registry.findByAnnotation(GreetingDAO.class,
"polite");
        System.out.println(dao2.getGreeting());

    }

    // My interfaces and impls

    public static interface GreetingDAO {

        public String getGreeting();
    }

    public static class MeanGreetingDAO implements GreetingDAO {

        @Override
        public String getGreeting() {

            return "What the frack do you want?";
        }

    }

    public static class PoliteGreetingDAO implements GreetingDAO {

        @Override
        public String getGreeting() {

            return "Hello dear sir/madam How can I help you?";
        }
    }

Results of Main method
=======================
What the frack do you want?
Hello dear sir/madam How can I help you?

GUICERegistry.java code listing
================================
public class GUICERegistry {

    private Injector injector;

    public <T> T findByAnnotation(Class<T> clazz, String
annotationImplementationName) {

        assert clazz != null;
        assert annotationImplementationName != null;

        List<Binding<T>> processorBindings =
injector.findBindingsByType(TypeLiteral.get(clazz));

        for (Binding<T> processorBinding : processorBindings) {
            Annotation annotationBound =
processorBinding.getKey().getAnnotation();
            if (annotationBound == null) {
                continue;
            }
            if (!(annotationBound instanceof Named)) {
                throw new IllegalArgumentException("When calling the
findByAnnotation is it assumed that implementation are bound via the @Named
annotation");
            }

            String name = ((Named) annotationBound).value();
            if (annotationImplementationName.equals(name)) {
                return processorBinding.getProvider().get();
            }

        }
        throw new IllegalArgumentException("some error message");
    }

    @Inject
    public void setInjector(Injector injector) {

        this.injector = injector;
    }
}

Original issue reported on code.google.com by ramzi.ya...@gmail.com on 28 Apr 2010 at 10:44

GoogleCodeExporter commented 9 years ago
See the Multibinder & MapBinder extensions @
http://code.google.com/p/google-guice/wiki/Multibindings .

Original comment by sberlin on 29 Apr 2010 at 3:24

GoogleCodeExporter commented 9 years ago
Thank you so much the MapBinder will do the trick for me , thanks for your time 
again

Original comment by ramzi.ya...@gmail.com on 29 Apr 2010 at 4:28