Here are some random observations concerning CreationalContext
, a funky little architecturally polluting blemish on the surface of CDI’s otherwise pretty good set of APIs. (I’ve written before on this little nugget.)
There is no documentation that says what a CreationalContext
is. The class javadoc reads, in total:
Provides operations that are used by the
Contextual
implementation during instance creation and destruction.
So its purpose is exactly that of its two operations, one of which (push()
) can be properly implemented as a no-op as we’ll see below. That means its purpose is solely to house the release()
method.
To portably create a CreationalContext
, you use BeanManager#createCreationalContext(Contextual)
. For the purposes of destroying dependent objects, which is the interface’s sole documented purpose, the supplied Contextual
is never used.
A CreationalContext
is architecturally tightly coupled to a Context
implementation for the Dependent
scope. If you implement one, you have to implement the other because there is no portable way for an arbitrary Context
implementing the Dependent
scope to indicate to a CreationalContext
that a dependent object needs to be tracked for subsequent destruction by the release()
method. But in Weld you cannot supply your own instance of a Context
for the Dependent
scope, because the Weld-supplied one is always active, and there can be at most one active Context
for a scope, and there is no way to remove a Context
. So therefore you cannot supply your own implementation of CreationalContext
in Weld unless you couple it to Weld interfaces and abstract classes…in which case why are you supplying one in the first place?
Weld implements CreationalContext
by constructing a tree of them: each one tracks dependent objects added by its child. This means that Weld’s CreationalContext
implementation is also tightly coupled to Weld’s implementation of BeanManager
: every time a contextual reference is acquired, whether via injection or programmatically, a new “child” CreationalContext
is created. This tree structure is not necessarily needed to perform dependent object cleanup (since, for example, OpenWebBeans implements CreationalContext
without such a tree structure). The result is that in Weld many CreationalContextImpl
objects get created that do nothing.
push()
and release()
have nothing to do with each other. In fact you can pass the TCK by implementing push()
as a no-op. Many developers you talk to think that these methods are related. Almost nobody knows how to use them properly. You are, it turns out, supposed to always (probably within a finally
block) call release()
as the last thing you do in a custom bean’s destroy()
method. Otherwise it is possible that your program will leak memory.
release()
means, simply, “destroy dependent objects tracked by this CreationalContext
“. Of course it may not be exactly this CreationalContext
, because it might be a tree of such CreationalContext
s. Or maybe it’s “destroy all dependent objects reachable from the creation of whatever it was that caused this CreationalContext
to come into existence”. No specification language indicates whether release()
must be idempotent. Obviously it would sure be nice if it were, so CDI implementations tend to make it so.
Remember that according to the specification a CDI implementation can destroy an unreferenced dependent object at any point by any means for any reason, so strictly speaking release()
isn’t really a method that should have ended up in the specification (it’s an implementation detail). It’s clearly convenient so maybe that’s why it ended up in here.
The only time you need a CreationalContext
is when you know that a contextual instance is going to be created. If you know that a contextual instance already exists, then the CreationalContext
will never be used by the Context#get(Contextual, CreationalContext)
method.
I often wonder why instead of this strange API there wasn’t a DependentContext
interface, extending Context
, that would allow you to add and destroy dependent object hierarchies, since we already know that Dependent
is a special scope. There’s probably a good reason but I can’t think of what it is at the moment.