Reputation: 49545
While I've found examples in CDI where you setup @Produces
(kinda factory like) or using the CDI javax.enterprise.inject.spi.Unmanaged
concepts, they all seem to presume that CDI will be the one creating the instance of the class on its own terms and lifecycle (which makes sense).
However, there are situations where CDI simply cannot create the instance.
Such as a 3rd party library (that isn't using CDI itself) which is creating the object internally and giving it to you.
Now, how can I take these already instantiated objects (which incidentally are final objects with no default constructor), and make them available for my CDI managed beans to then use?
Here's a simplified example.
public class Foo
{
@Inject
private ByteBuffer buf;
public void go()
{
// do something, with buffer
}
}
public void process() {
ByteBuffer buf = ByteBuffer.allocate(500);
// TODO: how to add "buf" to current context?
Foo foo = CDI.current().select(Foo.class,AnyLiteral.INSTANCE).get();
foo.go();
}
Now, I realize that for this specific example, I could eaily just pass in the ByteBuffer, or setup a @Produces
for ByteBuffer, or even have Foo make the ByteBuffer itself. (all of which would be easier). I chose ByteBuffer, because it exhibits the same problems I'm facing with the 3rd party library
final
and cannot be wrapped, overridden, or proxiedThe use case also has situations where there are nested CDI references that could also use access to this @Inject ByteBuffer buf;
.
Ideally it would be keen to have this be a pure CDI api technique, and not something that is weld or implementation specific.
I've devled into custom Scope creation as well, thinking that might be a solution for this, having a sort of @BufferScope
that identifies the start()
and end()
of this instance. But none of the examples and documentation make this very clear with regards to objects that CDI just cannot call newInstance()
or produce()
on. The object instantiation is out of my hands, but the ability to present it to a CDI Scope is possible, along with even managing the ultimate death / destruction of that instance.
Upvotes: 4
Views: 1238
Reputation: 16238
You use a producer method, which can be as simple as something like this:
@Produces
@ApplicationScoped
private Foo produceFoo() {
final Foo instance = // acquire one of those instances you're talking about
return instance;
}
If for whatever reason that doesn't work for you, you can alternatively write a portable extension and programmatically add a Bean
that does what you want. So something like this in CDI 2.0+ (untested):
private void afterBeanDiscovery(@Observes final AfterBeanDiscovery event) {
final Foo instance = // acquire one of these final instances you're talking about
event.addBean()
.scope(ApplicationScoped.class)
.qualifiers(whateverYouNeed)
.addTransitiveTypeClosure(instance.getClass())
.createWith(cc -> instance) // you may also need .destroyWith()
;
}
Once you have this "producing side" set up, then in any CDI bean anywhere you can do:
@Inject
private Foo foo;
Upvotes: 0
Reputation: 713
There is some fundamental misunderstanding here. CDI is not required to construct the bean instances it can serve through producer methods. A Dependent scope will work just fine if the class is not proxyable. You can also make a wrapper class for the object, and put said class instances in whichever scope you need.
Upvotes: 0
Reputation: 5003
I'm not sure I agree with the original assertion that CDI assumes it is constructing the instances. For example, I use the following in a JSF application to inject the current FacesContext instance....
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.faces.context.FacesContext;
public class FacesContextProducer {
@Produces @RequestScoped FacesContext getFacesContext() {
return FacesContext.getCurrentInstance();
}
}
At nowhere do I create the FacesContext instance. All that is required is that what has been created by the external framework is accessible.
So, if there is an external source from which you are getting instances, as long as you can get the correct one, the @Produces approach should still work?
Upvotes: 1
Reputation: 77226
Proxying is not the same as wrapping. A customary workaround is to create a ByteBufferHolder
(insert your class here) that adapts the custom builder flow into a bean that understands that it's inside the DI context.
Upvotes: 1