Garret Wilson
Garret Wilson

Reputation: 21356

PicoContainer JSR-330 @Named support?

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?

Upvotes: 0

Views: 582

Answers (1)

xeye
xeye

Reputation: 1256

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});

Upvotes: 1

Related Questions