Suggested way of injecting static dependencies

7,818 views
Skip to first unread message

Patrick Bergner

unread,
Apr 27, 2010, 5:44:52 AM4/27/10
to google-guice
Hi, I'm new to Guice and lack experience in using it the suggested
(intended) way. I already figured out most of what I need to use Guice
in a relatively simple application and like it very much but one thing
is missing: injecting static dependencies.

I need this in classes that contain only static methods (a utility
class). For the sake of an example, think of a logger that should be
injected and be usable by the static methods. Let's say it looks like
this:

public class Utils {

@Inject private static Logger log;

public static void logFoo( Foo bar )
{
log.info( bar.toString() );
}

}

How do I inject the Logger correctly? My current approach is to use
"requestStaticInjection( Utils.class )" in my Guice module but,
according to the docs, this is discouraged. What other options do I
have?

Thanks for your help!

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

Willi Schönborn

unread,
Apr 27, 2010, 6:14:25 AM4/27/10
to google...@googlegroups.com
Patrick Bergner wrote:
> Hi, I'm new to Guice and lack experience in using it the suggested
> (intended) way. I already figured out most of what I need to use Guice
> in a relatively simple application and like it very much but one thing
> is missing: injecting static dependencies.
>
> I need this in classes that contain only static methods (a utility
> class). For the sake of an example, think of a logger that should be
> injected and be usable by the static methods. Let's say it looks like
> this:
>
> public class Utils {
>
> @Inject private static Logger log;
>
> public static void logFoo( Foo bar )
> {
> log.info( bar.toString() );
> }
>
> }
>
> How do I inject the Logger correctly? My current approach is to use
> "requestStaticInjection( Utils.class )" in my Guice module but,
> according to the docs, this is discouraged. What other options do I
> have?
>
Not using static classes/methods or at least trying to avoid them.
Just my two cents.

Greetings
Willi

Stuart McCulloch

unread,
Apr 27, 2010, 6:22:17 AM4/27/10
to google...@googlegroups.com
On 27 April 2010 17:44, Patrick Bergner <eir...@gmail.com> wrote:
Hi, I'm new to Guice and lack experience in using it the suggested
(intended) way. I already figured out most of what I need to use Guice
in a relatively simple application and like it very much but one thing
is missing: injecting static dependencies.

I need this in classes that contain only static methods (a utility
class). For the sake of an example, think of a logger that should be
injected and be usable by the static methods. Let's say it looks like
this:

public class Utils {

 @Inject private static Logger log;

 public static void logFoo( Foo bar )
 {
   log.info( bar.toString() );
 }

}

How do I inject the Logger correctly? My current approach is to use
"requestStaticInjection( Utils.class )" in my Guice module but,
according to the docs, this is discouraged.

It's the use of static dependencies that's discouraged rather than the
requestStaticInjection method itself. If you really need to inject static
dependencies then requestStaticInjection() is the way to go, but you
should also consider ways to avoid these static dependencies in the
first place (if possible).
 
What other options do I have?

Thanks for your help!

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


--
Cheers, Stuart

Christian Edward Gruber

unread,
Apr 27, 2010, 7:47:43 AM4/27/10
to google...@googlegroups.com
Yes, I would make your methods non-static, make the class instantiatable - if you MUST, make a singleton static factory method, but in your Guice-ified code, don't use the factory method - just inject it where you need it, and in its constructor, ask for the logger. If you use it outside of Guice, then crete the Logger and pass it in to the constructor in the factory method.

public class MyUtils {
  private final Logger logger;
  public MyUtils(Logger logger) {
    this.logger = logger;
  }

  ... code ...

  // 
  // STATIC SINGLETON INITIALIZER - DON'T USE THIS IF YOU 
  // CAN USE GUICE INSTEAD
  //
  private static final MyUtils instance = new MyUtils(Logger.getLogger(MyUtils.class.getName());
  public static MyUtils getInstance() {
    return instance;
  }
  // or some variation of the above - lazily created if necessary
}

I'd even avoid using this, because creating new MyUtils().doSomething() is really not that costly at run-time (if you're not bothering to use guice). It may not even make it into the heap if you don't let a reference to it escape so garbage collection is cheap-o.

Christian.

Jonathan Abourbih

unread,
Apr 27, 2010, 7:51:07 AM4/27/10
to google...@googlegroups.com
I'm also a bit new to Guice, but I'll give it a shot. One way to avoid the static injection would be to use an instance of the Utils class:

@Singleton
public class Utils
{
   private static Logger log;

   

   @Inject
   private TestStatic(Foo myFoo) {
     TestStatic.myFoo = myFoo;
   }

   

   public static void logFoo(Foo bar) {
     log.info(bar.toString());
   }
}

And when you initialise your injector, just include:

Injector injector = Guice.createInjector( new AbstractModule() {
      @Override
      protected void configure()
      {
        bind(Logger.class).to(ReallyCoolLogImplementation.class);
bind(Utils.class);
      }});
injector.getInstance(Utils.class); //force Guice to call the constructor

Now, when you use the Utils class anywhere else in your code, you can just call Utils.logFoo(myFoo). This seems like an awful lot of work though.

Jonathan

Patrick Bergner

unread,
Apr 27, 2010, 8:07:22 AM4/27/10
to google-guice
Thanks for your replies. They give me some idea of the "Guice way".
I'll make the utilities non-static and let Guice create the instance
for me.

Now, if you don't mind, give me a hint on this one: I have a Settings
object that is a wrapper for a settings.xml file. I instantiate it
using Guice. As reading the .xml takes time it should only happen once
during the execution of the program, but I need the values (that
should be accessed through the wrapper object once it has loaded
the .xml content) multiple times.

The trouble (in my head) now is that I cannot bind() an instance of
the Settings wrapper in my Guice module because I need the injector
that will be created using just this module for creating the instance.

How can this be adressed?

Sam Berlin

unread,
Apr 27, 2010, 8:16:31 AM4/27/10
to google...@googlegroups.com
Let me repeat the problem to see if I understand it.  You

a) Have some kind of SettingsXmlReader class that reads an XML file and requires dependencies from Guice passed to its constructor (or parameter methods).

b) Need to also tell Guice to bind the result of some of SettingsXmlReader's methods (let's say: SXR.getFoo & SXR.getBar) so that other objects created by Guice can have those injected.

Is that correct?

If so, you can use Provider bindings to accomplish what you want.  For example

class MyModule extends AbstractModule() {
  public void configure() {
     bind(SettingsXmlReader.class).in(Scopes.SINGLETON);
  }

  @Provides Foo foo(SettingsXmlReader sxr) {
      return sxr.getFoo();
   }

   @Provides Bar bar(SettingsXmlReader sxr) {
      return sxr.getBar();
    }
 }

That tells Guice that whenever something wants a 'Foo', it should call the 'foo' method in MyModule and for 'Foo' it'll hand off whatever that method returns.  Internally to Guice, it knows that the 'foo' method has a dependency on SettingsXmlReader, so it'll pass the SettingsXmlReader that is bound through Guice.  Same thing with Bar.

Sam

Patrick Bergner

unread,
Apr 27, 2010, 8:41:44 AM4/27/10
to google-guice
Thanks for your reply, Sam. With (a) you're absolutely right. However,
I'm not sure if I understood (b) correctly. From the way I understood
it the answer would be that that's not what I need. Let my try to
explain SettingsXmlReader a bit better:

(i) SettingsXmlReader has dependencies in its constructor that are
passed in by Guice.

(ii) SettingsXmlReader has a load() method that does the reading of
the actual .xml file. This takes time and should therefore only happen
once during application lifetime. The read settings are then stored in
a Map.

(iii) SettingsXmlReader has getXYZ() methods that shall return the
values of the .xml file once it has been read. These methods are
called multiple times from multiple classes.

The crux is that I only want to read the .xml once and need the
instance of SettingsXmlReader where the .xml has been read multiple
times in multiple classes.

What I wanted to do is bind(SettingsXmlReader.class).toInstance(sxr)
in my AppModule but in order to create the instance sxr I need the
injector created with AppModule (to resolve the dependencies
SettingsXmlReader has).

Maybe that's what you just explained and I did not get it yet.

Patrick

On Apr 27, 2:16 pm, Sam Berlin <sber...@gmail.com> wrote:
> Let me repeat the problem to see if I understand it.  You
>
> a) Have some kind of SettingsXmlReader class that reads an XML file and
> requires dependencies from Guice passed to its constructor (or parameter
> methods).
>
> b) Need to also tell Guice to bind the result of some of SettingsXmlReader's
> methods (let's say: SXR.getFoo & SXR.getBar) so that other objects created
> by Guice can have those injected.
>
> Is that correct?

Christian Edward Gruber

unread,
Apr 27, 2010, 8:42:46 AM4/27/10
to google...@googlegroups.com
Please don't do this - you're using a single static logger behind an instance variable, and using Logger quite differently than it's intended.  And what happens if someone doens't force the constructor... log is not initialized.  Or what if there are multiple injectors in the VM - now you have one instance of Logger taking precedence over the other.  

You should just let Utils be a normal class and have normal instances created.  It works wonderfully.  Games with statics are quite dangerous like that - especially statics that depend on state derived from instances' behaviour.

Christian.

Sam Berlin

unread,
Apr 27, 2010, 8:52:37 AM4/27/10
to google...@googlegroups.com
It looks like you're angling to tell Guice, "I only want a single instance of SettingsXmlReader."  That's what the Singleton annotation/scope is for.  You can either add @Singleton to the SettingsXmlReader implementation class or you can explicitly bind it as a singleton (see my above example that bound it as a singleton).  That tells Guice to only ever create one instance.

FWIW, if the classes that need the getXYZ() method are only injecting SettingsXmlReader in order to get the result of its getXYZ method, I recommend that you abstract away that dependency.  Classes should only ever inject their direct dependencies.  In this case, SettingsXmlReader isn't really a dependency -- it's just a stop on the way to the right dependency.  Let's say getXYZ returns a Map<String, Object> -- you can add a
  @Provides Map<String, Object> xyz(SettingsXmlReader sxr) { return sxr.getXYZ() }
to your module, and then classes will never need to know or care that the XYZ map is actually constructed by a settings reader.  That lets you write smarter tests (you can test your classes now without having to insert SXR into the mix) and is clearer when looking at the class about what it really needs.

(You can add niceties liked binding annotations, too.  For example the @Provides method could have a return signature of "@Provides @Named("SettingsMap") Map<String, Object>" and classes can inject a @Named("SettingsMap") Map<String, Object>.)

Sam

Patrick Bergner

unread,
Apr 27, 2010, 8:56:14 AM4/27/10
to google-guice
Thanks, Sam. Now I got your first explanation as well.

Great people around here! :-)
Reply all
Reply to author
Forward
0 new messages