Help understanding @Inject (doesn't inject unless I use injector.getInstance())

73 views
Skip to first unread message

infinity2heaven

unread,
Mar 2, 2010, 6:40:50 PM3/2/10
to google-guice
New to guice.

public interface Template {
foo();
}

public class SomeTemplate implements Template {
@Inject
public SomeTemplate (Session session){
this.session = session;
}

public foo() {
// do something
}
}

// Module with bindings
public class TemplateModule extends AbstractModule {

@Override
protected void configure() {
bind(Session.class).toInstance(session);
bind(Template.class).to(SomeTemplate.class);
}

public static class Builder {
private Session session;

public TemplateModule buildModule() {
return new TemplateModule(session);
}

public Builder withSession(String session) {
this.session = session;
return this;
}
}
}

// JUnt 4.4 test
public class TemplateTest {

@Inject
Template template; // doesn't inject!

@BeforeClass
public static void init() throws Exception {
injector = Guice.createInjector(new
TemplateModule.Builder().withSession(new Session()));
// template= injector.getInstance(Template.class); // template is
initialized if this is uncommented
}

@Test
public void testFoo() {
template.foo(); // NullPointerException
}

}

What is wrong with the above code? Why doesn't @Inject automatically
inject the template instance variable? It seems redundant (and
limited) that I have to yet again use Injector.getInstance, each time
I need to access the template object. I'm sure doing something wrong
here ...

Sam Berlin

unread,
Mar 2, 2010, 7:15:38 PM3/2/10
to google...@googlegroups.com
There's no instruction to the Injector telling it to Inject the
instance of your TemplateTest class. If you add an additional module
to the Injector, something like:

new AbstractModule() { public void configure() { requestInjection(this); } }

then Guice will know to process @Inject methods/variables within
TemplateTest too.

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.
>
>

infinity2heaven

unread,
Mar 2, 2010, 10:31:39 PM3/2/10
to google-guice
Not sure if I follow since I'm already creating a Guice Module and
starting it in the Test class. Let's see if I can summarize it better:

1) TemplateModule binds an implementing class
bind(Template.class).to(SomeTemplate.class);

2) created a TemplateModule and initialized it in the Test Class
injector = Guice.createInjector(new
TemplateModule.Builder().withSession(new Session()).buildModule());

3) The same Test class has a @inject Template template

Why is it not injected?

From your answer, it looks like I have to create one module per class
where @inject is present. That seems incorrect to me.

Eelco Hillenius

unread,
Mar 2, 2010, 10:46:30 PM3/2/10
to google...@googlegroups.com
> Why is it not injected?

Because Guice is not in charge of creating your test class instances.
So you either have to explicitly ask it to inject for you, get a
reference yourself by using the injector, or use something like
AtUnit: http://code.google.com/p/atunit/wiki/SupportedContainers

Eelco

infinity2heaven

unread,
Mar 3, 2010, 12:34:21 AM3/3/10
to google-guice
Got it. Wasn't quite intuitive in the beginning but it seems like a
"Module" is analogous to a <bean-id> in spring. So if you have 25
beans that refers a single bean, "foo", you have a reference for foo
in all those beans. However, to reduce the boilerplate code, Spring
provides autowire(byType or byName). Is there a similar feature in
Guice.

AtUnit looks cool; will check it out. Meanwhile, I added this in the
@BeforeClass in my unit test

injector = Guice.createInjector(new
TemplateModule.Builder().withSession(new Session()).buildModule(),
new AbstractModule() {
@Override
public void configure() {
requestInjection(this);
}});


On running the debugger, I can see that template is initialized after
createInjector. However, my test (@Test) method still has a null
reference.

Strange, right? Am I missing something?

Dhanji R. Prasanna

unread,
Mar 3, 2010, 12:50:20 AM3/3/10
to google...@googlegroups.com
On Wed, Mar 3, 2010 at 4:34 PM, infinity2heaven <impalp...@gmail.com> wrote:
Got it. Wasn't quite intuitive in the beginning but it seems like a
"Module" is analogous to a <bean-id> in spring.

No, it's more like the entire xml file.
 
So if you have 25
beans that refers a single bean, "foo", you have a reference for foo
in all those beans. However, to reduce the boilerplate code, Spring
provides autowire(byType or byName). Is there a similar feature in
Guice.

Actually, you can think of everything in Guice as being "Autowired". Strictly speaking, if you have no interfaces, you don't need any modules and can just call getInstance() on any class directly, so long as the appropriate @Inject annotations are present.

You would have the same problem in Spring with the test not being injected. The problem is that your test is created by Junit, rather than by Guice, and Junit knows nothing about injection.

Dhanji.

Eelco Hillenius

unread,
Mar 3, 2010, 1:02:32 AM3/3/10
to google...@googlegroups.com
> injector = Guice.createInjector(new
> TemplateModule.Builder().withSession(new Session()).buildModule(),
>   new AbstractModule() {
>        @Override
>        public void configure() {
>                requestInjection(this);
>    }});

This doesn't work because requestInjection(this) requests injection of
your anonymous module
and because @BeforeClass can only be used on a static method, so there
is no 'this' for your unit test.

I think adding a method with @Before and then
requestInjection(YourTest.this) should work. Or you could use
requestStaticInjection instead. Or, what I would do frankly, don't
bother and just get your instance from the injector when you need it.

Eelco

infinity2heaven

unread,
Mar 3, 2010, 4:29:32 AM3/3/10
to google-guice
Thanks Eelco, I figured the anonymous inner class accessing an object
reference, and while fixing it, your suggestion of using
requestStaticInjection solves my problem.

Dhanji:
I still don't understand how autowire is "by default" in Guice. In the
example I mentioned, I have to create n modules for each Class
referencing template variable. Agreed, the following code

new AbstractModule() {
@Override
public void configure() {

requestStaticInjection (this);
}});

would inject the reference in the static instance, but that means I
have to write the same boilerplate code for every test, ie, every
class that has @Inject Template template.

@Inject is a Guice annotation and I expect it to be smart to figure
out (autowire) the binding.

As I understand now, this is not the case.

Dhanji R. Prasanna

unread,
Mar 3, 2010, 4:35:23 AM3/3/10
to google...@googlegroups.com
On Wed, Mar 3, 2010 at 8:29 PM, infinity2heaven <impalp...@gmail.com> wrote:
Thanks Eelco, I figured the anonymous inner class accessing an object
reference, and while fixing it, your suggestion of using
requestStaticInjection solves my problem.

Dhanji:
I still don't understand how autowire is "by default" in Guice. In the
example I mentioned, I have to create n modules for each Class
referencing template variable. Agreed, the following code

new AbstractModule() {
       @Override
       public void configure() {
               requestStaticInjection (this);
}});

would inject the reference in the static instance, but that means I
have to write the same boilerplate code for every test, ie, every
class that has @Inject Template template.

It will work for non-static members, with just @Inject. Static injection is not really intended to be used except in very rare cases like serialization.

The thing you need a module for is to couple interfaces to implementations so Guice can tell which implementation to use when you refer to Template (assuming it is an interface), for example XmlTemplate or HtmlTemplate. And if you use @ImplementedBy on the interface, you don't need modules at all.

Dhanji.

Colin Decker

unread,
Mar 3, 2010, 8:09:39 AM3/3/10
to google-guice
Tests are definitely not the best place to be learning how Guice works. Specifically, you shouldn't be attempting to inject things into JUnit test classes (instances of which are created for you by JUnit) and basing your understanding of Guice on your experience with that, considering that Guice making instances of classes for you is the very core of how it works, and it can't do it in that case.

Your understanding of Modules as analogous to Spring bean IDs is not correct. Modules are units of configuration... they define groups of related bindings, similar to what you might put in a single Spring XML file. Guice then autowires by providing @Inject annotated fields, methods and constructors with instances of the type they require according to the defined bindings. If you were using the module from your sample code, in an application, everywhere Guice saw "@Inject public MyClass(Template template)", for example, it would create an instance of SomeTemplate, providing it with the Session object, and then pass that SomeTemplate to the MyClass constructor as its Template.

If you need more than one kind of binding for Template, you use binding annotations (see http://code.google.com/p/google-guice/wiki/BindingAnnotations). The combination of type (i.e. Template) and binding annotation is called a key and is what determines what should be injected where... that is the analog to the ID of a bean in Spring.

Also important to note is that in any given application, modules and Guice.createInjector() should only be called once, at the application entry point. Some root application object should then be retrieved from the Injector and used to start the application. When Guice needs to get the instance of that application object, it will inject its dependencies (and the dependencies of those objects, etc.) based on the configuration in the modules.

To extend your initial example, imagine an application like this:

class Application {
  TemplateClient1 client1;
  TemplateClient2 client2;

  @Inject Application(TemplateClient1 client1, TemplateClient2 client2) {
    this.client1 = client1;
    this.client2 = client2;
  }

  void start() { ... }
}

Where TemplateClient1 and TemplateClient2 are two classes with a constructor like

@Inject TemplateClient1(Template template) { ... }

Then you bootstrap the application:

class Main {
  public static void main(String[] args) {
    Injector injector = Guice.createInjector(new TemplateModule.Builder()
      .withSession(new Session()).buildModule());

    Application app = injector.getInstance(Application.class);
    app.start();
  }
}

Since Application, TemplateClient1 and TemplateClient2 are concrete classes, we don't even need to write any binding for them. The Application object retrieved from the injector here will have its client1 and client2 fields, and those objects will each have an instance of TemplateImpl as their template, and each of those instances of TemplateImpl will have the Session object that was bound in the module.

I'd advise working on some simple application like the above to help you understand how Guice works, and also reading more of the user's guide.

Colin

bklough

unread,
Mar 3, 2010, 1:00:54 PM3/3/10
to google-guice
Perhaps I missed something, but I believe all you need is:

injector.injectMembers(this);

in your test class right after acquiring the injector instance (before
the commented template = injector.getInstance(...) line). This will
fullfil the injection requests in the test itself. I use a base test
class that does the equivalent for injecting loggers, Sessions, etc..,
so there shouldn't be a ton of boilerplate.

David Stanek

unread,
Mar 3, 2010, 1:37:45 PM3/3/10
to google...@googlegroups.com
On Wed, Mar 3, 2010 at 1:00 PM, bklough <bkl...@comcast.net> wrote:
> Perhaps I missed something, but I believe all you need is:
>
>    injector.injectMembers(this);
>
> in your test class right after acquiring the injector instance (before
> the commented template = injector.getInstance(...) line).  This will
> fullfil the injection requests in the test itself.  I use a base test
> class that does the equivalent for injecting loggers, Sessions, etc..,
> so there shouldn't be a ton of boilerplate.
>

Is using an injector in tests common practice? I would have thought
that hand wiring would be more popular.

--
David
blog: http://www.traceback.org
twitter: http://twitter.com/dstanek

bklough

unread,
Mar 3, 2010, 2:00:31 PM3/3/10
to google-guice
Depends upon what's being tested, I guess. I do both: 'hard-wire' if
necessary testing Providers and their support innards; inject into the
Integration tests to verify all the underlying wiring is as it should
be. If I'm testing my framework against multiple 3rd party components
(Various JMS providers, for instance) for compatibility and/or
performance, then definitely I'm injecting into tests; ditto for
different Transaction, Session management, Thread related, etc..
strategies. I'm sure there's a gazillion different answers for this
question. :-)


On Mar 3, 10:37 am, David Stanek <dsta...@dstanek.com> wrote:

bklough

unread,
Mar 3, 2010, 2:11:04 PM3/3/10
to google-guice
BTW infinity2heaven: If you're in the early stages and haven't picked
it up, I highly/strongly/seriously recommend Prasanna's "Dependency
Injection" Manning book. The core of DI isn't about Guice, Spring,
Hivemind, or whatever injection framework: it's about the nuts and
bolts of modularity. This book does a great job highlighting that.
IMHO, of course. Just saying. ;-)

Reply all
Reply to author
Forward
0 new messages