Annotation on local variable

1,734 views
Skip to first unread message

Jerem's

unread,
Jul 19, 2010, 11:21:04 AM7/19/10
to google-guice
Hello I try to use annotatoij on a local variable :

this is my module :

public class DrawModule extends AbstractModule {

@Override
protected void configure() {

this.bind(IDrawGraphService.class).annotatedWith(ToDot.class).to(DrawDotServiceImpl.class);
}
}

and my Annotation look like that :

@Retention(RUNTIME)
@Target({ LOCAL_VARIABLE, FIELD, PARAMETER })
@BindingAnnotation
public @interface ToDot {

}

and I try to do that :

Injector drawGraphInjector = Guice.createInjector(new DrawModule());
@ToDot
IDrawGraphService drawDotService =
drawGraphInjector.getInstance(IDrawGraphService.class);


But I have an exception :

Exception in thread "main" com.google.inject.ConfigurationException:
Guice configuration errors:

1) No implementation for
fr.irisa.cairn.simpleGraph.drawGraph.service.IDrawGraphService was
bound.
while locating
fr.irisa.cairn.simpleGraph.drawGraph.service.IDrawGraphService

1 error
at com.google.inject.InjectorImpl.getProvider(InjectorImpl.java:784)
at com.google.inject.InjectorImpl.getProvider(InjectorImpl.java:743)
at com.google.inject.InjectorImpl.getInstance(InjectorImpl.java:793)
at
fr.irisa.cairn.test.simpleGraph.runTimeTest.Launch.Main.main(Main.java:
25)


do you know why?

jérémie

Sam Berlin

unread,
Jul 19, 2010, 11:39:33 AM7/19/10
to google...@googlegroups.com
Guice cannot detect annotations on local variables this way (although it's an interesting idea!).  You have two options here:

1)  Make the variable on the class wherever this code is in and add an extra module that has requestInjection(YourClass.this) in its configure method.  Then Guice will inject that variable as part of its Injector creation.
2) Use injector.getInstance(Key.get(IDrawGraphService.class, ToDot.class)) instead.  That tells Guice that you want to retrieve the instance defined by the Key "@ToDot IDrawGraphService", as opposed to just "IDrawGraphService".

sam


--
You received this message because you are subscribed to the Google Groups "google-guice" group.
To post to this group, send email to google...@googlegroups.com.
To unsubscribe from this group, send email to google-guice...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-guice?hl=en.


Brian Pontarelli

unread,
Jul 19, 2010, 12:03:40 PM7/19/10
to google...@googlegroups.com
I'm not sure that would be possible to support without using APT or something like that. The injector doesn't know about the variable its return value is being assigned to and therefore wouldn't be able to infer the correct binding. This would be something to take up with the Java language people under project coin or something similar.

-bp

Jerem's

unread,
Jul 19, 2010, 12:45:39 PM7/19/10
to google-guice
Thanks sam.

that's not cool that Annotation don't work for local variable.

I try the second version. IT works. thanks :).
But I don't really like it.

So I try the first version. Bit it is not really clear in my mind.
I create a client class :

public class Client {

private IDrawGraphService service;

@Inject
public Client(IDrawGraphService service) {
super();
this.service = service;
}


public void executeService(ISimpleGraph graph, String path) throws
IOException {
service.draw(graph, path);
}
}

but Don"t really see hos decide hos to decided is the service is a
drawTextServiceImpl or a drawDotServiceImpl


jérémie
> > google-guice...@googlegroups.com<google-guice%2Bunsubscribe@google groups.com>
> > .

Sam Berlin

unread,
Jul 19, 2010, 1:37:56 PM7/19/10
to google...@googlegroups.com
Add an annotation to your injected variable, like: 

 @Inject public Client(@YourBindingAnnotation IDrawGraphService service)  { .. }

That tells Guice that when it injects the constructor with variables, it should inject the graph service that was annotated with that binding annotation.

sam


To unsubscribe from this group, send email to google-guice...@googlegroups.com.

Jerem's

unread,
Jul 19, 2010, 2:48:25 PM7/19/10
to google-guice
Yeah I know that. but It is not really what I want.
If I do that :

@Inject
public Client(@ToDot IDrawGraphService service) {
.. }

service can only be a DrawDotServiceImpl. but how can I have a
DrawTextServiceImpl?
I wuld like that the client can choose the implementation.
Here, he can't.

may I can build a new class client2.

@Inject
public Client2(@ToText IDrawGraphService service) {
.. }

But I don't like to have two kinds of ciient.

Jérémis


On 19 juil, 19:37, Sam Berlin <sber...@gmail.com> wrote:
> Add an annotation to your injected variable, like:
>
>  @Inject public Client(@YourBindingAnnotation IDrawGraphService service)  {
> .. }
>
> That tells Guice that when it injects the constructor with variables, it
> should inject the graph service that was annotated with that binding
> annotation.
>
> sam
>
> > > > google-guice...@googlegroups.com<google-guice%2Bunsu...@googlegroups.com>
> > <google-guice%2Bunsubscribe@google groups.com>
> > > > .
> > > > For more options, visit this group at
> > > >http://groups.google.com/group/google-guice?hl=en.
>
> > --
> > You received this message because you are subscribed to the Google Groups
> > "google-guice" group.
> > To post to this group, send email to google...@googlegroups.com.
> > To unsubscribe from this group, send email to
> > google-guice...@googlegroups.com<google-guice%2Bunsu...@googlegroups.com>

Sam Berlin

unread,
Jul 19, 2010, 3:07:45 PM7/19/10
to google...@googlegroups.com
Ahh -- sorry, i didn't get that you were wanting the client to choose which one to use.  In that case, take a look at MapBinder @ http://code.google.com/p/google-guice/wiki/Multibindings .  Set up a MapBinder where you bind a Map<Class<? extends Annotation>, IDrawGraphService>, and add a binding into that MapBinder for each of your implementations.  Then your client injects  Map<Class<? extends Annotation>, IDrawGraphService> and calls map.get(TheAnnotationItWants.class) and gets the proper implementation.  (You can also use enums for the keys, or any arbitrary other type, which might be clearer.)

sam

To unsubscribe from this group, send email to google-guice...@googlegroups.com.

Jerem's

unread,
Jul 20, 2010, 9:17:21 AM7/20/10
to google-guice
hmm.

it looks complicated.

At he beginning I just wanted to do that :

@ToDot
IDrawGraphService drawDotService =
drawGraphInjector.getInstance(IDrawGraphService.class);

@ToText
IDrawGraphService drawTextService =
drawGraphInjector.getInstance(IDrawGraphService.class);

So it was easy to choose an implementation. (just need an annotation).
I thought that Google guice is cool.
But guice annotation doesn't work on local variable.

So if we can't do that easily. I think I prefer the old method.

jérémie

On 19 juil, 21:07, Sam Berlin <sber...@gmail.com> wrote:
> Ahh -- sorry, i didn't get that you were wanting the client to choose which
> one to use.  In that case, take a look at MapBinder @http://code.google.com/p/google-guice/wiki/Multibindings.  Set up a
> > > > > > google-guice...@googlegroups.com<google-guice%2Bunsubscribe@google groups.com>
> > <google-guice%2Bunsu...@googlegroups.com<google-guice%252Bunsubscribe@g ooglegroups.com>
>
> > > > <google-guice%2Bunsubscribe@google groups.com>
> > > > > > .
> > > > > > For more options, visit this group at
> > > > > >http://groups.google.com/group/google-guice?hl=en.
>
> > > > --
> > > > You received this message because you are subscribed to the Google
> > Groups
> > > > "google-guice" group.
> > > > To post to this group, send email to google...@googlegroups.com.
> > > > To unsubscribe from this group, send email to
> > > > google-guice...@googlegroups.com<google-guice%2Bunsubscribe@google groups.com>
> > <google-guice%2Bunsu...@googlegroups.com<google-guice%252Bunsubscribe@g ooglegroups.com>
>
> > > > .
> > > > For more options, visit this group at
> > > >http://groups.google.com/group/google-guice?hl=en.
>
> > --
> > You received this message because you are subscribed to the Google Groups
> > "google-guice" group.
> > To post to this group, send email to google...@googlegroups.com.
> > To unsubscribe from this group, send email to
> > google-guice...@googlegroups.com<google-guice%2Bunsubscribe@google groups.com>

Sam Berlin

unread,
Jul 20, 2010, 9:43:28 AM7/20/10
to google...@googlegroups.com
If you prefer the old method, use getInstance(Key.get(...)).  It does exactly what you're looking for.  Just swap the annotation from the local variable to inside the Key.get method.

FWIW, though, injecting the injector is bad practice (because you aren't explicitly defining what your dependencies are).  MapBinder is the preferred way to do something like this.  It's very easy to use.  Your case would be:
 GraphType enum { DOT, TEXT } // new enum class
 ...
 configure() {  // your module configuration
   MapBinder<GraphType, IDrawGraphService> mapBinder = MapBinder.newMapBinder(binder(), GraphType.class, IDrawGraphService.class);
   mapBinder.addBinding(GraphType.DOT).to(DotGraphServiceImpl.class);
   mapBinder.addBinding(GraphType.TEXT).to(TextGraphServiceImpl.class);
 }
 ...
 @Inject Client(Map<GraphType, IDrawGraphService> services) {  // your client classes
     IDrawGraphService dotService = services.get(GraphType.DOT); // if you want dot
     IDrawGraphService textService = services.get(GraphType.TEXT); // if you want text
    ...
  }

no need to even use binding annotations.

sam

To unsubscribe from this group, send email to google-guice...@googlegroups.com.

Brian Pontarelli

unread,
Jul 20, 2010, 10:45:50 AM7/20/10
to google...@googlegroups.com
I'm pretty sure that local variable annotations aren't accessible at runtime by the right hand operand. Therefore, it doesn't have anything to do with Guice, but rather then JDK. Anyone know if that is possible with JDK 6 or 7? I'm guessing answer is "no" based on my knowledge of the way that the = operator is evaluated.

-bp

> To unsubscribe from this group, send email to google-guice...@googlegroups.com.

Jerem's

unread,
Jul 20, 2010, 11:46:11 AM7/20/10
to google-guice
hey thanks sam for you answer (very detailled answer :) ).

But I still have an exception :

1) No implementation for
java.util.Map<fr.irisa.cairn.simpleGraph.drawGraph.module.DrawGraphType,
fr.irisa.cairn.simpleGraph.drawGraph.service.IDrawGraphService> was
bound.
while locating
java.util.Map<fr.irisa.cairn.simpleGraph.drawGraph.module.DrawGraphType,
fr.irisa.cairn.simpleGraph.drawGraph.service.IDrawGraphService>
for parameter 0 at
fr.irisa.cairn.test.simpleGraph.runTimeTest.Launch.ClientImpl.<init>(ClientImpl.java:
20)
at
fr.irisa.cairn.test.simpleGraph.runTimeTest.Launch.ClientModule.configure(ClientModule.java:
9)

1 error
at
com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:
354)
at
com.google.inject.InjectorBuilder.initializeStatically(InjectorBuilder.java:
152)
at com.google.inject.InjectorBuilder.build(InjectorBuilder.java:105)
at com.google.inject.Guice.createInjector(Guice.java:92)
at com.google.inject.Guice.createInjector(Guice.java:69)
at com.google.inject.Guice.createInjector(Guice.java:59)
at
fr.irisa.cairn.test.simpleGraph.runTimeTest.Launch.Main.main(Main.java:
24)



My ClientImpl class look like that :

1) No implementation for
java.util.Map<fr.irisa.cairn.simpleGraph.drawGraph.module.DrawGraphType,
fr.irisa.cairn.simpleGraph.drawGraph.service.IDrawGraphService> was
bound.
while locating
java.util.Map<fr.irisa.cairn.simpleGraph.drawGraph.module.DrawGraphType,
fr.irisa.cairn.simpleGraph.drawGraph.service.IDrawGraphService>
for parameter 0 at
fr.irisa.cairn.test.simpleGraph.runTimeTest.Launch.ClientImpl.<init>(ClientImpl.java:
20)
at
fr.irisa.cairn.test.simpleGraph.runTimeTest.Launch.ClientModule.configure(ClientModule.java:
9)

1 error
at
com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:
354)
at
com.google.inject.InjectorBuilder.initializeStatically(InjectorBuilder.java:
152)
at com.google.inject.InjectorBuilder.build(InjectorBuilder.java:105)
at com.google.inject.Guice.createInjector(Guice.java:92)
at com.google.inject.Guice.createInjector(Guice.java:69)
at com.google.inject.Guice.createInjector(Guice.java:59)
at
fr.irisa.cairn.test.simpleGraph.runTimeTest.Launch.Main.main(Main.java:
24)

Jeremie
> > <google-guice%252Bunsubscribe@g ooglegroups.com>
>
> > > > > > .
> > > > > > For more options, visit this group at
> > > > > >http://groups.google.com/group/google-guice?hl=en.
>
> > > > --
> > > > You received this message because you are subscribed to the Google
> > Groups
> > > > "google-guice" group.
> > > > To post to this group, send email to google...@googlegroups.com.
> > > > To unsubscribe from this group, send email to
> > > > google-guice...@googlegroups.com<google-guice%2Bunsubscribe@google groups.com>

Sam Berlin

unread,
Jul 20, 2010, 12:52:42 PM7/20/10
to google...@googlegroups.com
Did you include this part
--
>  configure() {  // your module configuration
>    MapBinder<GraphType, IDrawGraphService> mapBinder =
> MapBinder.newMapBinder(binder(), GraphType.class, IDrawGraphService.class);
>    mapBinder.addBinding(GraphType.DOT).to(DotGraphServiceImpl.class);
>    mapBinder.addBinding(GraphType.TEXT).to(TextGraphServiceImpl.class);
>  }
--
in your module that gets installed?  

sam

To unsubscribe from this group, send email to google-guice...@googlegroups.com.

Jerem's

unread,
Jul 20, 2010, 12:57:24 PM7/20/10
to google-guice
yes
this is my module configuration :

@Override
protected void configure() {
MapBinder<DrawGraphType, IDrawGraphService> mapBinder =
MapBinder.newMapBinder(
this.binder(), DrawGraphType.class, IDrawGraphService.class);

mapBinder.addBinding(DrawGraphType.DOT).to(DrawDotServiceImpl.class);

mapBinder.addBinding(DrawGraphType.TEXT).to(drawTextServiceImpl.class);
}

jeremie
> ...
>
> plus de détails »

IvanoBulo

unread,
Jul 20, 2010, 5:03:11 PM7/20/10
to google-guice
Because you've specified "annotatedWith(ToDot.class)". But when you
getting instance through injector, as a key you are using an interface
only.

You may try:

class Test {
@Inject @ToDot
IDrawGraphService drawDotService;

public Test () {
Injector drawGraphInjector = Guice.createInjector(new DrawModule());
drawGraphInjector.injectMembers(this);

drawDotService.draw(); ///or whatever

}
}

- Ivan

Jerem's

unread,
Jul 21, 2010, 5:31:26 AM7/21/10
to google-guice
hmm no. I delete the "annotatedWith(ToDot.class)". so I don't use
anotation,

My main class look like that :

public static void main(String[] args) {
Injector demoInjector = Guice.createInjector(new DemoModule());
Injector clientInjector = Guice.createInjector(new ClientModule());
ISimpleGraph demo = demoInjector.getInstance(ISimpleGraph.class);
IClient client = clientInjector.getInstance(IClient.class);

System.out.println("Drawing graph...");
try {
client.executeService(demo, DrawGraphType.DOT, "demo.dot");
client.executeService(demo, DrawGraphType.TEXT, "demo.txt");
} catch (IOException e) {
System.out.println("failed !!!");
System.out.println(e);
e.printStackTrace();
}
System.out.println("Done.");

}

Jeremie

Sam Berlin

unread,
Jul 21, 2010, 9:38:05 AM7/21/10
to google...@googlegroups.com
On Wed, Jul 21, 2010 at 5:31 AM, Jerem's <dark...@gmail.com> wrote:
hmm no. I delete the "annotatedWith(ToDot.class)". so I don't use
anotation,

My main class look like that :

       public static void main(String[] args) {
               Injector demoInjector = Guice.createInjector(new DemoModule());
               Injector clientInjector = Guice.createInjector(new ClientModule());
               ISimpleGraph demo = demoInjector.getInstance(ISimpleGraph.class);
               IClient client = clientInjector.getInstance(IClient.class);

Is this the same main class you're using where you said you saw errors using MapBinder?  Are you installing the module with the MapBinder bindings in DemoModule or ClientModule?  Why are you using two different Injectors?

sam

 

Jerem's

unread,
Jul 21, 2010, 10:56:09 AM7/21/10
to google-guice
hmm maybe there few thibgs I have not understood yes about guice.

I have One injector per module.
But I don"t understand what do you mean by installing module....?
what do you mean by "installing?
yes it is that main class where I saw errors.

I Don't think I have install anything, so it must be my error.

Jérémie

On 21 juil, 15:38, Sam Berlin <sber...@gmail.com> wrote:
> > google-guice...@googlegroups.com<google-guice%2Bunsubscribe@google groups.com>
> > .

Colin Decker

unread,
Jul 21, 2010, 11:01:20 AM7/21/10
to google...@googlegroups.com
You should be using one Injector, total. That's a core part of how Guice works. Add all your Modules to this single injector:

   Injector injector = Guice.createInjector(new DemoModule(), new ClientModule());

Colin

To unsubscribe from this group, send email to google-guice...@googlegroups.com.

Jerem's

unread,
Jul 21, 2010, 12:18:34 PM7/21/10
to google-guice
It is good :)

I just do that in the main class :

Injector injector = Guice.createInjector(new DemoModule(), new
ClientModule(), new DrawModule());

and now, it works ^^

thanks a lot to every one for your precious help.


jérémie

Moandji Ezana

unread,
Jul 21, 2010, 5:04:18 PM7/21/10
to google...@googlegroups.com
On Tuesday, July 20, 2010, Jerem's <dark...@gmail.com>

> @ToDot
> IDrawGraphService drawDotService =
> drawGraphInjector.getInstance(IDrawGraphService.class);
>
> @ToText
> IDrawGraphService drawTextService =
> drawGraphInjector.getInstance(IDrawGraphService.class);
>

Maybe I'm missing something obvious, but if the client is deciding
which implementation to get, then why not just ask for it:


IDrawGraphService drawTextService =
drawGraphInjector.getInstance(DrawTextService.class)

Seems less convoluted and safer than MapBinder.

Moandji

Reply all
Reply to author
Forward
0 new messages