Handling of EJB business interface which is inherited in EAP
Environment
- Red Hat JBoss Enterprise Application Platform (EAP)
- 7
Issue
- Is it possible to use inheritance for EJB business interface?
- How to declare an interface as an EJB business interface?
- A working application in EAP 7.1 can not be deployed in EAP 7.2, it will fail with the following Exception
16:36:30,284 ERROR [org.jboss.as.controller.management-operation] (Controller Boot Thread) WFLYCTL0013: Operation ("deploy") failed - address: ([("deployment" => "ejb31-singletonAsync-ejb.jar")]) - failure description: {
"WFLYCTL0080: Failed services" => {"jboss.deployment.unit.\"ejb31-singletonAsync-ejb.jar\".INSTALL" => "WFLYSRV0153: Failed to process phase INSTALL of deployment \"ejb31-singletonAsync-ejb.jar\"
Caused by: org.jboss.as.server.deployment.DeploymentUnitProcessingException: WFLYEE0052: Failed to install component StartupSingletonAsyncPostBean
Caused by: org.jboss.as.server.deployment.DeploymentUnitProcessingException: WFLYEJB0406: No EJB found with interface of type 'org.jboss.wfink.ejb31.LocalTest' for binding org.jboss.wfink.ejb31.singleton.StartupSingletonAsyncPostBean/initBean"},
"WFLYCTL0412: Required services that are not installed:" => [
"jboss.naming.context.java.comp.ejb31-singletonAsync-ejb.ejb31-singletonAsync-ejb.StartupSingletonAsyncPostBean",
"jboss.naming.context.java.comp.ejb31-singletonAsync-ejb.ejb31-singletonAsync-ejb.TestReferenceBean",
"jboss.deployment.unit.\"ejb31-singletonAsync-ejb.jar\".WeldStartService",
"jboss.deployment.unit.\"ejb31-singletonAsync-ejb.jar\".beanmanager"
],
"WFLYCTL0180: Services with missing/unavailable dependencies" => [
"jboss.naming.context.java.comp.ejb31-singletonAsync-ejb.ejb31-singletonAsync-ejb.StartupSingletonAsyncPostBean.ValidatorFactory is missing [jboss.naming.context.java.comp.ejb31-singletonAsync-ejb.ejb31-singletonAsync-ejb.StartupSingletonAsyncPostBean]",
"jboss.deployment.unit.\"ejb31-singletonAsync-ejb.jar\".batch.artifact.factory is missing [jboss.deployment.unit.\"ejb31-singletonAsync-ejb.jar\".beanmanager]",
"jboss.deployment.unit.\"ejb31-singletonAsync-ejb.jar\".weld.weldClassIntrospector is missing [jboss.deployment.unit.\"ejb31-singletonAsync-ejb.jar\".WeldStartService, jboss.deployment.unit.\"ejb31-singletonAsync-ejb.jar\".beanmanager]",
"jboss.naming.context.java.comp.ejb31-singletonAsync-ejb.ejb31-singletonAsync-ejb.StartupSingletonAsyncPostBean.Validator is missing [jboss.naming.context.java.comp.ejb31-singletonAsync-ejb.ejb31-singletonAsync-ejb.StartupSingletonAsyncPostBean]",
"jboss.naming.context.java.comp.ejb31-singletonAsync-ejb.ejb31-singletonAsync-ejb.StartupSingletonAsyncPostBean.InstanceName is missing [jboss.naming.context.java.comp.ejb31-singletonAsync-ejb.ejb31-singletonAsync-ejb.StartupSingletonAsyncPostBean]",
"jboss.naming.context.java.comp.ejb31-singletonAsync-ejb.ejb31-singletonAsync-ejb.TestReferenceBean.ValidatorFactory is missing [jboss.naming.context.java.comp.ejb31-singletonAsync-ejb.ejb31-singletonAsync-ejb.TestReferenceBean]",
"jboss.naming.context.java.comp.ejb31-singletonAsync-ejb.ejb31-singletonAsync-ejb.TestReferenceBean.Validator is missing [jboss.naming.context.java.comp.ejb31-singletonAsync-ejb.ejb31-singletonAsync-ejb.TestReferenceBean]",
"jboss.naming.context.java.comp.ejb31-singletonAsync-ejb.ejb31-singletonAsync-ejb.StartupSingletonAsyncPostBean.InAppClientContainer is missing [jboss.naming.context.java.comp.ejb31-singletonAsync-ejb.ejb31-singletonAsync-ejb.StartupSingletonAsyncPostBean]",
"jboss.naming.context.java.comp.ejb31-singletonAsync-ejb.ejb31-singletonAsync-ejb.TestReferenceBean.InstanceName is missing [jboss.naming.context.java.comp.ejb31-singletonAsync-ejb.ejb31-singletonAsync-ejb.TestReferenceBean]",
"jboss.naming.context.java.comp.ejb31-singletonAsync-ejb.ejb31-singletonAsync-ejb.TestReferenceBean.InAppClientContainer is missing [jboss.naming.context.java.comp.ejb31-singletonAsync-ejb.ejb31-singletonAsync-ejb.TestReferenceBean]"
]
}
- How inheritance of the Bean's implementation works with the EJB business interface?
- The Bean class is not exposed with the business interface implemented by the superclass only, this has been worked before. What is the reason?
Resolution
From the specification every business interface need to be declared explicitly as a business interface by @Remote or @Local annotation or deployment descriptor.
If it works for some other implementations this is by accident and not backed up by the spec.
So this behaviour can be changed at any time without warning as it will not violate the specification.
See Content from issues.jboss.org is not included.JBEAP-17031
Note that extending a remote interface and use that as local interface is not a good design as a Remote interface might throw RemoteExceptions which are not allowed for Local interfaces!
Root Cause
The class does not have the full qualified annotations and no explicit declaration of the interface as shown below.
Because of the EJB 3.2 specification
4.9.2.1 Session Bean Superclasses
A session bean class is permitted to have superclasses that are themselves session bean classes. How-
ever, there are no special rules that apply to the processing of annotations or the deployment descriptor
for this case. For the purposes of processing a particular session bean class, all superclass processing is
identical regardless of whether the superclasses are themselves session bean classes. In this regard, the
use of session bean classes as superclasses merely represents a convenient use of implementation inher-
itance, but does not have component inheritance semantics.
As an example, the client views exposed by a particular session bean are not inherited by a subclass that
also happens to define a session bean.
@Stateless
public class SuperBean implements Super { ... }
@Stateless
public class ExtendedSuperBean extends SuperBean { ... }
Without any annotation for the implementation classes the ExtendedSuperBean will not be exposed with the Super business interface, only with a No-Interface view!
Adding annotation @Remote @Local to the interface, @Stateless @Local(Super.class) to the beans implementation or a deplyoment descriptor will force to have the ExtendedSuperBean being exposed as Super.
4.9.7 Session Bean’s Business Interface
- The bean class must implement the interface or the interface must be designated as a local or remote business interface of the bean by means of the Local or Remote annotation or in the deployment descriptor.
- All business interfaces must be explicitly designated as such if any of the following is true:
- the bean exposes a no-interface view
- any interface of the bean class is explicitly designated as a business interface of the bean by either of the following means:
- using the Local or Remote annotation with a non-empty value on the bean class
- using the Local or Remote annotation on the interface
- in the deployment descriptor
Caller EJB
@Stateless
StartService {
@EJB
private LocalTest test;
...
}
The referenced EJB
@Stateless
public class TestImpl implements RemoteTest {}
Interface one
// no annotation javax.ejb.Remote
// @Remote // or maybe annotated like this
public interface RemoteTest { ... }
Interface two
// no annotation javax.ejb.Local
// extending RemoteTest will not inherit the @Remote annotation from it !
public interface LocalTest extends RemoteTest {}
This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.