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.

Reply via email to