Search code examples
javadependency-injectionguice

Google Guice Named vs Annotation


I was going through Google Guice documentation and read about UntargettedBinding. Basically there are two options

  1. @Named
  2. Binding annotation

My question is, which one is better?

With @Named I dont have to create boiler plates to use annotations but it comes at cost of less type safety. Annotation code looks more cleaner IMHO.


Solution

  • You specified the Pros and Cons of binding annotation in general as explained here.
    Your statements are correct.

    One more advantage of @Named is to bind for properties using Names.bindProperties. Where using binding annotation is irrelevant. See how to load properties

    For UntargetBinding (which sound like it was the actual question) the documentation states two options

    If you don't want to use binding annotation/@Named just declare the bind to the concrete class.
    E.g.

    bind(MyConcreteClass.class);
    bind(AnotherConcreteClass.class).in(Singleton.class);
    

    You need to use binding annotation/@Named you must still add the target binding i.e. the ".toSometing" methods (to, toProvider, toContractor etc.)

    For example:

    public class TestUntargetBinding {
    
        @Test
        void testTargetBindingViaImplementBy() {
            final var injector = Guice.createInjector(new AbstractModule() {
                @Override
                public void configure() {
                    bind(MyConcreteClass.class)
                            .annotatedWith(Names.named("100"))
                            .toProvider(() -> new MyConcreteClass(100));
                    bind(MyConcreteClass.class)
                            .annotatedWith(Names.named("200"))
                            .toProvider(() -> new MyConcreteClass(200));
    
                }
            });
            //imagine a class with a constructor
            // @Inject
            // SomeClass(@Named("100) MyConcreteClass myConcreteClass1){...}
            final var myConcreteClass1 = injector.getInstance(Key.get(MyConcreteClass.class, Names.named("100")));
            final var myConcreteClass2 = injector.getInstance(Key.get(MyConcreteClass.class, Names.named("200")));
    
            assertThat(myConcreteClass1.doSomething(), Is.is(100));
            assertThat(myConcreteClass2.doSomething(), Is.is(200));
    
        }
    
        static class MyConcreteClass {
            private int i;
    
            public MyConcreteClass(int i) {
                this.i = i;
            }
    
            public int doSomething() {
                return i;
            }
        }
    }
    

    Guice will not know witch class to bind the name/annotation to unless you will specify the "toProvider"