noRollbackFor not always working on unchecked exceptions (not a duplicate) - spring

I've seen a lot of similar questions but they are usually just tangential to mine.
Here is my code.
#Override //class implements interface
//can also add "rollbackFor = OutOfMemoryError.class" here, to no avail
#Transactional(noRollbackFor = IllegalArgumentException.class)
public ReportTemplate getByCode(final String code)
//throws IllegalArgumentException - see question text
{
if(code == null) {
throw new IllegalArgumentException("ss");
}
}
Consumer (non-transactional) calls this method via autowired interface.
Despite noRollbackFor the transaction (consisting of this method alone) gets rolled back.
Ok I understand people who say "by default it's rollbackFor any unchecked, so since the default is not overridden, that rule still applies". But that should not be true, because that would mean noRollbackFor is useless :) We can try specify rollbackFor as in the comment above, in a hope it will cancel "default" rollbackFor - but this does not help: rollback still happens; looks like this setting is simply added to "default". Worst of all, I can't find a precise specification on how it should work, when noRollbackFor and rollbackFor are covering the same descendant exception (like in my case, RuntimeException vs IllegalArgumentException, who wins?).
Well, I was able to find but one official clarification and it says "the strongest matching rule wins" - but this seems to not be universally corrent, as in my case. Also, for some reason they are overly specific: they say no-rollback-for="InstrumentNotFoundException" means, literally, "any exception other than an InstrumentNotFoundException" would be rolled back (but what about InstrumentNotFoundException's descendants?) And anyway it's greatly outdated: 2.5.x, and newer documentation just says something like "rollbackFor lists exceptions to be rolled back, and noRollbackFor lists exceptions not to be", in a quite contradictory manner, I'd say.
What is even more interesting, the code above stops rolling back if I specify IllegalArgumentException in its "throws" clause. Yes, I don't have to, since its unchecked - but if I do, noRollbackFor finally seems to notice it and behave properly! Does anyone know what manual says this should happen? Or maybe it's a bug?
UPDATE Here are spring transaction logs (in my actual code YargReportTemplateDao$TemplateNotFoundException there is everywhere instead of IllegalArgumentException)
1) with "throws"
[qtp22373939-44] TRACE org.springframework.transaction.interceptor.TransactionInterceptor - Completing transaction for [ru.it.p321.dao.YargReportTemplateDaoImpl.getByCode] after exception: ru.it.p321.dao.YargReportTemplateDaoImpl$1: Yarg template was not found for given code: ITORG_REJECT_NOTIFICATION
[pool-28-thread-1] DEBUG org.springframework.transaction.jta.JtaTransactionManager - Initiating transaction commit
[qtp22373939-44] TRACE org.springframework.transaction.interceptor.RuleBasedTransactionAttribute - Applying rules to determine whether transaction should rollback on ru.it.p321.dao.YargReportTemplateDaoImpl$1: Yarg template was not found for given code: ITORG_REJECT_NOTIFICATION
[qtp22373939-44] TRACE org.springframework.transaction.interceptor.RuleBasedTransactionAttribute - Winning rollback rule is: NoRollbackRuleAttribute with pattern [ru.it.p321.dao.YargReportTemplateDao$TemplateNotFoundException]
2) without "throws
[qtp21176461-48] TRACE org.springframework.transaction.interceptor.TransactionInterceptor - Completing transaction for [ru.it.p321.dao.YargReportTemplateDaoImpl.getByCode] after exception: org.springframework.dao.InvalidDataAccessApiUsageException: Yarg template was not found for given code: ITORG_REJECT_NOTIFICATION; nested exception is ru.it.p321.dao.YargReportTemplateDaoImpl$1: Yarg template was not found for given code: ITORG_REJECT_NOTIFICATION
[qtp21176461-48] TRACE org.springframework.transaction.interceptor.RuleBasedTransactionAttribute - Applying rules to determine whether transaction should rollback on org.springframework.dao.InvalidDataAccessApiUsageException: Yarg template was not found for given code: ITORG_REJECT_NOTIFICATION; nested exception is ru.it.p321.dao.YargReportTemplateDaoImpl$1: Yarg template was not found for given code: ITORG_REJECT_NOTIFICATION
[qtp21176461-48] TRACE org.springframework.transaction.interceptor.RuleBasedTransactionAttribute - Winning rollback rule is: null
[qtp21176461-48] TRACE org.springframework.transaction.interceptor.RuleBasedTransactionAttribute - No relevant rollback rule found: applying default rules

The behavior you see has nothing to do with transaction handling but with exception translation. By default when a class is annotated with #Repository Spring will register a PersistenceExceptionTranslationInterceptor which will translate exceptions to one of the Spring DataAccessExceptions. By default it translates all exceptions UNLESS the exception thrown is declared in the throws clause.
This exception translation happens before the TransactionInterceptor and that way there is never an IllegalArgumentException thrown because that already got translated into something else.

Create your won custom exception (Extending from exception ) and apply noRollBackFor you custom exception class

Related

Changing default rollbackFor behaviour for any Exception

By default, Spring's Transactional annoation won't rollback on checked exceptions.
One can use Transactional's rollbackFor attribute to override this.
Is it possible to override this behaviour globally rather than on each annotation?
I have methods that throw IOException. A possibility could be wrapping those exceptions in RuntimeException, as they are unrecoverable for my code.
There are two approaches that I am aware of:
Create your own Meta-Annotation that handles your particular
transaction semantics
Write an aspect (either around or after-throwing) that wraps all checked exceptions in RuntimeExceptions

ExceptionFilterAttribute not handling properties exceptions

I implemented an ExceptionFilterAttribute class and registered it in the WebApiConfig class.
The action filter works good and handles any exception happened in any action but the problem is: when an exception happens while in any of the controller properties the action filter not handle this exception
[NotImplExceptionFilterAttribute]
public class AnyController : APIController
{
private readonly ModelDBContext _db = new ModelDBContext();
//some actions
}
in the mentioned example, the constructor of ModelDBContext contains some logic which may cause exception. This exception will not be handled by the ExceptionFilterAttribute. Why??? And how to handle it?
basically, simple answer is simple: exception filter is action-level filter.
Check this diagram first: http://blogs.msdn.com/b/kiranchalla/archive/2012/05/06/asp-net-mvc4-web-api-stack-diagram-currently-in-development.aspx
Then navigate to ApiController, line #232. There you can see that if there is at least one filter then ExceptionFilterResult will be used to wrap end action result.
Inside ExceptionFilterResult there is simple try-catch, if exception is thrown then all registered exception filters are called.
So, short summary of everything written above:
1) exception filter is not responsible for handling errors above controller's action
2) exception filter does not exist at the moment when controller's instance is created by DI container and when your ModelDBContext throws an exception
I hope this answers your question.
The problem is scope.
When the controller is instanced the private class member _db will initialize before any class methods execute. This is a CLR behavior.
Thus, an action filter will not catch an exception incurred during construction/initialization of your controller object, such as a failure to construct a ModelDBContext instance.
One solution is to create and dispose of ModelDBContext instances on every request, and some may argue this is the proper approach if you intend to gracefully handle (or log) connectivity failures (whether it's to a DB or a back-end service.)
You may also find IServiceLocator and a framework such as 'Unity' or 'Ninject' useful so that you're not "hardcoding" new ModelDBContext(); statements everywhere, but that's another subject. The root cause is you're initializing outside of the scope of an action method, action filters won't catch it.

Spring nested transaction marked as rollbackonly with unchecked exception

I am fairly new to Spring and transactions. I am sure this question has been asked before, but I still cannot figure the correct way to go about it.
I am using Spring and hibernate. I have a service method that goes like this:
#Transactional
public void processPendingReport(Report report) {
try {
// Do processing stuff, update report object state
reportDAO.save(report);
} catch (Exception e) {
reportDAO.markReportAsFailed(report);
}
}
If a RuntimeException occurs during processing, a "Transaction marked as rollbackOnly" RollbackException will be thrown, having as a result that the report will not be marked as failed (although I would like it to be).
I have tried using #Transactional(noRollbackFor=Exception.class), but still get the same issue.. Any suggestions? Could it be a configuration issue?
If a database exception (e.g. constraint violation) occurs in reportDAO.save() or reportDAO.markReportAsFailed() the transaction will be rolled back on the database level no matter what you are doing on the application level.
You can still mark the report as failed if reportDao.save() fails when you create a new transaction for reportDAO.markReportAsFailed(). Since ReportDAO is annotated #Transactional just remove the #Transactional annotation from the service method. You could also change the reportDAO.save() implementation to use a database function or stored procedure that wraps the insert statement and catches any exceptions on the database level.
HTH.

Spring transaction propagation_required issue

In our java project we are using ORM with hibernate and spring.
I had problems in deleting persistent objects. For example this sample method gets entities by ids and then delete them:
#Transactional
public void remove(List<Long> ids) {
SearchTemplate template = new SearchTemplate();
template.addParameter("milestoneId",ids);
List <InvoiceQueue> items = this.findByCriteria(template);
...
this.delete(items);
}
Method executes Ok without any exception but doesn't actually delete the items from the DB.
Adding the following annotation to the method definition #Transactional(propagation = Propagation.REQUIRES_NEW) solves the problem.
Can anyone explain why it doesn't work with the default propagation type PROPAGATION_REQUIRED.
Thanks in advance.
Environment details :
hibernate.version 3.5.5-Final, spring.version 3.0.5.RELEASE
Really just repeating what #PeterBagyinszki said in his comment, but the reason quite probably is that the transaction within which your delete occurs gets rolled back due to some other part throwing an exception, and all the changes made during the transaction get canceled. With Propagation.REQUIRES_NEW, the delete is done within it's own separate nested transaction. The outcome of the nested transaction (committed or rolled back) won't affect the "outer" transaction and vice versa.
Check your logs to see what is causing the transaction to be rolled back, note that even something like a simple SELECT -query failing with something like NoResultException will cause the transaction to roll back, unless you explicitly state in the #Transactional-annotation it not to roll back on certain exceptions.

Spring - how to handle exception

I am using Spring with Velocity. At times velocity produces an exception like
Error in interpolating string literal : org.apache.velocity.exception.MethodInvocationException: Invocation of method 'getMessage' in class org.springframework.web.servlet.support.RequestContext threw exception class org.springframework.context.NoSuchMessageException : No message found under code 'XX' for locale 'en_US'.
Question is - can I instruct spring to suppress NoSuchMessageException ? I am pretty new to Spring so do not know if I can create a exception handler which will not throw a exception if the message is not found? In my use case, it is a valid use case of not finding some of the messages in the messages.properties file.
[EDIT] - I found a way org.apache.velocity.app.event.MethodExceptionEventHandler to supply an even handler to velocity. I am however not sure how to register it with Spring.
It would be better, I think, to address the problem directly, rather than trying to suppress the exception, which could lead to avoid behaviour and uncompleted operations.
However, you didn't tell us how you'd want the system to respond in cases where the message is not defined for a given code. Do you want a blank String, or should the code itself be used as the default message?
I'm assuming that somewhere in your Spring context you have a defined a messageSource bean of some sort. These MessageSource beans usually have a property useCodeAsDefaultMessage. This defaults to false, but when set to true they will return the code itself as the message, in cases where no message is defined.
Alternatively, you can subclass the MessageSource class (whichever one you're using), and override the getDefaultMessage() method to handle cases where the code cannot be resolved.

Resources