Re: Quick question about providing values to a module

1,013 views
Skip to first unread message

Tim Boudreau

unread,
Apr 22, 2013, 6:59:16 AM4/22/13
to google...@googlegroups.com
I wrote a micro-framework for exactly that purpose - binding strings to contents from properties files, on top of another micro-framework for loading them without hard-coding paths (you can have system defaults in /etc/myapp.properties overlaid with ~/myapp.properties overlaid with ./myapp.properties and it takes care of binding them to @Named) - which might be helpful:
If you need values before the injector is created, you'll want to work directly with a Settings object (like a Properties without mutator methods - see the last javascript link), but you could just as easily write a Provider that uses @Named to get the string and initializes it on first use.

-Tim

Marshall Pierce

unread,
Apr 22, 2013, 10:25:32 AM4/22/13
to google...@googlegroups.com
An alternate approach might be to bind your "Settings" object and use a @Provides method in your PersistenceModule, like so:

public class PersistenceModule extends AbstractModule {

...

@Provides
Db4OStuff getDb4O(Settings settings) {
// use your settings
}
}

Or, you could just define a PersistenceModule constructor that has a Settings parameter if that's the time at which it's most convenient to work with the Settings object.

If you do wish to refactor your config access code away from your existing Settings class, Tim's Giulius looks simple and lightweight, though I happen to prefer are more strongly typed approach, so I'm currently enjoying using https://github.com/brianm/config-magic. I wrote a tiny wrapper around that to make it easy to use with Guice and any commons-config configuration source: https://github.com/palominolabs/config-inject.

No shortage of options for configuration handling… :)

Tim Boudreau

unread,
Apr 25, 2013, 5:44:36 PM4/25/13
to google...@googlegroups.com
I think there's a bit of chicken-and-egg confusion happening here - specifically:  Modules are things which set up bindings, which can *later* be used for injection.  The injector, which does the injecting, is *created* using the modules.

It looks like you are trying to get things injected *into* your module, which doesn't really make sense, because the injector that would do that doesn't exist yet, and won't exist until your module exists - by which time it is already constructed (yes, you could create an injector that creates some more modules and then create an injector over them so it's turtles all the way down, but these sorts of contortions become unreadable quickly).

Think of it this way:  Guice adds an explicit "initialization" phase to your application - think of it like running a meta-constructor for your whole application.  Modules' configure() methods are the code that runs inside that constructor.

If you need to load some configuration that will affect how things are bound - you need to pass some arguments into that "meta-constructor" - then you need some mechanism (such as reading a file, looking at environment variables, parsing command-line arguments - whatever suits you), but it's not going to be injection because the injector doesn't exist yet.

A straightforward form of this would be to do something like:
Properties p = //load some properties file
for (String key : p.stringPropertyNames()) {
   bind (String.class).annotatedWith(Names.named(key)).toInstance(p.getProperty(key));
   // or bindConstant or whatever
}

but has the nasty side-effect that if a property is missing from the file and some object needs it, a runtime exception will be thrown, probably when you don't expect it.  The library I pointed you at, at its heart, does more or less what the code above does, but with provisions for providing default values, standard filesystem locations for the file, automatic refresh, and ways to namespace classes or packages to load from different files/urls.

The point is, it sounds like you're looking for something to be injected into a module, but at the time your module is created, the injector does not exist - and while there might be hacky ways to convince Guice to do something like that, it's probably not a good idea - better to keep it simple.

-Tim

Thomas Broyer

unread,
Apr 27, 2013, 5:17:54 AM4/27/13
to google...@googlegroups.com

On Thursday, April 25, 2013 8:04:49 AM UTC+2, mmonti wrote:

Hi guys,

I really appreciate your replies. I took a look at both solutions Tim's micro-fwk and magic-config, but unfortunately I couldn't make it work, and also I am not sure if what i need. To be honest I think that I am pretty lost since I tried different ways to do it without success. Ill try to describe what "I think" my problem is and let me know if I am wrong.

The thing is, I need to bind a constant to a String value: bindConstant().annotatedWith(Db4Objects.class).to( <value-taken-from-properties> ).
That value should be passed to the module by the constructor or injected. BTW, I am using Names.bindProperties(...) to bind my config.properties files. 

So, my persistence module looks like:

public class PersistenceModule extends AbstractModule {

    @Inject @Named("config.db4o.database")
    private String database;
    
    @Override
    protected void configure() {
        install(PersistenceService.usingDb4o().across(UnitOfWork.REQUEST).buildModule());
        bindConstant().annotatedWith(Db4Objects.class).to(database);
    }
}

I wonder if you couldn't use:

bind(String.class).annotatedWith(Db4Objects.class).to(Key.get(String.class, Names.named("config.db4o.database")));

In other words: you're not binding a constant value, as you're trying to bind to another key.

Cédric Beust ♔

unread,
Apr 29, 2013, 1:19:39 AM4/29/13
to google...@googlegroups.com
Hi Mauro,

I've been meaning to write about this very topic for a while and your email finally pushed me over the edge:


This describes a simple, statically-typed (no @Named cop out!) way of injecting individual configuration parameters using Guice. For example:

public class A {
    @Inject
    @Prop(Property.HOST)
    private String host;

    @Inject
    @Prop(Property.PORT)
    private Integer port;
}

It seems to match closely what you are looking for, let me know what you think!

-- 
Cédric

 

-- 
Cédric



On Sun, Apr 21, 2013 at 11:47 PM, mmonti <monti...@gmail.com> wrote:
Hi guys,

Quick question from a newbie using Guice.. :)
I have the following module that I am using to persist my objects with db4o:

public class PersistenceModule extends AbstractModule {
    private static final Logger logger = LoggerFactory.getLogger(DefaultBootstrapModule.class);
    private static final String BOOKINGS_DATA = "./target/bookings.data";
    @Override
    protected void configure() {
        install(PersistenceService.usingDb4o().across(UnitOfWork.TRANSACTION).buildModule());
        bindConstant().annotatedWith(Db4Objects.class).to(BOOKINGS_DATA);
    }
}

Is there any way to "provide" to this module the database name, for example injecting the value into the module? What is the correct approach/pattern for this case? 
The idea is to take this configuration parameter from a properties file. I have already an object that provides me these values from the property, but i cant find the way to inject it to this module. I dont know if its possible but i assume that is a pretty common use case, so i would like to know what is the best way to do it.

Thanks!




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

Reply all
Reply to author
Forward
0 new messages