On 2 Nov 2011, at 22:01, Jeff wrote:
> Is the @Singleton scope based on the instance of the Injector being used?
>
> I have two classes that aren't getting injected. One is a static factory
> class (ThreadResourceFactory). The other is a class that the factory
> instantiates for me (ThreadResource).
>
> In my TestNG @BeforeClass method, I call ThreadResourceFactory.get() to
> retrieve an instance of ThreadResource for the current TestNG test thread.
>
> Since I couldn't figure out a way to retrieve the injector previously created
> by TestNG, I did the following in the ThreadResource constructor:
>
> Guice.createInjector(new MyModule()).injectMembers(this);
>
> This works sort of, but because I create another injector, it seems to be
> managing another set of @Singletons for that new Injector instance.
Correct, @Singleton's are per-binding, per-injector - if you bind A.class to
Singleton scope in two different injectors, you'll get two different instances
> I'm sure there is a better way to do this, I am just unsure how. Any
> suggestions?
You could always request static injection for the ThreadResourceFactory class
in your module:
@Override public void configure() {
requestStaticInjection(ThreadResourceFactory.class);
// ...
}
You could then have a setter method in ThreadResourceFactory (marked with
@Inject) that accepts Injector - this wouldn't be thread-safe because of the
static-ness, but that might not be an issue if you're running tests
sequentially. Alternatively you could @Inject the Injector or the
ThreadResourceFactory in a base test class that you then extend for all your
tests.
> On Fri, Oct 28, 2011 at 11:51 AM, Stuart McCulloch <[email protected]> wrote:
> On 28 Oct 2011, at 18:43, Jeff wrote:
>
>> Thanks for the great info and helping me work things out. The fog is
>> clearing.
>>
>> Since my language provider depends on the environment, is it kosher to do
>> something like:
>> @Provides @Named("ENV") @Singleton
>> public Properties EnvironmentProvider() {
>> //setup env
>> return env;
>> }
>>
>> @Provides @Named("LANG") @Singleton @Inject
> ^ you shouldn't need @Inject here since every parameter in a @Provides method
> will always be injected
>
>> public Properties LanguageProvider(@Named("ENV") Properties env) {
>> //load language files based on lang setting in env
>> return lang;
>> }
>> And if I mark these as @Singleton, am I the one that needs to store and
>> manage the instance or does Guice cache the object returned for lang and env
>> and never call this method directly again?
>
> Guice will apply the scoping around the @Provides method, so you don't need
> cache the result yourself
>
>> On Fri, Oct 28, 2011 at 6:32 AM, Stuart McCulloch <[email protected]> wrote:
>> On 27 Oct 2011, at 21:12, Jeff wrote:
>>
>>> The classes containing the injected fields are TestNG test classes. I am
>>> creating the Injector using the ServiceLoader mechanism within a class that
>>> implements org.testng.ISuiteListener. TestNG automatically picks up and
>>> runs the onStart() method before doing anything else and I call
>>> createInjector() there.
>>>
>>> Though, I think I just realized my problem (besides trying to learn/use
>>> Guice from within another framework I'm also just learning).
>>>
>>> The key bit I had not grasped previously was that for Guice/@Inject to
>>> work, object instantiation must be done directly by Guice
>>> (Injector.getInstance()), at least for the root node of the object graph (I
>>> think).
>>>
>>> Since TestNG instantiates classes without Guice by default, it was just
>>> creating normal instances and the @Inject annotations weren't getting
>>> processed.
>>>
>>> TestNG does support Guice via @Test(guiceModule = MyModule.class)
>>> annotation, but I wanted to avoid the need to put this on EVERY test class
>>> and thought I could insert my Modules/Providers and enable my custom
>>> bindings to work globally.
>>>
>>> I'm still playing with my code, but I feel like I'm on the right track.
>>> Can anyone confirm or help me understand if there is a different way?
>>
>> Yes, either the root of the object graph needs to be instantiated by Guice
>> or you need to use injectMembers(...) to inject an existing instance (in
>> which case you can't use constructor injection in that particular class). Of
>> course one benefit of putting @Test(guiceModule=...) on each test class (or
>> @Guice in the latest version:
>> http://testng.org/doc/documentation-main.html#guice-dependency-injection) is
>> that it documents that you're using dependency injection for that test, and
>> with modern IDEs it's not too hard to add this automatically or use a
>> template. Also note the latest release of TestNG supports module factories
>> so you could use the same factory across all your tests:
>> http://testng.org/javadocs/org/testng/IModuleFactory.html
>>
>>> Thanks!!
>>>
>>> On Thu, Oct 27, 2011 at 5:40 AM, Stuart McCulloch <[email protected]> wrote:
>>> On 27 Oct 2011, at 06:14, Jeff wrote:
>>>
>>>> I want to do something like:
>>>> @Inject @Named("conf")
>>>> Properties config;
>>>>
>>>> @Inject @Named("lang")
>>>> Properties language;
>>>> Where these objects are singletons initialized once at runtime with
>>>> environment-specific information.
>>>>
>>>> I've tried various things and none result in my Provider or @Provides
>>>> methods getting called. Here is a trimmed down version of my code using a
>>>> Provider class:
>>>>
>>>> MyModule.java:
>>>> public class SeleniumInjectionModule extends AbstractModule {
>>>> @Override
>>>> protected void configure() {
>>>>
>>>> bind(Properties.class).annotatedWith(Names.named("conf")).toProvider(ConfigProvider.class);
>>>>
>>>> bind(Properties.class).annotatedWith(Names.named("lang")).toProvider(LanguageProvider.class);
>>>> }
>>>> }
>>>> ConfigProvider.java:
>>>> @Singleton
>>>> public class ConfigProvider implements Provider<Properties> {
>>>> private final Properties config = new Properties();
>>>>
>>>> public ConfigProvider() {
>>>> //Load properties file based on 'config' system property value set in
>>>> Maven profile
>>>> ...
>>>> config.load(...);
>>>> ...
>>>> }
>>>> @Override
>>>> public Properties get() {
>>>> return config;
>>>> }
>>>> }
>>>>
>>>> LanguageProvider.java:
>>>> @Singleton
>>>> public class LanguageProvider implements Provider<Properties> {
>>>> private final Properties lang = new Properties();
>>>>
>>>> public LanguageProvider() {
>>>> //Load properties file based on 'language' system property value set
>>>> in Maven profile
>>>> ...
>>>> lang.load(...);
>>>> ...
>>>> }
>>>> @Override
>>>> public Properties get() {
>>>> return lang;
>>>> }
>>>> }
>>>> In my Global Init code:
>>>> Guice.createInjector(new MyModule());
>>>>
>>>> What am I missing?
>>>
>>> Where's the class containing the injected config/language fields mentioned
>>> in the start of this email?
>>>
>>> Assuming that class is called Foo then you need to use
>>> injector.getInstance(Foo.class) - or injector.injectMembers(myFoo) if you
>>> already have an instance of Foo - to start the injection process and inject
>>> those fields. Note that you don't need to do this for everything, just the
>>> class at the beginning of the injection graph to kick things off.
>>>
>>>> --
>>>> Jeff Vincent
>>>> [email protected]
>>>> See my LinkedIn profile at:
>>>> http://www.linkedin.com/in/rjeffreyvincent
>>>> I ♥ DropBox !!
>>>>
>>>>
>>>> --
>>>> You received this message because you are subscribed to the Google Groups
>>>> "google-guice" group.
>>>> To post to this group, send email to [email protected].
>>>> To unsubscribe from this group, send email to
>>>> [email protected].
>>>> 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 [email protected].
>>> To unsubscribe from this group, send email to
>>> [email protected].
>>> For more options, visit this group at
>>> http://groups.google.com/group/google-guice?hl=en.
>>>
>>>
>>>
>>> --
>>> Jeff Vincent
>>> [email protected]
>>> See my LinkedIn profile at:
>>> http://www.linkedin.com/in/rjeffreyvincent
>>> I ♥ DropBox !!
>>>
>>>
>>> --
>>> You received this message because you are subscribed to the Google Groups
>>> "google-guice" group.
>>> To post to this group, send email to [email protected].
>>> To unsubscribe from this group, send email to
>>> [email protected].
>>> 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 [email protected].
>> To unsubscribe from this group, send email to
>> [email protected].
>> For more options, visit this group at
>> http://groups.google.com/group/google-guice?hl=en.
>>
>>
>>
>> --
>> Jeff Vincent
>> [email protected]
>> See my LinkedIn profile at:
>> http://www.linkedin.com/in/rjeffreyvincent
>> I ♥ DropBox !!
>>
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "google-guice" group.
>> To post to this group, send email to [email protected].
>> To unsubscribe from this group, send email to
>> [email protected].
>> 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 [email protected].
> To unsubscribe from this group, send email to
> [email protected].
> For more options, visit this group at
> http://groups.google.com/group/google-guice?hl=en.
>
>
>
> --
> Jeff Vincent
> [email protected]
> See my LinkedIn profile at:
> http://www.linkedin.com/in/rjeffreyvincent
> I ♥ DropBox !!
>
>
> --
> You received this message because you are subscribed to the Google Groups
> "google-guice" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to
> [email protected].
> 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 [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/google-guice?hl=en.