I call account EJB method in JSF bean like that :
try{
account.someFunction(...);
}catch(SimRuntimeException e){
logger.log(Level.FATAL, "SimRuntimeException catched !");
}catch(SimNotRuntimeException e){
logger.log(Level.FATAL, "SimNotRuntimeException catched !");
}catch(Exception e){
logger.log(Level.FATAL, "Exception catched !");
}
My Exceptions :
public class SimRuntimeException extends RuntimeException {
public SimRuntimeException() {
super();
}
}
#ApplicationException(rollback=true)
public class SimNotRuntimeException extends Exception {
public SimNotRuntimeException() {
super();
}
}
when account.someFunction(...); throws SimRuntimeException I fall
into Exception block because my SimRuntimeException is wrapped
into EJBException probably by EJB container.
when account.someFunction(...); throws SimNotRuntimeException I fall as expected
into SimNotRuntimeException
So, what is concretely the difference between Exception with #ApplicationException(rollback=true) and RuntimeException please ?
Pal's blog states:
EJB makes a difference in Application Exceptions and System Exceptions. Application exception is something that you define, you throw, and you are aware of. By default the application exception does not cause a rollback, unless you define it that way (and I think it's recommended). Every checked exception that is mentioned in the method signature and also any checked or unchecked exception that is annotated with #ApplicationException, is an application exception.
System exceptions happen in cases, you don't control, and they are unchecked exceptions. They always cause rollback. Good practice is, if you wrap checked exceptions -- that cannot be avoided -- in your method into EJBException e.g. ParseException.
Related
I know that unchecked Exceptions (RuntimeExceptions) will usually cause a rollack of your transaction but what happens if you catch that exception in the same mothod? I want the rollback the whole transaction when errorOccurred is true. But I wonder if catching Exception will swallow the RuntimeException hence causing the transaction to NOT rollback? Does this code still rollback the transaction?
public static void main(String[] args) {
try {
// boring stuff...
if(errorOccurred)
throw new RuntimeException("RuntimeException is thrown.");
} catch (Exception e) {
System.out.println("RuntimeException cought. Does is still rollback transaction?");
}
}
If your program catches the run time exception that means exception has not reached to JEE container, hence from JEE container perspective it is normal program execution, so it will not rollback transaction.
If you want to catch the runtime exception as well as rollback the transaction you need to programmatically rollback the transaction on those specific runtime exception. In session bean it provides sessioncontext object which has method setRollbackOnly , with this method you can inform the container to rollback transaction without throwing runtime exception. Message driven bean also provides messagedrivencontext object which can be used to rollack transaction[ check for MDB https://docs.oracle.com/javaee/6/tutorial/doc/bnbpo.html]
I have method in my service class.
#Transactional
public void serviceMethod {
dao.daoMethod();
}
public void daoMethod() {//dao.daoMethod
//some code
try {
//some more code that throws an unchecked exception
} catch(Exception exception) {
//do something -- no exceptions generated/thrown from here
}
//some more code
}
Will this result in the transaction rolling back?
If the Unchecked exception was thrown from within a method that was called from the try block would it be any different?
No, the transaction will only be rolled back in case of an uncaught exception.
The transactional interceptors "wrap" around the calls of the annotated methods; they cannot see what happens inside them.
In your case it will silently ignore the exception. You didn't do anything inside the catch block. This is not advised at all.
If you catch an Exception in the try-catch block and you did some actions to handle this Exception - a rollback will not happen. In the case with RuntimeException, by default - the rollback will occur.
You can specify, which exceptions should cause the rollback. #Transactional(rollbackFor = MyCheckedException.class)
https://resourcepool.io/2014/11/16/java-quickies-what-you-wish-you-knew-about-spring-transactional-annotation/
https://www.catalysts.cc/wissenswertes/spring-transactional-rollback-on-checked-exceptions/
I am using spring Transactional annotation which is overriding custom exception:
Application exception overriden by commit exception
lets say
#Transactional
method A() {
try {
} catch (MyException e) {
throw MyException(e.getMessage, e);
}
}
Now exception I got from code which is calling A is transaction rollback exception.
I want exact exception thrown by code, but Apache ExceptionUtils.getRootCause is returning transaction rollback messages which doesn't clarify anything.
How can I propagate exact application exception to caller method in this case?
EJB 3.1 Session Bean:
import javax.ejb.*;
public class FooException extends EJBException {
}
#Stateless #Local
public class Foo {
public void bar() throws FooException {
if (/* something wrong */) {
throw new FooException();
}
}
}
Now the test:
import org.junit.*;
public class FooTest {
#Test(expected = FooException.class)
public void testException() {
new InitialContext().lookup("Foo").bar();
}
}
The problem is that EJBException is caught in the test, not FooException. Looks like EJB container looses information about my custom exception type and throws a basic type (EJBException). What is wrong here? (it's OpenEJB 3.1)
First of all, you don't need to use the #Local annotation here. This designates an interface as a local interface or when used at a bean (in your case) can be used to point to a local interface (via the value attribute). Neither case is applicable here. Your code as given will also not compile. lookup("Foo") will return an Object that needs to be casted.
Anyway about the problem, the EJB container doesn't loose any information but wraps your exception in an EJBException. This is because FooException ultimately inherits from RuntimeException. Any such exception is treated by the container as a nonapplication exception and for those the EJB spec defines that they should be wrapped.
In your situation you already extend from EJBException, so it seems like this is a corner case. JBoss AS 6 for instance doesn't do the extra wrapping in this situation, but apparently OpenEJB does.
You can solve this problem by either not letting FooException inherit from EJBException, or by catching the exception in your test, unwrapping it and rethrowing the unwrapped exception.
Since your bar method is declaring that it throws FooException, my guess is that you didn't realize that EJBException is a RuntimeException and thus a nonapplication exception. Why did you let FooException inherrit from EJBException? Did you think this was somehow required, or does this need to server some special purpose?
(as an extra hint, make sure you understand the difference between application and nonapplicaton exceptions with respect to rolling back any transaction and destroying the pooled bean)
I am using EJB3 on Glassfish using the default TopLink persistance manager. Within a Session Bean, when the persistence manager catches a DB exception, it marks the transaction to be rolled back, and throws an EJBException, in turn wrapping a RollbackException. Now I was expecting to be able to get the original jdbc exception out of the caused by exception of one of these exceptions, but it is not.
It is important that I do retrieve the original exception, as I need to report back to the users what the problem is, and to do this I need to analyse the SQL error codes.
Does anyone know if it is possible to get this information from Toplink? Or whether Hibernate makes it possible?
Thanks,
I had the same issue. I ended up using the AroundInvoke interceptor method , that way you can catch any exception on the server side , and extract whatever info you want to and wrap it to throw your own exception , and set the EjbContext to rollback the transaction.
I can provide you with an example if you don't come right.
Good question, Ant
I know you want to throw a database exception but when it occurs the application, in most of the time, is not able to restore its initial state or it does not know how to recover from it. So it should be handled as a runtime exception. Some problems in database exceptions includes
database connection failure
query is wrong
table or column does not exist
Above you see the application is not be able to restore its initial state. If you think it is possible restore its initial state so you should use a application exception. Client will get the same application exception thrown by your business method. If you want to be able to get the exact exception thrown by your business method you have two choices:
Use a business delegate pattern to access your EJB
As you know, runtime exception is wrapped by a EJBException, so you shold use something like
Let's suppose you have this Stateless session bean
#Stateless
public class BeanImpl implements Bean {
public void doSomething() {
try {
// some code
} catch(SomeException e) {
throw new EJBException(e);
}
}
}
So you wrap your session bean through a business delegate
public class BeamBusinessDelegate implements Bean {
// your stateless session bean goes here
private Bean bean;
public BeamImpl() {
InitialContext i = new InitialContext();
bean = (Bean) i.lookup(<GLOBAL_JNDI_ADDRESS_OR_RELATIVE_ENVIRONMENT_NAMING_CONTEXT_ADDRESS>);
}
public void doSomething() {
try {
bean.doSomething()
} catch(EJBException e) {
throw e.getCause();
}
}
}
Or you can extends EJBException according to your needs
public class DatabaseException extends EJBException {
}
So in your business method
#Stateless
public class BeanImpl implements Bean {
public void doSomething() {
try {
// some code
} catch(SomeException e) {
throw new DatabaseException();
}
}
}
regards,
The only way I've found to do what I want, is to force the manager to write to the db using manager.flush(), and then catch the PersistenceException that that throws. I can then log the database error as I want, and throw an EJBException to force rollback. Leaving the container to do the flush seems to irretrievably lose any useful messages with TopLink.
I have the same question : how to get the SQL error message generated from JPA?
I haven't found the solution either but, I added this line in my persistence.xml
<properties>
<property name="toplink.logging.level" value="FINE" />
</properties>
and now, I can see the sql commands issued.
Reference :
http://www.jairrillo.com/blog/2008/09/04/introduction-to-jpa-part-1-getting-started/