问题
I'm using Glassfish 3.1.2.2, java ee6.
I have a library in which a class uses CDI to get a helper class. I would like in one specific project where I use that library, to override that CDI dependency and force the library to use my own helper class, specific to that project instead. I can modify the library at will, but by default it should use its default helper class, so that behaviour doesn't change for other users of the library.
This should be the perfect application of the @Alternative
CDI pattern. I made a java interface for the helper class API; There is a default implementation in the library, then I can use the <alternatives>
tag in the beans.xml
; in the project where I want to override the behaviour, I would specify my own implementation of the helper in the beans.xml of that specific project.
Except it doesn't work. It's apparently impossible to override the alternatives behaviour from the library outside of the library in CDI 1.0 (java ee6).
And so no matter what I specify in the beans.xml of my outer project, CDI keeps selecting the bean defined in the library.
I considered going through a producer but I didn't find how to get CDI to give to the producer the EntityManager as a parameter, so that I can pass it forward to the helper class. In this project, we normally inject the EntityManager using the @PersistenceContext
annotation.
Any ideas on how to override that CDI injection from the outer project?
回答1:
You could write a Portable Extension to do this. Listen to the ProcessAnnotatedType
event and replace the AnnotatedType
with your own. You could use the Apache DeltaSpike BeanBuilder
class to help with this.
回答2:
Apache DeltaSpike provides a feature called global-alternatives which bypasses those stupid BDA rules. It's tested with a lot of containers and you don't have do care about the details manually. With OpenWebBeans you don't have this issue at all and some versions of Weld support it via a beans.xml in WEB-INF instead of META-INF.
回答3:
The solution I used in the end is related to the suggestion from LightGuard: I have CDI extension, and I override processAnnotatedType(), as suggested.
However instead of replacing the AnnotatedType
(which I'm not sure how I could do), I use the technique described there:
http://docs.jboss.org/weld/reference/latest/en-US/html/extend.html#d0e4800
And veto the the bean that was defined in the library.
Now that the default implementation is veto'ed, if I put my own bean in my application, that's the one that CDI chooses.
To make this work also in Arquillian integration tests, you must add this call to your archive:
addAsServiceProvider(Extension.class, <CDI extension class name>.class)
The javax.enterprise.inject.spi.Extension
resource does not need to have effect in Arquillian (see SHRINKWRAP-266).
来源:https://stackoverflow.com/questions/18575174/java-ee6-override-cdi-alternative