I am working on a framework which will be used in Java EE applications and therefore is likely to be deployed in the \lib
directory of an EAR file.
The framework will use CDI to programmatically lookup and inject beans that are located in the Java EE application that is using the framework. The problem I've got is when the Provider.get()
method from javax.enterprise.Provider<T>
is called by my framework to get an instance of the bean, Weld throws a UnsatisfiedResolutionException
.
To check this isn't an issue related to CDI I've also tried using MyClass myClass = Class.forName(clazz).newInstance();
to get an instance of the class but a ClassNotFoundException
is thrown.
The structure of EAR file I'm using for testing purposes is as follows:
MyTestApp.ear
+\lib\MyFramework.jar <----Contains the framework invoking the Provider.get() method
+MyTestApp.jar <----Contains the bean I want to inject
My test application's EAR contains an application.xml file which includes <library-directory>lib</library-directory>
.
I believe this problem is occurring because the bean I want to inject exists in a separate classloader. i.e. \lib\MyFramework.jar
is in a different classloader to MyTestApp.jar
. I found this SO question which seems to suggest this is the case. Given that I'm developing a framework I don't believe the answer in the question is a viable solution for my needs.
I'm intrigued to find out whether creating a CDI portable extension would allow me to get an instance of the bean I want to use, but don't have enough experience in this area. Using @Observes ProcessAnnotatedType<T>
I can see beans that exist outside of the \lib
directory in an EAR file, including the ones I want to programmatically inject.
My questions are:
Am I correct in assuming this problem is occurring because \lib\MyFramework.jar
and MyTestApp.jar
are in separate classloaders?
Is there anything I can do using CDI that will allow my framework when deployed in the \lib
directory of an EAR file to make the Provider.get()
method call to avoid Weld throwing a UnsatisfiedResolutionException
?
Is there anything I can do outside of CDI to achieve same result?
Update
I've now tried moving MyFramework.jar
to the root of the EAR file and also including the jar module in the application.xml
file but the container fails to start the application due to a CDI unsatisfied dependency exception. The bean referenced in the exception can be injected when MyFramework.jar
is located in the \lib
directory and is a different bean to the one referenced in my question.
1 : yes
2 : actually I don't know
3 : Yes, you must understand the ear classloader hierarchy, the jars in ear lib directory are loaded at the ear level and so available in all child classloaders (there is one child classloader per component in the ear).
It means that MyFramework.jar is visible from MyTestApp.jar ear child classloader but the inverse is false.
see In java EE, which jars should I put in the library dir?
You can either :