Would something like Provision Listeners (that were notified before & after
location/injection of all injected objects) help? Issue
http://code.google.com/p/google-guice/issues/detail?id=78 is a long-standing
one.. although I'm hesitant to make full-on "provision interceptors" because
that could make it too easy for people to silently change what objects are
injected or what is returned. I think some form of provision listener may
work though, something like:
ProvisionListener {
void beforeProvision(Key<T> key);
void afterProvision(Key<T> key, T provided);
}
or more like interceptors, but without the ability to modify the provision:
ProvisionListener {
void onProvision(Provision<T> provision);
Provision<T> {
T provision();
Key<T> getKey();
}
}
(Perhaps also providing a Set<InjectionPoint>.)
In my head, these would apply to _all_ provisioned objects, which includes
Providers & normal bindings. The main use-case I've seen for this is folks
that want to get timing data around how long it takes to inject/provision
their objects, so the can optimize accordingly. But it could also apply to
your use-case of needing to know when provision is all finished with
Providers, and may be a simpler method than InjectionListeners.
sam
On Tue, May 3, 2011 at 7:11 PM, Sam Berlin <[email protected]> wrote:
>
>
> On Tue, May 3, 2011 at 7:05 PM, Stuart McCulloch <[email protected]>wrote:
>
>> On 3 May 2011 23:30, Sam Berlin <[email protected]> wrote:
>>
>>>
>>> On Tue, May 3, 2011 at 6:14 PM, Stuart McCulloch <[email protected]>wrote:
>>>
>>>> Hi Sam,
>>>>
>>>> I think the change introduced in r1543 to fix Issue 626 breaks the
>>>> semantics of InjectionListeners in certain circumstances.
>>>>
>>>> Previously when the InjectionListener was called you could be certain
>>>> all @Inject annotated members had been injected and any circular proxies
>>>> were initialized. Unfortunately the change in r1543 means that the instance
>>>> could now still contain uninitialized provider proxies at the time
>>>> the InjectionListener is called. This makes InjectionListeners more fragile
>>>> and less useful, especially wrt basic lifecycle operations.
>>>>
>>>> I'm not quite sure how best to solve this - yes detecting cycles between
>>>> providers can be useful, but typically people put providers in to try and
>>>> break cyclic dependencies. So this change might even lead to situations
>>>> where (due to legacy code) there's a cycle that would have been solved with
>>>> providers but now can't be solved. But assuming we can't wind back the
>>>> clock
>>>> (or make this check optional), is there any chance we could add a new SPI
>>>> listener that gets called at the end of "circularGet"? ie. after the call
>>>> to "finishConstruction" like the listeners in ConstructorInjector? That way
>>>> we'd still have a way to manage the instance after all proxies are
>>>> initialized, but before it gets passed back to the caller.
>>>>
>>>
>>> The change should be strictly improving upon situations that would have
>>> previously failed. There were two failure scenarios before:
>>>
>>> 1) Two providers were circular dependent directly on each other. This
>>> scenario would have resulted in a StackOverflowError as each provided is
>>> recursively called to provide for the other.
>>>
>>> 2) A provider is involved in a circular dependency that involves a
>>> non-provider binding. If the Provider was a singleton, this would have
>>> resulted in Scopes.SINGLETON failing with a "re-entrant provider" failure.
>>> If it wasn't a singleton, I'm not 100% sure what would have happened (but
>>> it was likely broken).
>>>
>>> Would you be able to write a failing test case that uses
>>> InjectionListeners? The circular provider checks are intended to fix actual
>>> problems that we ran into at Google, and should result in all around safer
>>> code. I'm not sure what stands out with the circular dependency detection
>>> on Providers that wouldn't have already caused problems with Constructors,
>>> since the two have basically the same detection/handling model.
>>>
>>
>> Sure, I can write up a failing test - the degenerate case is quite easy to
>> recreate with a Provider cycle and basic InjectionListener, albeit not ideal
>> code. Note the difference between the Constructor and Provider case is that
>> the Constructor fires off its listeners after the proxies are initialized
>> (ie. their delegates set) whereas with the Provider case there are no
>> listeners to fire (and therefore no way to perform some last minute
>> management).
>>
>> I might experiment with adding the new SPI listener in sisu-guice. (For
>> now I've rolled this change back over there as it breaks our Plexus adapter
>> - which I admit does push Guice to the edge wrt. lifecycle management
>> because it has to support legacy code and semantics involving some very
>> tortuous cycles!)
>>
>
> Sounds good, thanks. I'd be curious to look at the test and see the
> Provider cycle, and how you made it work without getting StackOverflowErrors
> or randomly generated duplicate provided copies.
>
> sam
>
>
>>
>> sam
>>>
>>
>> --
>> Cheers, Stuart
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "google-guice" group.
>> To post to this group, send email to [email protected].
>> To unsubscribe from this group, send email to
>> [email protected].
>> For more options, visit this group at
>> http://groups.google.com/group/google-guice?hl=en.
>>
>
>
--
You received this message because you are subscribed to the Google Groups
"google-guice" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/google-guice?hl=en.