The (mostly) unknown story behind javax.ejb.EJBException

Yesterday I blogged about what impact Exceptions do have on JavaEE transactions in EJB.
But there is another funny EJB Exception mechanism waiting for you to get discovered – the javax.ejb.EJBException.

This handling dates back to the times when EJB was mainly intended to be a competition to NeXT Distributed Objects and Microsoft DCOM. Back in those days it was all about ‘Client-Server Architecture’ and people tried to spread the load to different servers on the network. A single EJB back then needed 4 classes and was inherently remote by default.

Only much later EJBs got a ‘local’ behaviour as well. And only in EJB-3.1 the No-Interface View (NIV) got introduced which made interfaces obsolete and are local-only.
But for a very long time remoting was THE default operation mode of EJBs. So all the behaviour was tailored around this – regardless whether you are really using remoting or are running in the very same JVM.

The impact of remoting

The tricky situation with remote calls is that you cannot be sure that every class is available on the client.

Imagine a server which uses JPA. This might throw a javax.persistence.EntityNotFoundException. But what if the caller – a Swing EJB client app – doesn’t have any JPA classes on it’s classpath?
This will end up in a ClassNotFoundException or NoClassDefFoundException because de-serialisation of the EntityNotFoundException will blow up on the client side.

To avoid this from happening the server will serialize a javax.ejb.EJBException instead of the originally thrown Exception in certain cases. The EJBException will contain the original Exceptions stack trace as pure Strings. So you at least have the information about what was going wrong in a human readable format.

If you like to read up the very details then check out 9.4 Client’s View of Exceptions in the EJB specification.

Switching on the ‘Auto Pilot”

Some containers like e.g. OpenEJB/TomEE contain a dual-strategy. We have a ‘container’ (ThrowableArtifact) which wraps the orignal Throwable plus the String interpretation and sends both informations as fallback over the line.

On the client side the de-serialization logic of ThrowableArtifact first tries to de-serialize the original Exception. Whenever this is possible you will get the originally thrown Exception on the client side. If this didn’t work then we will use the passed information and instead of the original Exception we throw an EJBException with the meta information as Strings.

The impact on your program?

The main impact for you as programmer is that you need to know that you probably not only need to catch the original Exception but also an EJBException. So this really changes the way your code needs to be written.
And of course if you only got the EJBException then you do not exactly know what was really going on. If you need to react on different Exceptions in different ways then you might try to look it up in the exception message but you have no type-safe way anymore. In that case it might be better to catch it on the server side and send an explicit @ApplicationException over the line.

When do I get the EJBException and when do I get the original one?

I’d be happy to have a good answer myself 😉

My experience so far is that it is not well enough specified when each of them gets thrown. But there are some certain course grained groups of container behaviour:

  • Container with Auto-Pilot mode; Those containers will always try to give you the original Exception. And only if it is really not technically possible will give you an EJBException. E.g. TomEE works that way.
  • Container who use the original Exception for ‘local’ calls and EJBException for remote calls.
  • Container who will always give you an EJBException – even for local invocations. I have not seen those for quite some time though. Not sure if this is still state of the art?

Any feedback about which container behaves what way is welcome. And obviously also if you think there is another category!

Advertisements

About struberg
I'm an Apache Software Foundation member blogging about Java, µC, TheASF, OpenWebBeans, Maven, MyFaces, CODI, GIT, OpenJPA, TomEE, DeltaSpike, ...

3 Responses to The (mostly) unknown story behind javax.ejb.EJBException

  1. Dirk Weil says:

    I just came across your statement that EJBException will contain the originating exceptions as pure strings. In one of our recent projects I discovered a different behaviour: EJBException contains the causing exceptions unchanged, leading to ClassCastExceptions within the client.

    If I look into the code of EJBException, there is nothing special in it; it just extends RuntimeException and does no special handling of exception causes. Couly you please point me to where the special behaviour of EJBException you described is specified?

    Thank you and see you (probably) in Mainz at JAX!
    Dirk

    • struberg says:

      Hi Dirk!
      Long time no see, hope all is fine!
      Is your original Exception maybe marked as @ApplicationException?

      To be more specific, the ThrowableArtifact is _not_ an EJBException. It just contains one. This will transparently unpacked on the client side and you will see the EJBException over there. With more or a bit less info, depending on which classes are available on the client.
      In which container do you see this problem?
      When writing this blog post I asked a few other EE guys and also tested with TomEE and WebSphere. So this should be fine from a spec level.
      Probably you can open a ticket for your container?
      LieGrue,
      strub

  2. Dirk Weil says:

    Hi Mark!

    The exception is a PersistenceException caused by some db specific SQL exception. It is not marked as ApplicationException, so the SQLException causes a PersistenceException, which causes a TransactionRolledBackException, which gets wrapped by an EJBException in the end. That is fine on the server side.

    On the client side I receive the EJBException, which is fine again. But the cause therein is a ClassNotFoundException (WildFly) or MarshallException (GlassFish), superceding any more detailed cause, which is bad for the client, because there is no chance of dealing with the error apart from displaying an unspecified error message and giving up.

    I’ve put together a demo on GitHub: https://github.com/GEDOPLAN/ejb-remote-exception-demo.

    I browsed through the EJB spec once more trying to find the part describing the specal treatment of EJBException, but did not find anything about it. Maybe we can discuss that in Mainz. See you soon, Dirk

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: