Search code examples
javacdiweld

How to setup a non-CDI bean from a 3rd party for @Inject into CDI bean


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

  • The instances are valid beans
  • I have no control over its source
  • Instances are created by the library
  • Those instances are final and cannot be wrapped, overridden, or proxied

The 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.


Solution

  • 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.