0

PicoContainer seems to indicate that it supports JSR-330 @Inject and @Named. (No, this other question doesn't seem to help, as it doesn't address the fact that the PicoContainer site says that some support for JSR-330 has been added.)

I add something to the container like this:

container.addComponent(Foo.class);
container.addComponent("myBar", new MySpecialBar());
container.addComponent("decoy", new SomeOtherBar());

I mark constructor parameters with @Named:

public class Foo(@Named("myBar") Bar bar) { ...

But when I try to get a Foo instance, PicoContainer complains that it has too many Bar instances to choose from.

Question 1: How do I get PicoContainer to work with @Named for constructor injection?

Then I try to use field injection inside Foo.java:

@Inject
@Named("myBar")
Bar bar;

That doesn't work either.

Question 2: How do I get PicoContainer to work with @Inject and @Named for constructor injection?

Or is the PicoContainer news page wrong, and there simply isn't any PicoContainer 2.x support for JSR-330 at all?

Community
  • 1
  • 1
Garret Wilson
  • 18,219
  • 30
  • 144
  • 272

1 Answers1

1

Looks like I'm the only person on stackoverflow who answers pico questions but I'm not the pico team member, so for the final answer you may need to visit their mailing list :)

While looking at the framework sources (2.10 ... 2.15) I can't see any support for javax.inject.Named and @Inject is supported as pico annotation, not as javax.inject.Inject

As for solving ambiguous dependencies pico offers several ways: http://picocontainer.codehaus.org/ambiguous-injectable-help.html (using parameter names, IMHO a bit weird but it may be ok for you) and http://picocontainer.codehaus.org/disambiguation.html (using Parameter object -- not bad, but verbose, another one using binding annotations as in Guice, IMHO even more weird) and if none of the above suits you, you can take Parameter object idea and make you little disambiguation adapter, with IMHO cleaner look

    class DisambiguationAdapter<T> extends AbstractAdapter<T> {

    private final Object[] params;

    public DisambiguationAdapter(Object componentKey, Class<T> componentImplementation, Object... params) {
        super(componentKey, componentImplementation);
        this.params = params;
    }
    // the idea is to make child container that overrides ambiguos deps using the parameters hints
    @Override
    public T getComponentInstance(PicoContainer container, Type into) throws PicoCompositionException {
        MutablePicoContainer tmpContainer = new DefaultPicoContainer(container);
        tmpContainer.addComponent(getComponentKey(), getComponentImplementation());
        for (Object param : params) {
            tmpContainer.addComponent(container.getComponent(param));
        }

        T instance = tmpContainer.getComponent(getComponentImplementation());
        tmpContainer.dispose();
        return instance;
    }

    @Override
    public void verify(PicoContainer container) throws PicoCompositionException {
        for (Object param : params) {
            if(container.getComponent(param) == null) {
                throw new PicoCompositionException("Can't resolve param-key=" + param + " to satisfy dependencies for " + getDescriptor());
            }
        }
    }

    @Override
    public String getDescriptor() {
        return getComponentImplementation().getCanonicalName();
    }
}

then you declare this method to add components that require ambiguous deps:

    public void register(Object key, Class<?> component, Object... params) {
    container.addAdapter(new DisambiguationAdapter<>(key, component, params));
}

and then you use it like this:

// constructor for some class requiring ambig deps
public ProfileFinder(/* ambig param */ ProfileDao dao, /* any other params */ Param1 param1, Param1 param2)......

// container composition
// hint key, impl class
c.addComponent(ProfileDaoSelector.SLAVE, jdbi.onDemand(ProfileDao.class));
c.addComponent(ProfileDaoSelector.MASTER, jdbiMaster.onDemand(ProfileDao.class));
// impl class, hint keys array
c.register(ProfileService.class, new Object[] {ProfileDaoSelector.MASTER});
c.register(ProfileFinder.class, new Object[] {ProfileDaoSelector.SLAVE});
xeye
  • 1,250
  • 10
  • 15
  • But does anyway know why on http://picocontainer.codehaus.org/news.html they say they support `@Named` and `@Inject` from JSD-330? Is this available in PicoContainer 3? If so, how can I get PicoContainer 3 via Maven? – Garret Wilson Jan 16 '15 at 16:10
  • As I can see in pico's Jira they're fixing bugs and adding small improvements to 2.x but don't have time to support the web site. Pico 3.x is usable but was never released to maven, you have to build it yourself and deploy to local repo. – xeye Jan 19 '15 at 08:51
  • So the question remains: why do they say they support `@Named` and `@Inject` from JSR-330? Saying that they haven't updated the web site doesn't answer the question --- does that mean that they supported it in the past but no longer support it, and the web site is now out of date? Maybe you don't know the answer, but that's one of the questions I'm raising here. – Garret Wilson Jan 19 '15 at 17:17
  • @xeye hey! I bit OT but, why PicoContainer development stopped? – LppEdd Apr 17 '21 at 16:16
  • @LppEdd I'm not a picocontainer contributor so can only guess: although there's always a place for improvements, older versions of pico are well polished and still used in such famous product as Intellij IDEA and various backends. Unfortunately other DI containers went the path of massive annotations usage which is an anti-pattern. There's an abandoned branch to make pico compatible with JSR 330 annotations but probably there was no much interest for it. – xeye Apr 18 '21 at 09:54
  • @xeye thanks. My interest in understanding PicoContainer comes from the fact I make IntelliJ plugins, and exploring the codebase I liked how each piece is wired up by Pico. I'm using it now on a Swing project too. – LppEdd Apr 18 '21 at 10:23
  • @LppEdd yes, pico really shines with its concepts of hierarchical containers that can be created and destroyed dynamically for UI scopes thus reducing a chance for memory leaks etc. You can do the same stuff with spring/guice though I think pico is lighter and the api is nicer. Overall nowdays pico gives you a perspective, set of patterns that you can use even with other frameworks. – xeye Apr 18 '21 at 19:23
  • @xeye thanks! Since I need the support for the Named annotation anyway, I've ported the core PicoContainer to Gradle (but since it's multi-module will most likely port Gems too). https://github.com/lppedd/picocontainerx, I'm doing a cleanup. – LppEdd Apr 20 '21 at 18:14