Re: Help with the basics - Injecting field in a new class

150 views
Skip to first unread message

Thomas Broyer

unread,
Apr 10, 2013, 7:15:28 PM4/10/13
to google...@googlegroups.com
Dependency Injection 101: only objects created by the DI container (Guice in this case) are injected; this means only objects that have been retrieved from the Injector (through its getInstance method generally) or have themselves been injected into other classes. It's possible to inject objects that you 'new' yourself (or more generally have not been created by Guice itself), but again it has to be explicit: https://code.google.com/p/google-guice/wiki/Injections#On-demand_Injection

On Thursday, April 11, 2013 12:21:20 AM UTC+2, Newbie McBozo wrote:
I'm working with an application that uses Guice.

I know nothing about guice, and parsing the documentation for my particular situation hasn't been easy.

I have a java class.  That class needs an object provided by the application.

If I subclass an application provided class and override it's binding, obtaining the object is a matter of
@Inject
AppObject ao

Within my own classes, if I try that, the injected object is null.

How do I set up my own classes so that when I instantiate them, the injected fields are resolved?

I imagine that I need to bind my class, but I'm having difficulty figuring it how to do that without spending time learning way more about Guice than this fairly simple (and I imagine common) situation really should require.

David Stanek

unread,
Apr 10, 2013, 9:18:07 PM4/10/13
to google...@googlegroups.com

On Wed, Apr 10, 2013 at 8:09 PM, Newbie McBozo <kall...@gmail.com> wrote:
I get that, and forgive me for being dense, but I don't get how to make it so that my class is created by Guice so that my injections will work.

I see that the application provides a module that's called on startup.  Within that module I see a series of functions that call binder.bind and in all of those classes I see that injection works.

Looking at that, I would think that I could binder.bind my own class but that doesn't seem to work.  I could have syntax issues, but my sense is that there's a fundamental thing that I'm missing. 
 

Are you using the injector to create the instance of your object?  Do you have a code sample?

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

Cédric Beust ♔

unread,
Apr 10, 2013, 9:30:11 PM4/10/13
to google...@googlegroups.com
On Wed, Apr 10, 2013 at 5:09 PM, Newbie McBozo <kall...@gmail.com> wrote:
I get that, and forgive me for being dense, but I don't get how to make it so that my class is created by Guice so that my injections will work.

This is the first thing you need to fix. If you can't get Guice to instantiate these objects, then they can't be injected.

-- 
Cédric

Stephan Classen

unread,
Apr 11, 2013, 2:27:12 AM4/11/13
to google...@googlegroups.com
If your factory method has no arguments it is easier to remove the factory and have guice inject a Provider<MyClass> instead of the factory

see: http://code.google.com/p/google-guice/wiki/InjectingProviders


On 04/11/2013 04:33 AM, Newbie McBozo wrote:
Thanks for your help guys, I figured it out.

The way I attacked this was this:

I created a factory interface.  I then added a line to the configure function of the module:

binder.install(new FactoryModuleBuilder().build(MyClassFactory.class));

rather than calling "new" for new instances of the class, I inject a  factory and call MyClassFactory.create().

I'm not explaining it very well, but my code is working.  The variables that I was trying to inject are now resolving appropriately.


On Wednesday, April 10, 2013 5:09:25 PM UTC-7, Newbie McBozo wrote:
I get that, and forgive me for being dense, but I don't get how to make it so that my class is created by Guice so that my injections will work.

I see that the application provides a module that's called on startup.  Within that module I see a series of functions that call binder.bind and in all of those classes I see that injection works.

Looking at that, I would think that I could binder.bind my own class but that doesn't seem to work.  I could have syntax issues, but my sense is that there's a fundamental thing that I'm missing. 

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

Christian Gruber

unread,
Apr 11, 2013, 3:06:25 AM4/11/13
to google...@googlegroups.com
It is easier, but please don't. While the two are practically similar,
it is a design obfuscation to inject a Provider<Foo> merely to serve as
a factory of Foo. Provider is an internal type to Guice/DI, whereas a
factory is class that manages value types and domain objects.

It is technically valid to do this, but it starts to conflate the kinds
of objects in your system and can lead to increased mess.

Injecting Provider<Foo> is advisable for crossing barriers where you
cannot properly scope objects because of limitations of legacy
platforms, etc., or to defer construction for optimization. But if you
have classes that you need created frequently and you need new
instances, consider keeping them as factory managed.

I tend to divide my code into Collaborators/Services, Configuration, and
Value-Types/consumables. The former I inject, the latter I create with
Factories. I admit this is merely an opinion. Stephan is not wrong,
but I think it's inadvisable to use Provider<T> as a factory merely
because it has a no-args get() method which is similar to create().

Christian.
Christian Gruber :: Google, Inc. :: Java Core Libraries :: Dependency
Injection
email: cgr...@google.com :::: mobile: +1 (646) 807-9839

Peter Reilly

unread,
Apr 11, 2013, 4:32:00 AM4/11/13
to google...@googlegroups.com
I totally disagree. Provider<X> a, a.get(), is the correct replacement for new X();

Peter




To post to this group, send email to google...@googlegroups.com.
Visit this group at http://groups.google.com/group/google-guice?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.



--
You received this message because you are subscribed to the Google Groups "google-guice" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-guice+unsubscribe@googlegroups.com.

To post to this group, send email to google...@googlegroups.com.
Visit this group at http://groups.google.com/group/google-guice?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
Christian Gruber :: Google, Inc. :: Java Core Libraries :: Dependency Injection
email: cgr...@google.com :::: mobile: +1 (646) 807-9839
--
You received this message because you are subscribed to the Google Groups "google-guice" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-guice+unsubscribe@googlegroups.com.

Tim Peierls

unread,
Apr 11, 2013, 7:14:49 AM4/11/13
to google...@googlegroups.com
Are you talking about com.google.inject.Provider or javax.inject.Provider or both?

Calling javax.inject.Provider an internal type seems a bit harsh.

--tim


To post to this group, send email to google...@googlegroups.com.
Visit this group at http://groups.google.com/group/google-guice?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.



--
You received this message because you are subscribed to the Google Groups "google-guice" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-guice+unsubscribe@googlegroups.com.

To post to this group, send email to google...@googlegroups.com.
Visit this group at http://groups.google.com/group/google-guice?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
Christian Gruber :: Google, Inc. :: Java Core Libraries :: Dependency Injection
email: cgr...@google.com :::: mobile: +1 (646) 807-9839
--
You received this message because you are subscribed to the Google Groups "google-guice" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-guice+unsubscribe@googlegroups.com.

Stuart McCulloch

unread,
Apr 11, 2013, 7:32:25 AM4/11/13
to google...@googlegroups.com
Note that Provider<X> is not guaranteed to always return a new instance, it depends on the scope of the binding behind it.

If X has been bound as a singleton in the injector then you'll always get the same instance returned from Provider<X>.get().

To unsubscribe from this group and stop receiving emails from it, send an email to google-guice...@googlegroups.com.

Cédric Beust ♔

unread,
Apr 11, 2013, 12:18:22 PM4/11/13
to google...@googlegroups.com
To me, Provider should only be used if, in order to create the instance, you need some additional information that's not available at the very beginning of the application, when Guice establishes all the bindings. From this standpoint, @Inject and providers are not really interchangeable:
  • @Inject: the instance can be created at startup
  • Provider: the instance needs information only available after Guice has created the module
  • Assisted injection: the instance needs a mix of runtime parameters and injected dependencies
And these days, I'm more and more thinking toward removing Providers completely and using assisted injections everywhere, even when all the parameters to the factory are @Assisted since it's quite likely that, as the code evolves, it will end up needing some injected dependencies, so since I will end up having to convert these providers into assisted factories anyway, I might just go ahead and go there directly.

I have settled on a pattern that looks like this:

class Foo {
  // Assisted injection
  public interface IFactory {
    Foo create(Person p);
  }

  @Inject
  private Foo(@Assisted Person p, InjectedResource resource1) {
    ...
  }
}

And whenever I need a Foo:

  @Inject
  private Foo.IFactory factory;

  foo = factory.create(person);

-- 
Cédric



-- 
Cédric

Christian Gruber

unread,
Apr 11, 2013, 2:41:48 PM4/11/13
to google...@googlegroups.com
Sorry - the wording is perhaps overstated. javax.inject.Provider is
merely a standardization of Guice's Provider in order to provide more
compatibility between different DI systems. They occupy the same space
in the design.

And I suppose it's not "internal" to Guice in that it is a public API,
but it is, nevertheless, a part of the DI mechanism. It is a part of
the framework itself rather than merely a signal like @Inject which, as
an annotation, is throw-away if you don't want to use it.

But more importantly, what it isn't is a generalized Factory interface
or pattern, though it bears a similarity to it. It also bears a
similarity to Supplier and any number of other "get me something"
patterns. My point is, it's distinct from the concept of Factory<T> or
Supplier<T> (or even Lazy<T> as Dagger has).

Christian.
>>> http://code.google.com/p/**google-guice/wiki/**InjectingProviders<http://code.google.com/p/google-guice/wiki/InjectingProviders>
>>>
>>>
>>> On 04/11/2013 04:33 AM, Newbie McBozo wrote:
>>>
>>>> Thanks for your help guys, I figured it out.
>>>>
>>>> The way I attacked this was this:
>>>>
>>>> I created a factory interface. I then added a line to the
>>>> configure
>>>> function of the module:
>>>>
>>>> binder.install(new FactoryModuleBuilder().build(**
>>>> MyClassFactory.class));
>>>>
>>>> rather than calling "new" for new instances of the class, I inject
>>>> a
>>>> factory and call MyClassFactory.create().
>>>>
>>>> I'm not explaining it very well, but my code is working. The
>>>> variables
>>>> that I was trying to inject are now resolving appropriately.
>>>>
>>>> On Wednesday, April 10, 2013 5:09:25 PM UTC-7, Newbie McBozo wrote:
>>>>
>>>> I get that, and forgive me for being dense, but I don't get how to
>>>> make it so that my class is created by Guice so that my injections
>>>> will work.
>>>>
>>>> I see that the application provides a module that's called on
>>>> startup. Within that module I see a series of functions that call
>>>> binder.bind and in all of those classes I see that injection works.
>>>>
>>>> Looking at that, I would think that I could binder.bind my own
>>>> class but that doesn't seem to work. I could have syntax issues,
>>>> but my sense is that there's a fundamental thing that I'm missing.
>>>>
>>>> On Wednesday, April 10, 2013 4:15:28 PM UTC-7, Thomas Broyer wrote:
>>>>
>>>> Dependency Injection 101: only objects created by the DI
>>>> container (Guice in this case) are injected; this means only
>>>> objects that have been retrieved from the Injector (through
>>>> its getInstance method generally) or have themselves been
>>>> injected into other classes. It's possible to inject objects
>>>> that you 'new' yourself (or more generally have not been
>>>> created by Guice itself), but again it has to be explicit:
>>>> https://code.google.com/p/**google-guice/wiki/Injections#**
>>>> On-demand_Injection<https://code.google.com/p/google-guice/wiki/Injections#On-demand_Injection>
>>>> <https://code.google.com/p/**google-guice/wiki/Injections#**
>>>> On-demand_Injection<https://code.google.com/p/google-guice/wiki/Injections#On-demand_Injection>
>>>> google-guice+unsubscribe@**googlegroups.com<google-guice%2Bunsu...@googlegroups.com>
>>>> .
>>>> To post to this group, send email to google...@googlegroups.com.
>>>> Visit this group at
>>>> http://groups.google.com/**group/google-guice?hl=en<http://groups.google.com/group/google-guice?hl=en>
>>>> .
>>>> For more options, visit
>>>> https://groups.google.com/**groups/opt_out<https://groups.google.com/groups/opt_out>
>>>> .
>>>>
>>>>
>>>>
>>> --
>>> You received this message because you are subscribed to the Google
>>> Groups
>>> "google-guice" group.
>>> To unsubscribe from this group and stop receiving emails from it,
>>> send an
>>> email to
>>> google-guice+unsubscribe@**googlegroups.com<google-guice%2Bunsu...@googlegroups.com>
>>> .
>>> To post to this group, send email to google...@googlegroups.com.
>>> Visit this group at
>>> http://groups.google.com/**group/google-guice?hl=en<http://groups.google.com/group/google-guice?hl=en>
>>> .
>>> For more options, visit
>>> https://groups.google.com/**groups/opt_out<https://groups.google.com/groups/opt_out>
>>> .
>>>
>>
>>
>> Christian Gruber :: Google, Inc. :: Java Core Libraries :: Dependency
>> Injection
>> email: cgr...@google.com :::: mobile: +1 (646) 807-9839
>>
>>
>> --
>> You received this message because you are subscribed to the Google
>> Groups
>> "google-guice" group.
>> To unsubscribe from this group and stop receiving emails from it,
>> send an
>> email to
>> google-guice+unsubscribe@**googlegroups.com<google-guice%2Bunsu...@googlegroups.com>
>> .
>> To post to this group, send email to google...@googlegroups.com.
>> Visit this group at
>> http://groups.google.com/**group/google-guice?hl=en<http://groups.google.com/group/google-guice?hl=en>
>> .
>> For more options, visit
>> https://groups.google.com/**groups/opt_out<https://groups.google.com/groups/opt_out>
>> .
>>
>>
>>
>
> --
> You received this message because you are subscribed to the Google
> Groups "google-guice" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to google-guice...@googlegroups.com.

Christian Gruber

unread,
Apr 11, 2013, 2:58:15 PM4/11/13
to google...@googlegroups.com
That's more or less where I'm at, Cedric.

That said, I'm also in favor of "new" for pure raw value types. There
are places where you don't need a seam for testing or for
modularity/decoupling, because you're dealing with something that you
are never going to sanely mock or stub or swap.

Pure value types that aren't used in any persistent configuration role
are examples of these for me. These should be newed and passed in on
the call stack, if needed.

Again, these are judgments, and your design will vary. We all develop
certain styles based on what pains we've felt in our prior applications.
For myself, when I see people injecting Provider<T> everywhere, it
suggests to me that they're either wanting a factory, or have
mis-aligned their scopes and which objects fall in which scopes.

Christian.

On 11 Apr 2013, at 11:18, Cédric Beust ♔ wrote:

> To me, Provider should only be used if, in order to create the
> instance,
> you need some additional information that's not available at the very
> beginning of the application, when Guice establishes all the bindings.
> From
> this standpoint, @Inject and providers are not really interchangeable:
>
> - @Inject: the instance can be created at startup
> - Provider: the instance needs information only available after Guice
> has created the module
> - Assisted injection: the instance needs a mix of runtime parameters
>>>> http://code.google.com/p/**google-guice/wiki/**InjectingProviders<http://code.google.com/p/google-guice/wiki/InjectingProviders>
>>>>
>>>>
>>>> On 04/11/2013 04:33 AM, Newbie McBozo wrote:
>>>>
>>>>> Thanks for your help guys, I figured it out.
>>>>>
>>>>> The way I attacked this was this:
>>>>>
>>>>> I created a factory interface. I then added a line to the
>>>>> configure
>>>>> function of the module:
>>>>>
>>>>> binder.install(new FactoryModuleBuilder().build(**
>>>>> MyClassFactory.class));
>>>>> On-demand_Injection<https://code.google.com/p/google-guice/wiki/Injections#On-demand_Injection>
>>>>> google-guice+unsubscribe@**googlegroups.com<google-guice%2Bunsu...@googlegroups.com>
>>>>> .
>>>>> To post to this group, send email to
>>>>> google...@googlegroups.com.
>>>>> Visit this group at
>>>>> http://groups.google.com/**group/google-guice?hl=en<http://groups.google.com/group/google-guice?hl=en>
>>>>> .
>>>>> For more options, visit
>>>>> https://groups.google.com/**groups/opt_out<https://groups.google.com/groups/opt_out>
>>>>> .
>>>>>
>>>>>
>>>>>
>>>> --
>>>> You received this message because you are subscribed to the Google
>>>> Groups "google-guice" group.
>>>> To unsubscribe from this group and stop receiving emails from it,
>>>> send
>>>> an email to
>>>> google-guice+unsubscribe@**googlegroups.com<google-guice%2Bunsu...@googlegroups.com>
>>>> .
>>>> To post to this group, send email to google...@googlegroups.com.
>>>> Visit this group at
>>>> http://groups.google.com/**group/google-guice?hl=en<http://groups.google.com/group/google-guice?hl=en>
>>>> .
>>>> For more options, visit
>>>> https://groups.google.com/**groups/opt_out<https://groups.google.com/groups/opt_out>
>>>> .
>>>>
>>>
>>>
>>> Christian Gruber :: Google, Inc. :: Java Core Libraries ::
>>> Dependency
>>> Injection
>>> email: cgr...@google.com :::: mobile: +1 (646) 807-9839
>>>
>>>
>>> --
>>> You received this message because you are subscribed to the Google
>>> Groups
>>> "google-guice" group.
>>> To unsubscribe from this group and stop receiving emails from it,
>>> send an
>>> email to
>>> google-guice+unsubscribe@**googlegroups.com<google-guice%2Bunsu...@googlegroups.com>
>>> .
>>> To post to this group, send email to google...@googlegroups.com.
>>> Visit this group at
>>> http://groups.google.com/**group/google-guice?hl=en<http://groups.google.com/group/google-guice?hl=en>
>>> .
>>> For more options, visit
>>> https://groups.google.com/**groups/opt_out<https://groups.google.com/groups/opt_out>
>>> .

Cédric Beust ♔

unread,
Apr 11, 2013, 3:44:03 PM4/11/13
to google...@googlegroups.com
On Thu, Apr 11, 2013 at 11:43 AM, Newbie McBozo <kall...@gmail.com> wrote:

I had 6 parameters required on instantiation, and one necessary injected variable that did not need to be private.  Rather than annotate 6 variables and have Guice add the 7th, I chose to simply inject the 7th as a member variable directly rather than in the constructor.

If you're not using assisted injection, then it looks like you must be instantiating your object by calling new yourself, which means your field will not get injected (unless you inject it manually after creation, which you should avoid).

Are you sure what you are describing works?

-- 
Cédric

Newbie McBozo

unread,
Apr 11, 2013, 4:17:43 PM4/11/13
to google...@googlegroups.com, ced...@beust.com
I probably wasn't clear enough.

By assisted injection, I was talking about something that looks like this:
==========
public interface MyClassFactory{
   public MyClass create(String myString);
}

public class MyClass{
   private String myString;
   private MyObject superThing;
   @Inject
   public MyClass(
@Assisted String myString, MyObject injectedThing){
     myString = myString;
     superThing = injectedThing;   
}

===========
When you call MyClassFactory.create("Something");

Guice provides the variable injectedThing to the constructor.

By not using assisted injection, I'm talking about this
==========
public interface MyClassFactory{
   public MyClass create(String myString);
}

public class MyClass{
   private String myString;
   @Inject
   MyObject superThing;

   @Inject
   public MyClass(
String myString){
     myString = myString;
}
==========
It's still assisted in a sense, but the field superThing isn't assigned via the constructor and I don't have to annotate myString with @Assisted to indicate that it's provided by the calling code.

I still create the object with MyClassFactory.create("Something");

And the end result still works the same.  It's really just a different way of going about it.  I don't know if it works for everyone in every situation, but field injection the way I did in the second example is what I see more commonly in the code I'm working with.  The @Inject notation on the constructor was something I missed entirely because it existed in base classes rather than the classes I was examining, and how the objects were being created was buried deep enough that I had a difficult time finding the code and figuring out how to do it myself.

My use of the term "Assisted Injection" was really centered around the fact that the first method is what shows up in the Guice docs and in a few websites that I found.

Cédric Beust ♔

unread,
Apr 11, 2013, 4:30:09 PM4/11/13
to google...@googlegroups.com
On Thu, Apr 11, 2013 at 1:17 PM, Newbie McBozo <kall...@gmail.com> wrote:

I still create the object with MyClassFactory.create("Something");

If MyClassFactory is instantiated by you and not Guice (through assisted injection), then the returned object will not have its fields injected, you might want to double check that.

-- 
Cédric

Newbie McBozo

unread,
Apr 11, 2013, 5:02:10 PM4/11/13
to google...@googlegroups.com, ced...@beust.com
Yep.  Within the calling class (which itself was created by guice) I have

@Inject
MyClassFactory mcf;


And then when I need one...

  MyClass myObj = mcf.create("Something");


I'm unsure of whether I can do that inject within the calling method, but I actually need the factory in a few methods, so having it in the calling class makes it easy.

If it wasn't working, I'd be receiving exceptions and I'd have some missing on-screen elements in the application.  I haven't written a lot of unit tests just yet, but on the surface things look sound.

Cédric Beust ♔

unread,
Apr 11, 2013, 5:17:57 PM4/11/13
to Newbie McBozo, google...@googlegroups.com
Oh so Guice is instantiating the factory, even if it's not using assisted injection. Then yes, this will work.


-- 
Cédric

Reply all
Reply to author
Forward
0 new messages