Why PicoContainer 2.0?

First EJB 3.0 then Google Guice seemed to copy the ideas from PicoContainer, adding some more value. EJB 3.0 ommitted the essential Constructor Injection, and Guice went far to far down a annotations road. Soon after Guice, even the Spring Framework team decided to do things the direct way with 'JavaConfig'.

So PicoContainer 1.x was refactored (not rewritten) into PicoContainer 2.0. All the unit tests were kept, and excerise took hundreds of commits, but the team is pleased with the result.

Can my component use multiple constructors?

Yes.

You can code multiple constructors for a component:

class MyComp {

  private ThreadPool theThreadPool;
  
  public MyComp(ThreadPool threadpool) {
    theThreadPool = threadpool;
  }

  public MyComp() {
    theThreadPool = new DefaultThreadPool();
  }

  // other methods.


}

How does PicoContainer decide what constructor to use?

PicoContainer will instantiate a given component using the "greediest" satisfiable constructor. By greedy, we mean the constructor that takes the most parameters. By satisfiable, we mean constructors where all arguments can be satisfied by other registered components.

If you register a component with no satisfiable constructors, or two or more ambiguous "largest" constructors, a RuntimeException will be thrown when you ask for the component instance.

We recommend for most components, you use only one constructor, although this is by no means a requirement.

How does PicoContainer compare to EJB containers?

Oh blimey, it is rather different. EJB has loads of things you must extend, implement, provide and throw. It is also not an IoC design. It is close in that components are managed by a container, but the cumbersome and static nature of the JNDI lookups ensure that it is not actually IoC. PicoContainer is not a superset of EJB though, as it provides no remoting capability.

How does PicoContainer decide what constructor to use?

PicoContainer will instantiate a given component using the "greediest" satisfiable constructor. By greedy, we mean the constructor that takes the most parameters. By satisfiable, we mean constructors where all arguments can be satisfied by other registered components.

If you register a component with no satisfiable constructors, or two or more ambiguous "largest" constructors, a RuntimeException will be thrown when you ask for the component instance.

We recommend, for the sake of predictablility, that PicoContainer compatible components use only one constructor, although this is by no means a requirement.

How to use primitive types in constructors?

PicoContainer will look for the greediest constructor of your component. But if your component's constructor depends on primitive types you may set the values explicitly.

public interface ThreadPool {
	void setSize(int);
}

public class MyComp {
	private ThreadPool threadPool;
	public MyComp(ThreadPool pool, int size) {
		threadPool = pool;
		threadPool.setSize(size);
	}
}

In this case you can set the parameters at registration time:

DefaultPicoContainer pico = new DefaultPicoContainer();
pico.addComponent(ThreadPool.class, DefaultThreadPool.class);
pico.addComponent(MyComp.class, MyComp.class, new Parameters[] {
	new ComponentParameter(),
	new ConstantParameter(new Integer(5));
})
MyComp myComp = (MyComp)pico.getInstance(MyComp.class);

Use ConstantParameter to set constant values and the ComponentParameter to let Pico resolve the dependency.

When should I use PicoContainer?


We recommend using PicoContainer when your application consists of many different classes (components) that are related to each other. Instantiating and lacing/connecting a lot of objects can be difficult task.

Why Another IoC Framework?

After a long period of watching Inversion of Control frameworks, and for some of us avoiding them because of their cumbersome nature, we got together to write what we believe is the simplest possible IoC design. One, perhaps, that considers the so-designed component as more important that the container.

When we set out to do this in 2003, there was nothing equivalent to PicoContainer (xContainer originally). XWork, that underpinned WebWork2 was a general/embeddable Setter Dependency Injection framework, but not well known. The Spring Framework started in the same timescale, and we were talking to its authors before Martin Fowlers Dependency Injection article. Later we discovered that HiveMind (now at Apache) also was in the same space.

Why Constructor Injection?

Constructor Injection is hard to swallow for people who have been living with Interface Lookup or Setter Injection for long. We think it's like TDD. Once you get the grasp of it, you don't go back. Here are some benefits with this type of IoC:

Will we support Guice's @Inject annotation transparently?

We could compile PicoContainer against Guice.jar and leverage the @Inject method with a new InjectionFactory (and probably will). The problem is that there is no easy way to use an annotation without having its class in the classpath. There's no easy 'transparent' solution for this.

Things fail silently if the jar is missing, unless the annotation is used - then it fails noisily. Meaning, the mere declaration of an annotation on a component is not enough to cause a ClassNotFoundException on load, if its not used:

@Retention(RetentionPolicy.RUNTIME)
@Target(value={ElementType.METHOD})
public static @interface Bar {
}
import com.google.inject.Inject;
public class Foo {

    @Inject
    @Bar
    public void setFoo(String str) {
        System.out.println("0>" + str);
    }

    public static void main(String[] args) throws NoSuchMethodException {

        Foo foo = new Foo();
        foo.setFoo("hello");

        Method m = Foo.class.getMethod("setFoo", String.class);

        Annotation[] anns =  m.getDeclaredAnnotations();
        System.out.println("1> " + anns.length);
        for (int i = 0; i < anns.length; i++) {
            Annotation ann = anns[i];
            System.out.println("2> " + ann.toString());
        }

        Annotation ann =  m.getAnnotation(Inject.class);
        System.out.println("3> " + ann);
    }
}

Leaving Guice out of the classpath, and trying to launch Foo...

commandline: java -cp classes Foo
0>hellos
1> 1
2> @Foo$Bar()
Exception in thread "main" java.lang.NoClassDefFoundError: org/picocontainer/annotations/Inject
        at Foo.main(Foo.java:32)

The class loads, but the @Inject annotation is not present in the set of declared annotations, but another in the classpath is. Lastly when accessed explicitly, there is an exception thrown. Contrast to, the same run with Guice in the classpath:

0>hello
1> 2
2> @org.picocontainer.annotations.Inject()
2> @Foo$Bar()
3> @org.picocontainer.annotations.Inject()