[GLASSFISH-17412] Annotations in plain java classes shouldn't be processed Created: 12/Oct/11  Updated: 20/Dec/16

Status: Open
Project: glassfish
Component/s: deployment
Affects Version/s: 3.1.1_dev
Fix Version/s: future release

Type: Bug Priority: Major
Reporter: omolenkamp Assignee: Hong Zhang
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Attachments: GZip Archive ejb-reference-testcase.tar.gz    
Tags: 3_1_x-exclude


When deploying an EJB-module, Glassfish seems to scan for injection annotations in all classes, not just the ones marked as EJB.

This can lead to problems when plain java classes (no @Stateless, @Stateful, etc) contain annotations that would be invalid for container-managed classes, because Glassfish then refuses to deploy the application. It shouldn't do this, and instead ignore these annotations on unmanaged classes.

I've attached an example project that demonstrates this problem. It contains a non-EJB class AbstractTestA that contains an unresolvable @EJB annotation on a field, which causes deployment to fail:

SEVERE: Cannot resolve reference Local ejb-ref name=test.AbstractTestA/test,Local 3.x interface =test.TestA,ejb-link=null,lookup=,mappedName=,jndi-name=,refType=Session
SEVERE: Exception while deploying the app [ejb-reference-testcase]
SEVERE: Cannot resolve reference Local ejb-ref name=test.AbstractTestA/test,Local 3.x interface =test.TestA,ejb-link=null,lookup=,mappedName=,jndi-name=,refType=Session
java.lang.RuntimeException: Cannot resolve reference Local ejb-ref name=test.AbstractTestA/test,Local 3.x interface =test.TestA,ejb-link=null,lookup=,mappedName=,jndi-name=,refType=Session
at com.sun.enterprise.deployment.util.EjbBundleValidator.accept(EjbBundleValidator.java:608)
at com.sun.enterprise.deployment.EjbBundleDescriptor.visit(EjbBundleDescriptor.java:760)
at com.sun.enterprise.deployment.Application.visit(Application.java:1765)
at com.sun.enterprise.deployment.archivist.ApplicationFactory.openArchive(ApplicationFactory.java:195)
at org.glassfish.javaee.core.deployment.DolProvider.load(DolProvider.java:181)
at org.glassfish.javaee.core.deployment.DolProvider.load(DolProvider.java:93)
at com.sun.enterprise.v3.server.ApplicationLifecycle.loadDeployer(ApplicationLifecycle.java:828)
at com.sun.enterprise.v3.server.ApplicationLifecycle.setupContainerInfos(ApplicationLifecycle.java:770)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:368)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:240)
at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:382)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$1.execute(CommandRunnerImpl.java:355)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:370)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1064)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1200(CommandRunnerImpl.java:96)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1244)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1232)
at com.sun.enterprise.v3.admin.AdminAdapter.doCommand(AdminAdapter.java:459)
at com.sun.enterprise.v3.admin.AdminAdapter.service(AdminAdapter.java:209)
at com.sun.grizzly.tcp.http11.GrizzlyAdapter.service(GrizzlyAdapter.java:168)
at com.sun.enterprise.v3.server.HK2Dispatcher.dispath(HK2Dispatcher.java:117)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:238)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:680)

SEVERE: Exception while deploying the app [ejb-reference-testcase] : Cannot resolve reference Local ejb-ref name=test.AbstractTestA/test,Local 3.x interface =test.TestA,ejb-link=null,lookup=,mappedName=,jndi-name=,refType=Session

My actual use case is only slightly more complex: I'm using a shared library jar in several EJB-modules, that contains both EJB interfaces and abstract implementations. The abstract implementations include an @EJB reference to their own interface, to be able to start certain operations in a new transaction.

Each EJB-module implements some (often not all) of the interfaces, using the provided abstract implementation. Because only the actual implementations are marked with @Stateless (etc) and the abstract ones are not, injection annotation processing should only happen for the beans that are actually implemented. This worked properly in Glassfish 2.1.

Comment by Cheng Fang [ 12/Oct/11 ]

@EJB and other annotations on the super classes of EJB bean class are part of the dependency of this EJB, and need to be processed. This is required by Java EE and EJB spec.

If some ejb-ref only apply to certain concrete EJB bean class, then the concrete bean class is better place than the common super class. You may want to use lookup, or have a non-annotated setter method in super class, to be overridden with a setter method annotated with @EJB in subclass if needed.

Comment by omolenkamp [ 12/Oct/11 ]

"@EJB and other annotations on the super classes of EJB bean class are part of the dependency of this EJB, and need to be processed. "

Yes, but what's happening is that these annotations are also processed on classes that aren't EJB's themselves, and don't have any subclasses that are EJB's either. There's no reason to do this, and it will break the setup I described.

Comment by Sanjeeb Sahoo [ 13/Oct/11 ]

Seems like a bug to me. @EJB should only be processed for classes that are "injection capable."

Comment by Cheng Fang [ 14/Oct/11 ]

Assign to deployment. Hong, can you take a look?

Comment by Hong Zhang [ 14/Oct/11 ]

Yes today we scan all the classes for annotations as it's hard to determine which we should scan and should not ahead of the time. But it might be possible to filter the processed results to remove the unwanted processing.
The reason it used to work in 2.* is we did not scan libraries for annotation processing which was a bug and we fixed that in 3.*.

Comment by Hong Zhang [ 18/Oct/11 ]

Will look at this for trunk (the changes for this will be too involving for 3.1.*).

Comment by Hong Zhang [ 28/Feb/13 ]

Scrub bugs for 4.0 HCF. Did not get a chance to look into this one, as the changes for this one will be very involving, re-target for later release.

Generated at Mon Jan 16 10:45:16 UTC 2017 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.