Despite the fact that EJB inheritance sometimes uses Java inheritance – they’re not always the same. Just as you could read in my previous post, EJB doesn’t have to implement any interface to expose a business interface.
The other way around is also true – just because EJB is implementing some interface or extending other EJB doesn’t mean it exposes all or any of its views.
Let’s say we want to have some basic EJB exposing remote business interface. We then want to extend this EJB and
override remote business methods.
Nothing fancy, right? But let’s take a look at some examples.
Remote business interface:
public interface RemoteA {
void remoteA();
}
Base EJB:
@Stateless
@Remote(RemoteA.class)
public class SuperclassEJB implements RemoteA {
public void remoteA() {
// Some basic code that can be overriden.
}
}
The above SuperclassEJB
is our base EJB. It exposes one remote business interface with one method.
Now let’s move to subclasses of our EJB:
Case 1 – Java Inheritance
@Stateless
public class SubclassEJB1 extends SuperclassEJB {
// 'remoteA' is not EJB business method. EJB inheritance is strictly for
// implementation reusing.
}
SubclassEJB1
is an EJB – that’s for sure. But what interfaces does it expose?
Because an EJB component must explicitly define what business interfaces it’s defining – our EJB doesn’t have any
real business methods at all!
It’s new, fresh no-interface view EJB.
This means that if in your code you’ll do:
@EJB SubclassEJB1 myEJB
it’ll inject your no-interface view EJB with no business methods in it.@EJB(name="SubclassEJB1") RemoteA myEJB
it’ll refuse to make this injection becauseRemoteA
is not a business interface of our EJB.
What’s interesting – if instead of container injection using @EJB
you’d do lookup like this:
RemoteA subclassEJB1 = (RemoteA) initCtx.lookup("java:module/SubclassEJB1");
subclassEJB1.remoteA();
it won’t throw any exception and invoke the remoteA()
method correctly. Why?
Because what we really looked up was the no-interface view of our EJB. We then casted it to the RemoteA
(which is
correct from plain Java perspective) and invoked a no-interface view method.
I think you’ll agreee it can be quite confusing – instead of using remote interface we’ve ended up with local bean method being correctly invoked.
Case 2 – Java Inheritance With Interface Implementation
@Stateless
public class SubclassEJB2 extends SuperclassEJB implements RemoteA {
// 'remoteA' is correctly exposed as EJB business method BUT as an
// implicit local i-face. Method implementation is correctly inherited.
}
Now this looks really weird. Our EJB is extending other EJB and implements remote business interface, right?
Well, not exactly. We’re implementing plain Java RemoteA
interface. This interface itself doesn’t have @Remote
annotation and neither does SuperclassEJB
. This means we’re exposing RemoteA
as a local business interface.
This is one of the default behaviors of EJBs that was discussed in my previous post.
This means that if in your code you’ll do:
@EJB(name="SubclassEJB2") RemoteA myEJB
it’ll use local business interface. Quite messed up, don’t you think?
Case 3 – Java Inheritance With Interface Implementation and View Declaration
@Stateless
@Remote(RemoteA.class)
public class SubclassEJB3 extends SuperclassEJB {
// Method 'remoteA' is correctly exposed as EJB business method (thanks
// to @Remote on EJB). Method implementation is correctly inherited.
}
This is a correct example of EJBs extension. We’ve correctly reused the implementation with Java inheritance,
implemented the EJB remote business interface and exposed it using @Remote
. The implements
clause is not even
required – the @Remote
would be enough. However, the @Remote
part is crucial.
This means that if in your code you’ll do:
@EJB(name="SubclassEJB3") RemoteA myEJB
it’ll properly use remote business interface.
Conclusion
As you can see EJB inheritance sometimes might not be as easy as expected. It requires you to know the basics of components and views definition. By default component inheritance is plainly for code reusing – not for component extension. Without this knowledge you might bump into some quite weird and frustrating problems.
All of the examples were tested on JBoss AS 7.1.1.