After all these years, I still love PicoContainer. I can't help it. It does exactly what I need it to do, and no more. About six months ago I found out that I could use PicoContainer to build components at runtime from specific instances of other objects in the container. For example, you ask the container for a type of Juice that is made from a specific type of Fruit in your container, based on a name you've previously given that specific instance of Fruit. This allows you the twin comforts of abstraction in your class implementation and precision in your runtime targeting of those objects in the container. It's the best of both worlds.
/**
* COMMERCIAL OBJECT RELATIONAL MAPPING (CORM) PROJECT
* This document is Copyright (C) 2004-2006
* Alexander Saint Croix. All rights reserved.
*
* THE CONTENTS OF THIS FILE MAY BE USED
* UNDER THE TERMS OF THE
* ACADEMIC FREE LICENSE, VERSION 2.1.
*
* See http://opensource.org/licenses/afl-2.1.php
* for details.
*/
package org.eremite.examples;
import junit.framework.TestCase;
import junit.framework.Assert;
import org.picocontainer.MutablePicoContainer;
import org.picocontainer.Parameter;
import org.picocontainer.defaults.DefaultPicoContainer;
import org.picocontainer.defaults.BasicComponentParameter;
public class PicoContainerTest extends TestCase {
private MutablePicoContainer c;
public void setUp() throws Exception {
super.setUp();
c = new DefaultPicoContainer();
}
public void tearDown() throws Exception {
super.tearDown();
}
public void testPicoBehavior() throws Exception {
c.registerComponentInstance(
"lemon", new Fruit("lemon"));
c.registerComponentInstance(
"lime", new Fruit("lime"));
c.registerComponentInstance(
"bubble", new Fruit("tapioca"));
c.registerComponentImplementation("lemonjuice",
Juice.class, new Parameter[] {
new BasicComponentParameter("lemon")});
c.registerComponentImplementation("limejuice",
Juice.class, new Parameter[] {
new BasicComponentParameter("lime")});
c.registerComponentImplementation("bubbletea",
Juice.class, new Parameter[] {
new BasicComponentParameter("bubble")});
Juice lemonade = getJuice("lemonjuice");
Juice limeade = getJuice("limejuice");
Juice bubbletea = getJuice("bubbletea");
Assert.assertEquals("lemon", lemonade.getType());
Assert.assertEquals("lime", limeade.getType());
Assert.assertEquals("tapioca", bubbletea.getType());
System.out.println("w00t! Pico works.");
}
private Juice getJuice(String s) {
return (Juice) c.getComponentInstance(s);
}
}
What happens in the code above is great. First, I feed a handful of Fruit components into the container, giving each of them names and distinguishing them from each other by a String. Then, I register a handful of Juice components in the container, each according to a different type of Fruit.
Later on, when I need some Juice, I can get it by name, and the type of Fruit that it contains is also pulled from the container. This allows me to feed abstract concepts of objects into a container, and ask for a fully constructed object that contains other objects in the container.
It's great Inversion of Control. Elegant, simple, lightweight. Gotta love Pico.
Now, a further question I'm wondering is whether I could make a JuiceMix object out of two types of Juice, and be able to ensure that the first one is a lemon and the second is a lime. Both objects are Fruit--can the container recognize the difference, or is it too ambiguous? If I could do this, it'd allow me to do very complex action processing in a declarative runtime environment in response to changing state conditions. It'd be very powerful.
PicoContainer 1.1, at only 75Kb, is a much sweeter deal for raw IoC than Spring at 32Mb. There used to be a SpringContainer available, but it required a lot of XML configuration and overhead that I didn't want to trouble myself with at the time, when I can get what I need from PicoContainer. I've recently heard of something cleverly dubbed "femtocontainer", which uses java.beans.XMLDecoder to accomplish much of what Spring does. Now that's an interesting idea that I'll look into more.