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 because RemoteA 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.