JSR-299 EG,
For a while now, the Seam 3 project has been working to solve a portability
issue that prevents modules (i.e., extensions) from running on GlassFish
(3.0 and 3.1) [1]. After much research, we've determined that this isn't a
problem that we have much control over. It's clear that there is an
inconsistency in the way the JSR-299 specification is being interpreted with
regard to extension loading.
The question is this. Does an extension have to be in an bean archive in
order to be loaded?
Section 11.5 states:
"An extension is a service provider of the
service javax.enterprise.inject.spi.Extension declared in
META-INF/services."
If one assumes that "service provider" refers to the term defined in the jar
specification [2], then one would conclude that an extension does not have
to be in a bean archive to be recognized (these are orthogonal concerns).
However, the Java EE 6 reference implementation (GlassFish) does not honor
this interpretation prior to version 3.1-b37, as indicated by [3].
Even with the recent fix to the reference implementation, there is a
secondary interpretation problem:
Can an extension register a bean programmatically for a class that resides
in another non-bean archive?
This question requires a short example.
Assume one archive, a.jar, has the following contents:
org/opentck/javaee/cdi/spi/beforebeandiscovery/BeanClassToRegister.class
A second archive, b.jar, has the following contents:
org/opentck/javaee/cdi/spi/beforebeandiscovery/AnotherBeanClassToRegister.class
org/opentck/javaee/cdi/spi/beforebeandiscovery/AnotherManualBeanRegistrationExtension.class
org/opentck/javaee/cdi/spi/beforebeandiscovery/ManualBeanRegistrationExtension.class
META-INF/services/javax.enterprise.inject.spi.Extension
AnotherBeanClassToRegister has an injection point of type
BeanClassToRegister:
public class AnotherBeanClassToRegister {
@Inject
private BeanClassToRegister collaborator;
}
BeanClassToRegister and AnotherBeanClassToRegister are added as beans
programmatically in respective extensions listed in the service provider
descriptor:
public class ManualBeanRegistrationExtension implements Extension {
public void registerBeans(@Observes BeforeBeanDiscovery event,
BeanManager bm) {
event.addAnnotatedType(bm.createAnnotatedType(BeanClassToRegister.class));
}
}
public class AnotherManualBeanRegistrationExtension implements Extension {
public void registerBeans(@Observes BeforeBeanDiscovery event,
BeanManager bm) {
event.addAnnotatedType(bm.createAnnotatedType(AnotherBeanClassToRegister.class));
}
}
The two libraries, a.jar and b.jar are bundled in a web archive, test.war
WEB-INF/lib/a.jar
WEB-INF/lib/b.jar
WEB-INF/beans.xml
Deploying this archive to the reference implementation fails with an error
message that the injection point from above cannot be satisfied. Clearly
there is a visibility problem across bean archives in this case.
Adding META-INF/beans.xml to a.jar and removing the
ManualBeanRegistrationExtension from b.jar resolves the issue in the
reference implementation.
The fact that there is so much discussion around this issue has led me to
the conclusion that it needs to be addressed at the specification level.
These scenarios have been prepared using Open TCK tests (based on
Arquillian). [4]
-Dan
p.s. Thanks to Jason Porter for helping track down this issue and drafting
the initial the Open TCK tests.
[1]
https://issues.jboss.org/browse/SOLDER-47
[2]
http://download.oracle.com/javase/6/docs/technotes/guides/jar/jar.html#Se...
[3]
http://java.net/jira/browse/GLASSFISH-14808
[4]
https://github.com/opentck/javaee_cdi/tree/master/src/test/java/org/opent...
--
Dan Allen
Principal Software Engineer, Red Hat | Author of Seam in Action
Registered Linux User #231597
http://mojavelinux.com
http://mojavelinux.com/seaminaction
http://www.google.com/profiles/dan.j.allen