views:

631

answers:

6

I am checking out Google Guice as DI framework but I am a bit puzzled: why there's no configuration file at all?

I found a partial explanation on this question but it is still not clear how I would be able to set my component roles (or any other thing I need to use a switch) without a config file.

Any help appreciated!

+11  A: 

The configuration is in the code instead of config files, which is a valid decision for many scenarios.

Yes, it means that you have to rebuild (possibly just the modules) if you want to release a different way of plumbing your application - although of course you could still get some configuration values from command-line arguments, properties files etc if you want to.

If you regularly need to change your application plumbing and don't want to redeploy anything but a single file, Guice may not be for you. If on the other hand your main reason for using DI is to make your code clearer, and in production you'll always really use the same plumbing (or close enough) then Guice is a good option - there are often bits of logic you want to use when sorting out the plumbing anyway, and components which are generally hard to describe/construct declaratively.

Different DI frameworks have different benefits and trade-offs - use whichever one is most suitable for your application.

Jon Skeet
thanks for the clarification!
JohnIdol
+3  A: 

A lot of configuration in Guice is implicit, via the @Inject Annotation. A great deal of complexity in projects comes from a big number of project Artifacts. Java files, Xml files, Properties files, databases, parameters.. Guice tries to remove a part of this complexity by not using config files.

Re-wiring your application is easy at compile time. Most likely you will only need to edit your module class. For most classes handeled by Guice, you will need no config at all, but only @Inject in the right places - you will only need to configure anything when you have two different Implementations of the same Interface - or when you want to inject classes from external libraries using Provider classes.

Andreas Petersson
+5  A: 

Most of the DI configuration will be the same from one deployment to another, so they can very well be configured using code, which makes Guice's configuration very terse and you get the benefits of compile time type checking, refactoring tools, code navigation etc.

For those few things that change from deployment to another, such as the database username and password configuration, you can write the needed code yourself. Write code which reads the configuration file (maybe a properties file), parses the parameters, and binds them in your Guice modules so that your application gets access to them. The code that is needed for doing that won't take many lines of code.

Esko Luontola
+1  A: 

Not sure what you mean by file but Guice lets you change implementaions via Binder and custom Providers .

Surya
Yeah - what I mean is that the only way to change behavior is to rebuild the whole thing
JohnIdol
+2  A: 

It is trivial to introduce boostrapping using configuration files if you are so inclined. We use Guice together with a simple API that loads property files where the things go that really need to be parameterized. This can be used together with @Named annotations and such, and of course you can have some conditionals in modules (though it is a good idea not to over-do that).

This is an example of how part of our bootstrapping is set up:

public class MetModules extends AbstractModule {

    private static final Logger log = LoggerFactory.getLogger(MetModules.class);

    private final Settings settings;

    public MetModules(Settings settings) {
     this.settings = settings;
    }

    @Override
    protected void configure() {

     // common (stage independent modules) go here
     install(new CommandsModule());
     install(new ServletsModule());
     install(new DataBaseModule(settings));
     install(new JobsModule(settings));

     // any development/ production specific modules
     Stage stage = currentStage();
     if (Stage.DEVELOPMENT.equals(stage)) {
      configureForDevelopment();
     } else { // PRODUCTION
      configureForProduction();
     }
    }

    /**
     * Install modules that will be used in development.
     */
    private void configureForDevelopment() {

     // Mock implementation of email delivery that just logs it got a
     // message rather than trying to send it.
     install(new AbstractModule() {
      @Override
      protected void configure() {
       bind(Delivery.class).toInstance(new Delivery() {

        public String deliver(MailMessageExchange exchange)
          throws DeliveryException {
         log.info("email message: "
           + exchange.getMessage().getMailMessage()
           + " to "
           + Arrays.asList(exchange.getMessage()
             .getMailMessage().getTo())
           + " (not sent)");
         return "fooMessageId";
        }
       });
      }
     });

     // local in-memory registry suffices
     install(new LocalServiceRegistryModule());

     // local in memory db implementations of services
     install(new LocalServicesModule());
    }

    /**
     * Install modules that will be used in production.
     */
    private void configureForProduction() {
     // we really only need this (error interception and audit logging)
     // in production
     install(new AopModule());
     install(new ZooKeeperServiceRegistryModule());     }
}

Where Settings is what reads our properties files and such. Right now development/ production together with specific settings overrides specific for deployments seems to do the job for us, but we could go further with this if we wanted to obviously.

Eelco
+1  A: 

I have recently created the following project.

http://code.google.com/p/guice-property-injector/

It is WIP but allows runtime injection of properties from a property file based on environment.

sounds interesting - thx
JohnIdol