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
Contextualimplementation 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
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.
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?
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.
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
CreationalContexts. 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.