EJB Inheritance is Different From Java Inheritance

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:

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:

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:

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.