0

I have problem with using entityManager managed by EJB Container.

In my ear i have 3 modules:

-domain - There are Entity Classes and DAO Implementations with Interfaces as EJBs.

-services - There I would have logic related with processing requests, invoking bussiness exceptions based on libraries exceptions (for example database exceptions).

-Rest Services - There I would have rest endpoints to receive and send some business objects.

So the main problem is with using EJBs in services layer, I can declare Rest endpoint class, service class, and DAO Class as EJBs. But that way i can't catch exceptions related with database, because as I red I get transactionRollback exception in my EJB container provided by WildFly and this exception is existing on commiting transaction.

I thought about removing @Stateless annotation from service class, but when I do it EJB container don't inject entityManager in my DAO class. Also I tried using @Inject annotation in service class, but still get the same NullPointer exception on entityManager in Dao Class.

Below I am adding sample code implementations in my project :

DAO Class:

@Stateless
public class CardDaoImpl implements CardDao {

@PersistenceContext(unitName = "test")
protected EntityManager em;

public CardBase addCardToDatabase(CardBase card) {
    em.persist(card);
    return card;
}

Service Class (here I want to handle businessExceptions):

@Stateless
public class TestService implements TestServiceIf {

@EJB(beanInterface = CardDao.class)
private CardDao dao;

@Override
public CardBase addCard(CardBase card) {
    dao.addCardToDatabase(card);
    return card;
}

}

Rest Endpoint Class:

@Stateless
@Path("/test")
public class Test {

@EJB(beanInterface = TestServiceIf.class)
private TestServiceIf service;

@GET
@Path("/test")
@Produces(MediaType.APPLICATION_JSON)
public String addCard() {
    CardBase card = new SampleCard();
    //Setting card object fields//
    service.addCard(card);
    return "Hello";
}

}

This is only one solution which I've discovered. But what's with throwing my businnesExceptions? Maybe it's not a good practice to throwing them in this service layer?

1 Answers1

1

With EJB 3.X, you have some specificities about exceptions occurring in ejb methods.

-services - There I would have logic related with processing requests, invoking bussiness exceptions based on libraries exceptions (for example database exceptions).

By default, the container wraps in a technical exception (EJBTransactionRolledbackException) all exceptions occurring in EJB which it considers as unexpected. In the same way you can catch all unexpected exceptions in your application. Beside exception wrapping, the container triggers a rollback on the current transaction.
To avoid technical exception wrapping by the container, your business exceptions must not be considered as unexpected by the container.

Broadly, you have two cases :

  • Either, these are checked. Nothing to do in this case.

  • Either, these are runtime. You must add the ApplicationException annotation on them or specify the application-exception behavior since the xml configuration of the EJB.

From ApplicationException javadoc :

: Applied to an exception to denote that it is an application exception and should be reported to the client directly (i.e., unwrapped).

At last, the rollback operation may be desirable or not. You may configure it like that :

@ApplicationException(rollback=true)
public class MyBusinessRuntimeException extends RuntimeException {

or

@ApplicationException(rollback=false)
public class MyBusinessRuntimeException extends RuntimeException {

With Weblogic, I remember I also had to declare these exceptions in the signature of the method.


Update for comment :

But first i need to catch exception from third party lib for example ConstraintValueException.

You have two ways of doing. Handling the exception explicitly where the problem may occur or handling the exception in a transverse way. I think you refer to ConstraintViolationException.

  • Handling the exception where it occurs when the exception is specific and needs the context to be handled :

If you expect to a specific third party exception in a specific scenario, you would like to catch it to return your business exception, you should catch the third party exception as soon as it is risen.
First, it is a good practice to catch an exception as soon as we know how to handle it.
Second, that avoid letting the exception going up to the next layer and therefore be turned into a EJBTransactionRolledbackException exception.
However, sometimes, a exception type may be handled in a transversal way for good reasons.
In this case, you could use a transversal handling for that exception.

  • Transverse handling when the exception contains required information to be handled:

If you want to handle your expected runtime exception in a transversal way, you may use a JEE interceptor and catching it to throw your own business exception.
In this case, you must define in the interceptor a mapping between the cause of the caught exception and your custom exception.

Example of interceptor to perform your need (it doesn't handle all scenarios, just a nominal scenario) :

public class WrappingInBusinessExceptionInterceptor {

    @AroundInvoke
    public Object handleExceptions(final InvocationContext ctx) throws Exception {

        try {
            Object result = ctx.proceed();
            return result;
        }

        catch (Exception exception) {
            // log the root exception
               ...
               Exception causeException = e.getCause();
               if (causeException !=null &&
                   causeException.getClass()==ConstraintValueException.class){
                  // throw your custom exception
                  String businessMsg =  
                         retrieveBusinessMessageFrom(causeException);
                  throw new MyBusinessException(businessMsg);
                }
        }                               

    }
davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • Ok this is second part of solution. But first i need to catch exception from third party lib for example ConstraintValueException or something like that when I am adding something to my database with existed key value. When I catch that i will throw my businnesException to handle it on front-end with correct message. – Hubert Leszczyński Nov 06 '16 at 20:38
  • Ok but you don't see my point. My code only works when i mark all classes with annotation @Stateless making them EJBs. So container after receiveing rest request is probably opening a transaction and closing it after data will be out of EJB class. For example I've tested it in servlet. In servlet class all wroks fine, I could inject my service EJB object in Servlet class which wasn't an EJB, so there i could catch my RolledBackTransactionException. – Hubert Leszczyński Nov 06 '16 at 22:12
  • In added code i used REST as endpoint and I had to mark it with @Stateless annotation. If I didin't mark this class, I get nullPointerException on entityManager.persist(), because container don't Inject it. – Hubert Leszczyński Nov 06 '16 at 22:12
  • I understand your point now. Unfortunately I think that it is a side-effect from the relationship between Java EE components in the container because you said it works with Servlet. But why declaring your rest service as Stateless EJB disturb you ? It has advantages, especially if you use EJB in lower layers.. Here another post (you maybe saw)where the author has a similar problem : stackoverflow.com/questions/22022019/…. The oracle Java EE doc about if stateless is mandatory when using jax-rs with ejb is not very clear : docs.oracle.com/javaee/6/tutorial/doc/gkncy.html – davidxxx Nov 06 '16 at 23:26
  • I found solution. I've injected that with CDI (using managedBean annotation on classes and @Inject on objects). I also had to add beans.xml files into my projects (to META-INF in EJB and to WEB-INF in WEB) with specific xml header. – Hubert Leszczyński Nov 08 '16 at 09:02
  • Excellent. Thank you for the feedback. – davidxxx Nov 08 '16 at 09:25