How to make a serviceloader created class handle container managed objects

520 Views Asked by At

I'm currently writing a library where I want the user of my library to implement an interface. From within my library I'm calling this implementation.

I'm using ServiceLoader to instantiate the implementation provided by the integrator and it works just fine. The integrator calls a start() method in my library and in the end he gets something in return. The implementation is used to give me some things along the way that I need in order to get to the final result. (I'm deliberately not using CDI or any other DI container 'cause I want to create a library that can be used anywhere. In a desktop application, a spring application an application using guice...)

Now I'm facing a problem. I'm creating a showcase in which I'm using my own library. It's a webapplication where I'm using jsf and CDI. When I instantiate the implementation provided in said webapp from within my library, I'm dealing with a non-container managed object. But since this implementation needs to use container managed objects I'm kinda screwed since this can never work.

Example: Interface in lib:

public interface Example{
   public abstract String getInfo();
}

Implementation in war:

public class ExampleImpl implements Example{

   @Inject
   private ManagedBean bean;
   public String getInfo(){
      return bean.getSomethingThatReturnsString();
   }
}

As you can see this is a huge problem in the way my library is build since the bean will always be null... This means no one using a DI container can use my library. I know I can get the managedbean by doing a FacesContext lookup and get the managedbean but more importantly, my library isn't very well designed if you think about it.

So to conclude my question(s): Is there any way I can make the serviceloader use a DI container to instantiate the class?

Anyone who knows a better way to fix my problem?

Anyone who knows a better way to get the things I need without making the integrator implement an interface but I can get information from the integrator?

I know this is a quite abstract question but I'm kinda stuck on this one.

Thanks in advance

1

There are 1 best solutions below

0
On

As the implementation of Example is not performed within the CDI container the injection doesn't happen. What you can do is to lookup the bean manually using the BeanManager. According to the docs, the BeanManager is bound to the jndi name java:comp/BeanManager. Using the following code you can get the BeanManager within your implementation class and lookup the dependencies manually:

InitialContext context = new InitialContext();
BeanManager beanManager = (BeanManager) context.lookup("java:comp/BeanManager");
Set<Bean<?>> beans = beanManager.getBeans(YourBean.class, new AnnotationLiteral<Default>() {});
Bean<YourBean> provider = (Bean<YourBean>) beans.iterator().next();
CreationalContext<YourBean> cc = beanManager.createCreationalContext(provider);
YourBean yourBean = (YourBean) beanManager.getReference(provider, YourBean.class, cc);

where YourBean is the dependency you are looking for.