Thursday, March 08, 2007

Guice 1.0

We're pleased to announce the open source release of Google's internal Java dependency injection framework Guice. Guice wholly embraces annotations and generics, thereby enabling you to wire together and test objects with less effort than ever before. Annotations finally free you from error-prone, refactoring-adverse string identifiers.

Guice injects constructors, fields and methods (any methods with any number of arguments, not just setters). Guice includes advanced features such as custom scopes, circular dependencies, static member injection, Spring integration, and AOP Alliance method interception, most of which you can ignore until you need it.

An earlier version of Guice already powers Struts 2's plugin architecture. Google has been running Guice in mission critical applications for months, and now you can, too. We hope you enjoy Guice as much as we do.

Guice lives at Google Code. From there, you'll find the user's guide, Javadocs, and download. Please direct any questions to the mailing list.

21 Comments:

Blogger Ola said...

congrats

10:53 AM  
Blogger Bob said...

Thanks, O. You were about as close as you could come to being the first user. ;)

11:08 AM  
Blogger Filipe said...

@ImplementedBy(ServiceImpl.class)
public interface Service {
void go();
}

That's quite quite ugly.

11:26 AM  
Blogger Bob said...

@ImplementedBy is an experts only feature; it's not for everybody. You have to weigh the benefits and consequences in context. @ImplementedBy may not be as robust as a completely separate interface, but it is more concise, and it's better than depending directly on a concrete class. If you're only using an interface to simplify unit testing, @ImplementedBy is a perfectly pragmatic compromise.

12:52 PM  
Blogger Filipe said...

Having your interface knowing who implements them is very beyond pragmatism.
Or maybe I'm just not an expert. Or maybe I work in a team.

That aside the framework looks nice.

1:02 PM  
Blogger Bob said...

I personally don't use @ImplementedBy either, but some external early adopters made a compelling case for it. When trying to decide whether it does more harm than good or not, I reasoned that a user can even more easily depend directly on a concrete class, so why not give my users what they want? :)

1:21 PM  
Blogger Sony said...

Annotations are going to improve a lot of stuff especially things that are controversial as being either configuration or programming.

I fully expected a bunch of IoC containers using Annotations to come out soon. Tapestry 5 is introducing one as well (replacing Hivemind). With the proliferation of IoC Containers, and added integration between different IoC Containers for interoperation is a bit scary. May be you guys should settle on some JCP/JSR to standardize the IoC Container (or is EJB-3 it? still rejected by many) for the sake of our Apps !!!

What is lost in all this - is the fact that IoC is a first class Design Pattern - I tried to introduce Context IoC to capture its first class nature in an article a while back. In my opinion Context IoC is a "base" pattern whereby most patterns (but not all) including most of GoF can be expressed as a sequence of refactorings of Contexts.

2:41 PM  
Blogger Bob said...

Sony, if you find yourself needing features from another framework, please let us know so we can support you. We soley use Guice ourselves, but we provide integration hooks because Guice is new and not all application are green field.

As for standardization, my bet is on JSR 299.

I tried to illustrate that dependnecy injection is a pattern which doesn't necesarily require a framework in the user's guide introduction. Is this what you mean?

2:55 PM  
Blogger szimano said...

Guice is something *really* cool. I'm definitely going to give it a try in my project, which is JSR-168 portlet.

If you're intersted how it went i can provide a report in few days ;-).

3:13 AM  
Blogger Bob said...

Please keep us updated. We're definitely interested in integration stories.

8:50 AM  
Blogger Jelmer said...

Hmm I just finished browsing through the documentation. And though I like the design I would argue that this is nothing that could not be easily implemented on top of spring. It seems like your typical case of not invented here syndrome.

3:40 PM  
Blogger Bob said...

Jelmer, except building on Spring would result in a framework which is more complicated and two orders of magnitude slower with obscure error messages. If starting fresh makes me guilty of a "NIH syndrome," then I gladly stand accused. ;)

3:50 PM  
Blogger Ben Tomasini said...

Congrats on this release.

As an early HiveMind user, I have been looking forward to using the new IoC module in Tapestry 5. Guice has some real similarities with it.

Have you taken a look at Tapestry 5 IoC? Can you comment on any significant similarities or differences?

6:31 PM  
Blogger Bob said...

Thanks, Ben. The biggest thing about Tapestry IoC that jumps out at me is they still use string identifiers. Guice does not.

6:47 PM  
Blogger grunch said...

Well, everything looks fine except of one thing. What about distributed configuration? With Guice it's impossible to inject (in a good fashion) dependency configured (by Module) in one jar to some class placed in another jar because you need injector class to get configured instance.

5:00 PM  
Blogger Bob said...

I'm not sure I understand. Each jar can provide modules. If you create an Injector from those modules and then inject classes in the jars, the jars can even depend on each other indirectly.

5:05 PM  
Blogger grunch said...

Maybe my post was too enigmatic… sorry…I’ll try to explain it in another way. Let’s take a plug-in example:
Platform has plug-in support and each plug-in can use Service (interface) implementations which are bounded in Guice in main platform. PlatformImpl also starts plug-ins. Same Platform interface shall be injected to Plugins. Plugins are products that are provided by customers. Plugins can be started by Platform and they run independently from each other. Platform can also stop them.
E.g.

public interface PluginSupport{
void startWork();
void stopWork();
}

public interface Service{
void doSomething();
}

public class ServiceImpl implements Service{

}

class ConfigurationModule implements Module{
public void configure(Binder binder){
binder.bind(Platform.class).to(PlatformImpl.class).in(Scopes.SINGLETON);
binder.bind(Service.class).to(ServiceImpl.class).in(Scopes.SINGLETON);
}
}

public interface Platform{
void registerPlugin (PluginSupport plugin);
}

public class PlatformImpl{

private List< PluginSupport > plugins = new ArrayList< PluginSupport >();
private Injector injector;

PlatformImpl(){
injector = Guice.createInjector(new ConfigurationModule());

}

public void startPlatform(){
for (PluginSupport plugin: plugins){
//HERE’S THE PROBLEM – No plug-ins will be registered in platform
plugin.startWork();
}

}

public void stopPlatform(){
for (PluginSupport plugin: plugins){
//SAME PROBLEM – No plug-ins will be registered in platform
plugin.stopWork();
}

}

void registerPlugin (PluginSupport plugin){
plugins.add(plugin)
}
}

And now plugins.

public class FirstPlugin implements PluginSupport{

@Inject
public FirstPlugin(Platform platform, Service service){
platform.registerPlugin(this);

}

public void startWork(){…}
public void stopWork(){…}
}

public class SecondPlugin implements PluginSupport{

@Inject
public FirstPlugin(Platform platform) {
platform.regiserPlugin(this);

}

public void startWork(){…}
public void stopWork(){…}

}

I’ve omitted Platform initialization.

Each plugin shall be instantiated by Guice. I guess it’s impossible. There would have to be some static workaround for that. To instantiate plug-in implementations, each plug-in would have to provide its own Module, but then there would be several Injector instances and each of them would have different Platform instance.
How can I cause to create plug-in instances and start them? Is it impossible?

4:12 AM  
Blogger Bob said...

Grunch, this looks eerily similar to the plugin architecture we use. Needing a list of things to which multiple plugins contribute is a common use case, and the solution isn't as clean as I would like (yet).

First, we create a binding for the list of things. List<Link> for example.

  bind(new TypeLiteral<List<Link>>() {}).toInstance(new ArrayList<List<Link>>());

Then, in each plugin module, we register an eager singleton which adds a link for that plugin. For example:

  bind(Intializer.class).asEagerSingleton();

Where Initializer looks like this:

  class Initializer {
    @Inject
    Initializer(List<Link> links) {
      links.add(...);
    }
  }

We hope one day to support "multi-bindings" so you don't need a separate binding to a list or registry, and you won't need separate initialization logic.

If you want to implement your design, you could bind a list of Plugins. Your modules would each add plugin[s] from eager singletons like above. You might consider using an explicit PluginRegistry class instead of a plain List. This keeps you from having to deal directly with generics.

Then you could bootstrap your plugin registry:

  Injector injector = ...;
  // All the plugins have already
  // added themselves.
  PluginRegistry pluginRegistry =
    injector.getInstance(PluginRegistry.class);
  pluginRegistry.startAll();

11:13 AM  
Blogger Stan said...

When's the next release due?

5:17 AM  
Blogger Bob said...

I'm on a short hiatus focusing on my main project at the moment. We don't have a concrete plan just yet, but we have plenty of ides (see the issue tracker).

8:01 AM  
Blogger Scott said...

Bob, you are one crazy guy --

I just watched your Guice video on TSS and was giddy as a school girl after only a few minutes of viewing. Are you military… love the hair! I am writing Struts 2 in Action with Don Brown and Chad Davis so I especially enjoyed you pimping the Guice plug-in. It sounds like Josh Bloch has inspired you with his KISS doctrine.

When will we see you and Rod in the ring on Pay-per-view?

Peace,
Scott Stanlick
stanlick@gmail.com

1:56 PM  

Post a Comment

Links to this post:

Create a Link

<< Home