is Encounter.getProvider() usable from inside InjectionListener?

321 views
Skip to first unread message

James Strachan

unread,
Apr 1, 2009, 6:42:23 AM4/1/09
to google...@googlegroups.com
I've nearly got a first spike of the JSR 250 support for @Resource
going in GuiceyFruit using the current trunk of Guice. But I just
banged my head when attempting, inside
InjectionListener.afterInjection() to get the Encounter.getProvider()
- to try look up a dependent object that I need.

For example for JSR 250 the InjectionListener needs to get a JNDI
Context object - which I was hoping to use Guice to dependency inject.
When I saw the getProvider() methods on Encounter I figured this was
the way of asking for a provider from inside an InjectionListener?

Maybe I'm using the wrong API or maybe there's a small bug? Or maybe
its just not possible to inject an InjectionListener? (The latter
could be true due to ordering issues).

FWIW here's the stack trace if it helps... Anyone got any ideas?

.
com.google.inject.ProvisionException: Guice provision errors:

1) Error notifying InjectionListener
org.guiceyfruit.support.AbstractGuiceyFruitModule$3$1@603bdc of
org.guiceyfruit.jsr250.ResourceUsingBaseModuleTest$MyBean.
Reason: java.lang.IllegalStateException: This Provider cannot be used
until the Injector has been created.
while locating org.guiceyfruit.jsr250.ResourceUsingBaseModuleTest$MyBean

1 error
at com.google.inject.InjectorImpl$4.get(InjectorImpl.java:768)
at com.google.inject.InjectorImpl.getInstance(InjectorImpl.java:794)
at org.guiceyfruit.jsr250.ResourceUsingBaseModuleTest.testResourceInjection(ResourceUsingBaseModuleTest.java:56)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:40)
Caused by: java.lang.IllegalStateException: This Provider cannot be
used until the Injector has been created.
at com.google.inject.internal.Preconditions.checkState(Preconditions.java:142)
at com.google.inject.spi.ProviderLookup$1.get(ProviderLookup.java:87)
at org.guiceyfruit.support.AbstractGuiceyFruitModule$2.get(AbstractGuiceyFruitModule.java:63)
at org.guiceyfruit.support.AbstractGuiceyFruitModule$2.get(AbstractGuiceyFruitModule.java:61)
at org.guiceyfruit.support.AbstractGuiceyFruitModule$3$1.afterInjection(AbstractGuiceyFruitModule.java:85)
at com.google.inject.ConstructorInjector.construct(ConstructorInjector.java:97)
at com.google.inject.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:100)
at com.google.inject.ProviderToInternalFactoryAdapter$1.call(ProviderToInternalFactoryAdapter.java:45)
at com.google.inject.InjectorImpl.callInContext(InjectorImpl.java:813)
at com.google.inject.ProviderToInternalFactoryAdapter.get(ProviderToInternalFactoryAdapter.java:42)
at com.google.inject.Scopes$1$1.get(Scopes.java:54)
at com.google.inject.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:48)
at com.google.inject.InjectorImpl$4$1.call(InjectorImpl.java:759)
at com.google.inject.InjectorImpl.callInContext(InjectorImpl.java:805)
at com.google.inject.InjectorImpl$4.get(InjectorImpl.java:755)

If its any help the source of the code using the InjectionListener /
Encounter is here...
http://code.google.com/p/guiceyfruit/source/browse/trunk/guiceyfruit-core/src/main/java/org/guiceyfruit/support/AbstractGuiceyFruitModule.java

e.g. this is the line causing the issue:
http://code.google.com/p/guiceyfruit/source/browse/trunk/guiceyfruit-core/src/main/java/org/guiceyfruit/support/AbstractGuiceyFruitModule.java#63

when we attempt to inject an AnnotationMemberProvider instance so we
can inject a member
http://code.google.com/p/guiceyfruit/source/browse/trunk/guiceyfruit-core/src/main/java/org/guiceyfruit/support/AbstractGuiceyFruitModule.java#85
--
James
-------
http://macstrac.blogspot.com/

Open Source Integration
http://fusesource.com/

limpb...@gmail.com

unread,
Apr 1, 2009, 12:18:32 PM4/1/09
to google-guice
On Apr 1, 3:42 am, James Strachan <james.strac...@gmail.com> wrote:
> When I saw the getProvider() methods on Encounter I figured this was
> the way of asking for a provider from inside an InjectionListener?

When we were designing the API, the intention was to invalidate the
Encounter when hear() returned. Unfortunately, I didn't actually write
any code to do the invalidation. I'll do this! As it's written now, if
you call getProvider() on an Encounter after hear() returns, it'll
return a perpetually broken Provider. That provider will never have a
working get() method.

Can you do your getProvider() calls within hear()? That way you'll get
much better performance: InjectableType.Listener gets invoked once per
type, whereas hear() gets invoked once per instance. If you do all of
your potentially-expensive Provider lookups at type-discovery time,
things should perform reasonably.

James Strachan

unread,
Apr 1, 2009, 1:36:32 PM4/1/09
to google...@googlegroups.com
2009/4/1 je...@swank.ca <limpb...@gmail.com>:

I've just done that. I still get the same exception though. (See below).

I'm thinking we do need to defer looking up objects until as late as
possible; so that the injector can completely initialise itself before
we start looking up new objects? Or do you not think thats an issue?


1) Error notifying InjectableType.Listener
org.guiceyfruit.support.AbstractGuiceyFruitModule$3@dd5a3d (bound at
org.guiceyfruit.support.AbstractGuiceyFruitModule.bindAnnotationMemberProvider(AbstractGuiceyFruitModule.java:70))
of org.guiceyfruit.jsr250.ResourceTest$MyBean.

Reason: java.lang.IllegalStateException: This Provider cannot be used
until the Injector has been created.

at org.guiceyfruit.jsr250.ResourceTest$1.configure(ResourceTest.java:37)
1 error
at com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:332)
at com.google.inject.InjectorBuilder.initializeStatically(InjectorBuilder.java:152)
at com.google.inject.InjectorBuilder.build(InjectorBuilder.java:105)
at com.google.inject.Guice.createInjector(Guice.java:92)
at com.google.inject.Guice.createInjector(Guice.java:69)
at com.google.inject.Guice.createInjector(Guice.java:59)
at org.guiceyfruit.jsr250.ResourceTest.testResourceInjection(ResourceTest.java:33)


Caused by: java.lang.IllegalStateException: This Provider cannot be
used until the Injector has been created.
at com.google.inject.internal.Preconditions.checkState(Preconditions.java:142)
at com.google.inject.spi.ProviderLookup$1.get(ProviderLookup.java:87)
at org.guiceyfruit.support.AbstractGuiceyFruitModule$2.get(AbstractGuiceyFruitModule.java:63)
at org.guiceyfruit.support.AbstractGuiceyFruitModule$2.get(AbstractGuiceyFruitModule.java:61)

at org.guiceyfruit.support.AbstractGuiceyFruitModule$3.hear(AbstractGuiceyFruitModule.java:86)
at com.google.inject.ConstructorInjectorStore.createConstructor(ConstructorInjectorStore.java:89)
at com.google.inject.ConstructorInjectorStore.access$000(ConstructorInjectorStore.java:35)
at com.google.inject.ConstructorInjectorStore$1.create(ConstructorInjectorStore.java:44)
at com.google.inject.ConstructorInjectorStore$1.create(ConstructorInjectorStore.java:42)
at com.google.inject.internal.FailableCache$1.apply(FailableCache.java:35)
at com.google.inject.internal.MapMaker$StrategyImpl.compute(MapMaker.java:528)
at com.google.inject.internal.MapMaker$StrategyImpl.compute(MapMaker.java:398)
at com.google.inject.internal.CustomConcurrentHashMap$ComputingImpl.get(CustomConcurrentHashMap.java:2031)
at com.google.inject.internal.FailableCache.get(FailableCache.java:46)
at com.google.inject.ConstructorInjectorStore.get(ConstructorInjectorStore.java:59)
at com.google.inject.ConstructorBindingImpl.initialize(ConstructorBindingImpl.java:55)
at com.google.inject.InjectorImpl.initializeBinding(InjectorImpl.java:378)
at com.google.inject.BindingProcessor$1$1.run(BindingProcessor.java:163)
at com.google.inject.BindingProcessor.initializeBindings(BindingProcessor.java:209)
at com.google.inject.InjectorBuilder.initializeStatically(InjectorBuilder.java:120)

Bob Lee

unread,
Apr 1, 2009, 1:38:30 PM4/1/09
to google...@googlegroups.com
Thanks for the feedback, James. Sounds like I need to update the injectable type listener docs to make it clear that you need to get your providers, etc., out of the Encounter and pass those to the injection listener.

Like Jesse said, you actually have all of the information up front and can do the work once per type instead of once per instance (just like we do elsewhere in Guice, hence its good performance). This is what I was talking about when I said that the injectable type listener should create a list of of method/provider pairs and pass it to the injection listener. At run time, the injection listener will just iterate over that list, get an object from the provider and pass it to the method.

On the bright side, my hope is that this will be the world's fastest EJB impl, at least after we performance tune Guice to get back to version one levels.

Bob

Bob Lee

unread,
Apr 1, 2009, 1:39:55 PM4/1/09
to google...@googlegroups.com
On Wed, Apr 1, 2009 at 10:36 AM, James Strachan <james.s...@gmail.com> wrote:
I've just done that. I still get the same exception though. (See below).

You can only call get() on the provider from the injection listener (because the injector doesn't exist yet when we're in the injectable type listener).

Bob

James Strachan

unread,
Apr 1, 2009, 2:18:14 PM4/1/09
to google...@googlegroups.com
2009/4/1 James Strachan <james.s...@gmail.com>:

> 2009/4/1 je...@swank.ca <limpb...@gmail.com>:
>>
>> On Apr 1, 3:42 am, James Strachan <james.strac...@gmail.com> wrote:
>>> When I saw the getProvider() methods on Encounter I figured this was
>>> the way of asking for a provider from inside an InjectionListener?
>>
>> When we were designing the API, the intention was to invalidate the
>> Encounter when hear() returned. Unfortunately, I didn't actually write
>> any code to do the invalidation. I'll do this! As it's written now, if
>> you call getProvider() on an Encounter after hear() returns, it'll
>> return a perpetually broken Provider. That provider will never have a
>> working get() method.
>>
>> Can you do your getProvider() calls within hear()? That way you'll get
>> much better performance: InjectableType.Listener gets invoked once per
>> type, whereas hear() gets invoked once per instance. If you do all of
>> your potentially-expensive Provider lookups at type-discovery time,
>> things should perform reasonably.
>
> I've just done that. I still get the same exception though. (See below).

Sorry I was being thick :) Its working fine now!

I had to split the steps up; getting a reference to the Provider - and
then using the Provider. Obvious really :) Looking up the provider in
hear() - then using it again inside the InjectionListener works a
treat!

Thanks guys! @Resource injection looks like its working fine. Just
tidying up the code a bit & trying to get lifecycle stuff working...

James Strachan

unread,
Apr 1, 2009, 2:19:50 PM4/1/09
to google...@googlegroups.com
2009/4/1 Bob Lee <craz...@crazybob.org>:

> Thanks for the feedback, James. Sounds like I need to update the injectable
> type listener docs to make it clear that you need to get your providers,
> etc., out of the Encounter and pass those to the injection listener.
>
> Like Jesse said, you actually have all of the information up front and can
> do the work once per type instead of once per instance (just like we do
> elsewhere in Guice, hence its good performance). This is what I was talking
> about when I said that the injectable type listener should create a list of
> of method/provider pairs and pass it to the injection listener. At run time,
> the injection listener will just iterate over that list, get an object from
> the provider and pass it to the method.
>
> On the bright side, my hope is that this will be the world's fastest EJB
> impl, at least after we performance tune Guice to get back to version one
> levels.

Yeah! :)

I was trying to do everything as late as possible as I was worried
about ordering and dependencies & was passing in the encounter rather
than the provider. Nice and elegant though, now i've seen the light :)

Reply all
Reply to author
Forward
0 new messages