I will present this example as simply as I know how.
I have a Grandparent class whose constructor accepts a Parent. I have a Parent class whose constructor accepts a Child. I have a Child class whose constructor accepts nothing.
- The
Grandparentis (arbitrarily) inDependentscope. - The
Parentis (importantly) inSingletonscope. - The
Childis (importantly) inDependentscope.
I have implemented custom beans for each of these so that their destroy methods will be invoked (otherwise Weld optimizes away the need for a destroy call).
The grandparent's Bean will create a Grandparent instance like this:
return new Grandparent((Parent)bm.getReference(bm.resolve(bm.getBeans(Parent.class)), Parent.class, cc));
Note in particular I use the supplied CreationalContext as the Contextual#create(CreationalContext) method documentation instructs.
The Parent bean does the same sort of thing, but asking obviously for a Child reference.
(These mechanics are (deliberately) exactly what Weld (et al.) uses to implement its injection machinery.)
In my test code:
I create a CreationalContext to use for the anticipated Grandparent construction:
CreationalContext<Grandparent> gpcc = bm.createCreationalContext(grandparentBean);
I get a Grandparent contextual reference using that gpcc:
Grandparent gp = (Grandparent)bm.getReference(grandparentBean, Grandparent.class, gpcc);
At this point, when I inspect gpcc, I note that it has two dependent objects in it in its parentDependentInstances collection and zero in its dependentInstances collection. (Note that it, of course, has no parent.)
My mental model had been that given a Bean, GPB, creating a Grandparent instance, GP, the CreationalContext used at creation time, GPCC, will contain any dependent-scoped instances "belonging to" GP (which is exactly zero). Under this (flawed?) mental model, if I were to call release() on GPCC it would effectively do nothing.
Instead I'm seeing that GPCC contains:
- information to destroy
GP - information to destroy
C, whereCis theChildinstance thatGPknows nothing about
Naïvely, it looks like Child has been added as a dependent object of Grandparent in some way. This surprised me. If I destroy Grandparent, surely I shouldn't destroy Child?
To be clear: when I use the grandparentBean to destroy Grandparent, supplying it with gpcc, Child is not in fact destroyed. So everything works, but I don't know how.
It seems my mental model is flawed. What is the proper mental model that explains this state of affairs?
(I wonder if I'm hitting side effects of https://issues.redhat.com/browse/WELD-2743. If the child CreationalContext is not created, then the parent dependent instances, it would seem, are never "seen".)
Update: my mental model is definitely being whipsawed by WELD-2743's changes. getInjectableReference does create child CreationalContexts, as it always has, but getReference no longer does for reasons I don't fully understand.