My Grails Service calls a plugin which throws a runtime exception. In my case, I don't care about the exception, so it is swallowed.
MyGrailsService {
def myMethod {
...
try {
//callPlugin
} catch (Exception ex) {
...
}
}
}
All fine, exception is caught and processing continues. However, in my Controller, I have a catch (Throwable t) block, which I am not expecting to get executed because the exception is swallowed. It turns out the catch (Throwable t) block is executed because Grails throws a a org.springframework.transaction.UnexpectedRollbackException
which of course I do not want it to do. I guess I am getting this because the exception the plugin throws is runtime, so Grails rolls back the Transaction.
I don't want this UnexpectedRollbackException being thrown.
Any tips?
What i would have done is
class MyService{
static transactional = false
def myMethod {
...
try {
//callPlugin
} catch (Exception ex) {
...
}
}
#Transactional(readOnly = true)
def someMethod {
// Some code here
}
}
The above code will make all the methods in the service non transactional and we will explicitly make the methods transactional which we want.
However once more thing can be a point to be taken care of, the method of the plugin you are calling, that method can itself be a transactional method, which on error may get rolled back and throw a UnexpectedRollbackException. So you have to check it once if the plugin method is transactional.
Related
After checking the answer provided here (https://stackoverflow.com/a/34514526/6613150), I'm able to intercept the message before it's processed.
However, I now need to get it after the method who is annotated with #RabbitListener ends.
Any idea?
Add a MethodInterceptor advice to the container's advice chain instead. That way you have access to the Message before and after the listener call (and notification of any exception thrown).
try {
// before (message is in invocation arguments)
invocation.proceed();
// after
}
catch (Exception e) {
...
throw e;
}
finally {
...
}
I have the following below piece of code when I am running SonarQube for code quality check on it after integrating it with Maven.
However, Sonar is complaining that I should Either log or rethrow this exception.
What am I missing here? Can some one help me please.
Code
public ShippingResponse processShipping(ShippingRequest request) {
log.debug("Processing Reservation Request ....");
try{
return helper.processShippingMethod(request);
} catch (ServiceException serviceException) {
log.error(RESERVATION_EXCE, ExceptionUtils.getStackTrace(serviceException));
throw serviceException;
} catch (Exception e) {
throw new ServiceException(ErrorMessages.EPO_SM_ERR_03, e.getMessage());
}
}
The point that Sonar is trying to make is that you ideally print or keep the root cause of your exception, so basically the stack. You keep it by passing the exception object because if you only keep the message you lose all that information. To make sonar happy you either print the stack trace (log.error(ErrorMessages.EPO_SM_ERR_03, e)), or re-throw a new exception passing the Throwable object to the constructor.
So the ideal solution would be to use the ServiceException like this;
public class ServiceException extends Exception {
public ServiceException(String message, Throwable cause) {
super(message, cause);
}
}
throw new ServiceException(ErrorMessages.EPO_SM_ERR_03, e);
I have the following method:
#Transactional
public Store handle(Command command) {
Store store= mapper.map(command.getStoreDto(), Store.class);
Store persistedStore = storeService.save(store);
addressService.saveStoreAddress(store, command.getEmployeeId()); //this method is not crucial, should be called independently and in another transaction, without any rollback in case of exception
return persistedStore;
}
addressService.saveStoreAddress is not crucial - when this method will throw any exception, store should be saved anyway (storeService.save(store);). What is the best solution in my case?
Use #Transactional(propagation=REQUIRES_NEW) on the saveStoreAddress() such that it will execute in a new and separate transaction.
To prevent the transaction of the handle() will be rollback because of the exception throw from saveStoreAddress() , you also have to try-catch when calling saveStoreAddress().
In the end , it looks something like:
#Service
public class AddressService {
#Transactional(propagation=REQUIRES_NEW)
public void saveStoreAdress(.....){
}
}
#Transactional
public Store handle(Command command) {
.......
try{
addressService.saveStoreAddress(store, command.getEmployeeId());
}catch (Exception ex){
/***
* handle the exception thrown from saveStoreAddress.
* If you want the current transaction not rollback just because of the
* exception throw from saveStoreAddress(), do not re-throw the exception when
* handling this exception
*/
}
return ....;
}
I try save list of entities to Oracle Db.
#Transactional
public void save() {
//logick
for (QuittanceType quittanceType : quittance) {
quittancesService.parseQuittance(quittanceType);
}
//logick
}
On each step I call this method:
#Transactional
#Override
public void parseQuittance(QuittanceType quittance) {
try {
//logick create payToChargeDb
paymentToChargeService.saveAndFlush(payToChargeDb);
} catch (Exception e) {
log.warn("Ignore.", e);
}
}
and method
#Override
public PaymentsToCharge saveAndFlushIn(PaymentsToCharge paymentsToCharge) {
return paymentToChargeRepository.saveAndFlush(paymentsToCharge);
}
When I try save entity with constraint My main transaction rollback and I get stacktrace:
Caused by: java.sql.BatchUpdateException: ORA-02290: CHECK integrity constraint violated(MYDB.PAYMENTS_TO_CHARGE_CHK1)
But I want skip not success entities and save success. I marck my method
#Transactional(propagation = Propagation.REQUIRES_NEW)
and it look like this:
#Transactional
#Override
public void parseQuittance(QuittanceType quittance) {
try {
//logick create payToChargeDb
paymentToChargeService.saveAndFlushInNewTransaction(payToChargeDb);
} catch (Exception e) {
log.warn("Ignore.", e);
}
}
and
#Transactional(propagation = Propagation.REQUIRES_NEW)
#Override
public PaymentsToCharge saveAndFlushInNewTransaction(PaymentsToCharge paymentsToCharge) {
return paymentToChargeRepository.saveAndFlush(paymentsToCharge);
}
But when I try save entity with constraint I not get exception and not enter to catcj block. just stop working debugging and the application continues to work. I do not get any errors. and as if rollback is happening
The proxy created by #Transactional does not intercept calls within the object.
In proxy mode (which is the default), only external method calls
coming in through the proxy are intercepted. This means that
self-invocation (in effect, a method within the target object calling
another method of the target object) does not lead to an actual
transaction at runtime even if the invoked method is marked with
#Transactional. Also, the proxy must be fully initialized to provide
the expected behavior, so you should not rely on this feature in your
initialization code (that is, #PostConstruct).
https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction-declarative
The same documentation recommends use of AspectJ if you want this behaviour.
I am using Spring with Hibernate in my project.There are many methods written in DAO implementation java file and every method is using the same try/catch/finally lines of code which seem redundant to me.
I am told to optimize/refactor the code since the file LOC exceeds 10k.I read somewhere that using HibernateDaoSupport we need not to worry about exceptions or closing the session. It will be taken care of by Spring itself.
Could somebody please help me how to proceed or do the needful or any better way to handle exceptions?I am pasting below code of one method in DAO layer.
public class CSDDaoImpl extends HibernateDaoSupport implements CSDDao {
public Deal getDealStructure(long dealId) throws CSDServiceException {
Session session = null;
try {
session = getSession();
Deal deal = (Deal) session.createCriteria(Deal.class).add(
Restrictions.eq("dealId", dealId)).uniqueResult();
return deal;
} catch (DataAccessResourceFailureException darfex) {
String message = "Failed to retrieve the deal object.";
CSDServiceException ex = new CSDServiceException(message, darfex);
ex.setStackTrace(darfex.getStackTrace());
ex.setErrorCode(Constants.DATA_ACCESS_FAILURE_EXP);
ex.setMessageToUser(message);
throw ex;
} catch (IllegalStateException isex) {
String message = "Failed to retrieve the deal object.";
CSDServiceException ex = new CSDServiceException(message, isex);
ex.setStackTrace(isex.getStackTrace());
ex.setErrorCode(Constants.ILLEGAL_STATE_EP);
ex.setMessageToUser(message);
throw ex;
} catch (HibernateException hbex) {
String message = "Failed to retrieve the deal object.";
CSDServiceException ex = new CSDServiceException(message, hbex);
ex.setStackTrace(hbex.getStackTrace());
ex.setErrorCode(Constants.HIBERNATE_EXP);
ex.setMessageToUser(message);
throw ex;
} finally {
if (session != null && session.isOpen()) {
try {
session.close();
} catch (HibernateException hbex) {
log.error("Failed to close the Hibernate Session.", hbex);
hbex.printStackTrace();
CSDServiceException ex = new CSDServiceException(
"Failed to close the Hibernate Session.", hbex);
ex.initCause(hbex.getCause());
ex.setStackTrace(hbex.getStackTrace());
throw ex;
}
}
}
}
}
The best approach of handling exceptions is i believe through writing an Exception Interceptor to intercept all your DAO calls and you can catch the ones you only need in your application and wrap it with your own custom application specific exceptions.
You definitely do not need to work directly with session once an exception is thrown. That would defeat the purpose of using HibernateDaoSupport and Spring.
Have a look at this link : http://static.springsource.org/spring/docs/current/spring-framework-reference/html/classic-spring.html
Hope that helps.