I Have Aspect around Methods in Transactional service.
Unfortunately, when I catch errors by service, another exception is throwed. How can I prevent from this error ?
*I searched for similar question but no-one solutions seems be adequat for my case
#Aspect
#Component
public class ServiceGuard {
#Pointcut("execution(* simgenealogy.service.*.*(..))")
public void persistence() {}
#Around("persistence()")
public Object logPersistence(ProceedingJoinPoint joinPoint) {
try {
Object o = joinPoint.proceed();
return o;
} catch (ConstraintViolationException constraintException) {
// (...)
return null;
} catch (Throwable throwable) {
// (...)
return null;
}
}
}
And error log.
2019-07-29 02:10:37.979 ERROR 11300 --- [ion Thread] s.a.g.s.w.ServiceGuard :
Constraint violation: First Name cannot be empty
2019-07-29 02:10:38.023 ERROR 11300 --- [ion Thread] s.a.g.s.w.ServiceGuard :
Constraint violation: Last Name cannot by empty
Exception in thread "JavaFX Application Thread" org.springframework.transaction.UnexpectedRollbackException: Transaction silently rolled back because it has been marked as rollback-only
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:755)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:714)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:534)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:305)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at
You catch exceptions which probably occur for a reason. Then you just return null as the result of the previously executed (via proceed()) method, probably in situations where another, non-null return value is expected.
As you do not provide any application code, this is speculative, but I assume that the null return value is then assigned to a data property which ought have a non-null value (see the constraint violations in your log). More precisely you set first and last names to null which causes constraint violations which in turn causes your transaction to be rolled back because mandatory data fields are not set.
How to fix this? Either return non-null default values for first/last name (sounds strange, though) or let the original exceptions escalate instead of swallowing them and causing follow-up problems.
Bottom line: Your exception handling is just broken and needs fixing.
Ok I found solution.
#Transactional is also #Arround Aspect. The problem was in ordering aspects. My Guard class wasn't in fact around Transaction. Put #Order(0) on Guard and #Order(1) on #Transactional service solved issue.
Related
I have code like so
#Transactional(propagation = Propagation.NESTED)
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class C1 {
...
public void xxx() {
try {
obj.someMethod();
} catch (Exception e) {
C2.yyy();
}
}
}
public class C2 {
#Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = false)
public void yyy() {
...
}
}
My assumption is that when obj.someMethod(); throws a constraint violation exception C2.yyy() should still be able to save stuff to the DB.
However what I see is that when C2.yyy() is called Postgres reports
ERROR: current transaction is aborted, commands ignored until end of transaction block
Why should it do that? After all C2.yyy() should run in a different transaction that should be unaffected by the state of what happened in the invoking code. No?
Update
On further debugging here is what I found - let us say the call stack is like so
#Transactional(readOnly = false, propagation = Propagation.NESTED)
b1.m1()
#Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
b2.m2()
b3.m3()
b4.m4()
My assumption was that the DB code in m4() would execute in a new transaction because of the annotation on b2.m2(). But it seems the code in TransactionAspectSupport.java looks at the transaction annotation only on the current method and not on the stack. When it does not find any #transactional on m4() it assumes REQUIRES. Isn't this incorrect?
As answered here DatabaseError: current transaction is aborted, commands ignored until end of transaction block : "This is what postgres does when a query produces an error and you try to run another query without first rolling back the transaction".
Meaning that you 'obj' should run in its own transaction and roll back on exception.
Regarding the question in the update: REQUIRES_NEW always creates a new transaction, it is both documented and tested.
I'm working in a Grails application that uses a remote Rice 2.3.6 (embedded in Kuali Coeus 5.2.1) as an IAM backend. Many aspects of this are successful! But this one is not:
org.kuali.rice.kim.api.role.RoleService kimRoleServiceClient
...
kimRoleServiceClient.assignPrincipalToRole(
principalId,
role.namespace,
role.name,
qualifiers)
kimRoleServiceClient.principalHasRole(
principalId,
[kimRoleServiceClient.getRoleIdByNamespaceCodeAndName(
role.namespace,
role.name)],
qualifiers) // returns true, as expected
kimRoleServiceClient.removePrincipalFromRole(
principalId,
role.namespace,
role.name,
qualifiers)
kimRoleServiceClient.principalHasRole(
principalId,
[kimRoleServiceClient.getRoleIdByNamespaceCodeAndName(
role.namespace,
role.name)],
qualifiers) // returns true (unexpected behavior)
No error is returned, either as a result of the call or as an exception logged in the remote KC catalina.out. I can verify in the KC UI that the role is still assigned, and it's not a caching issue between the two calls -- I can wait a respectable amount of time and the role is still assigned.
Any clues?
EDIT:
It was suggested on the rice.collab mailing list that the problem may be related to KULRICE-9835: removePrincipalFromRole uses attribute id instead of attribute name in qualifier, which is marked as fixed in Rice 2.5.1. This might present a further hurdle, but at the moment this call fails even for roles with no qualifier, i.e. when qualifiers in the call above is an empty Map.
Your edit comments that you are not passing qualifiers however the code throws an exception in this case looking at the code ? Could this be your issue ?
./rice-middleware/kim/kim-impl/src/main/java/org/kuali/rice/kim/impl/role/RoleServiceImpl.java
#Override
public void removePrincipalFromRole(String principalId, String namespaceCode, String roleName,
Map<String, String> qualifier) throws RiceIllegalArgumentException {
if (StringUtils.isBlank(principalId)) {
throw new RiceIllegalArgumentException("principalId is null");
}
if (StringUtils.isBlank(namespaceCode)) {
throw new RiceIllegalArgumentException("namespaceCode is null");
}
if (StringUtils.isBlank(roleName)) {
throw new RiceIllegalArgumentException("roleName is null");
}
if (qualifier == null) {
throw new RiceIllegalArgumentException("qualifier is null");
}...
I have a situation where we update an entity data and then based on certain type of updates we may update another entity as well.
There are situations when the updation in the second entry may fail for some reasons and throw exceptions.
The question is how to handle this situation as we would like to rollback the changes done in the first entity.
We cannot defer the update to the first entry until the second entry update.
In the current situation if that happens then
as soon as the code reach the below block then it will commit the first entry changes even there are failures in 2nd entity update. so how to rollback? I think not closing the persistentManager if 2nd entity update is failed is not the right option.
finally {
try {
if (pm != null && pm.isClosed() == false )
pm.close();
} catch (Exception e) {
log.severe("Exception in finally of execute of updateDonor");
log.severe("Exception class is :" + e.getClass().getName());
log.severe("Exception is :" + e.getMessage());
throw new Exception(e.getMessage()
+ "Unable to close persistence manager");
}
log.info("end of updateDonor");
}
I'm not sure I fully understand your situation, but would cross-group (XG) transactions, which allow a transaction to be applied to entities from more than one entity group, be what you are looking for? Search for 'cross-group transactions on this page as well. With an XG transaction, either all changes to the entities encompassed by the transaction go through, or none do.
I have a service hosted in a WPF application with an async method with the Begin/end methods, and when I catch an exception in the service, I want to throw a faultException to warn to the client.
However, when I try to throw the faultException, the host application crash, shutdown suddenly.
In my repository, I catch the UpdateException, then, I create a custom exception, UniqueKeyException, that is throw to the caller. The caller is an auxiliar method that is called in the Begin method.
This auxiliar method, catch the UniqyeKeyException and only do a "throw", that is capture in the try/catch block of my end method. Here there is something that I don't understand, why in the end mehod this exception is catched in the block of AgregateException instead of the UniqueKeyException.
Well, anyway, in the catch block of the end method, in the AgregateException block, I check if the innerException is UniqueKeyException, if it is true, I create an object UniqueKeyArgs (a custom class with the information to send to the client), create a FaultException and finally do the throw FaultException. It is in this step, the throw, where the host application crash.
I think that I have all configure correctly, because my custom class UniqueKeyArgs is decorate as Datacontract and its properties as DataMember, in the app.config of my host application I configure the behavior to include exception details and in the contract I decorate it with faultContract.
Why the application crash?
My code is the following:
REPOSITORY
public List<Usuers> updateUsers(List<Users> paramUsers)
{
....
catch(UpdateException ex)
{
SqlException innerEx = (SqlException)ex.InnerException;
//Code 2627 is Unique Key exception from SQL Server.
if (innerEx != null && innerEx.Number == 2627)
{
//I create the conditions of searching
ConditionsUsers conditions = new conditions();
conditions.UserName = (Users)ex.StateEntries[0].Entity).userName;
//Search for the existing user
Users myUser = getUser(conditions);
string message = "the user " + conditions.userName + " exists.";
throw new UniqueKeyException(message, myUser);
}
throw;
}
SERVICE IMPLEMENTATION
//This is my auxiliar method, called in the Begin method.
private submitUpdates()
{
....
catch(UniqueKeyException ex)
{
//The code enter here
throw;
}
}
public IAsyncResult BeginUpdateUsers(List<users> paramUsers, AsyncCallback callback, object state)
{
Task<List<Users>> myTask= Task<List<Users>>.Factory.StartNew(p => sumbmitUpdates(paramUsers), state);
return myTask.ContinueWith(res => callback(myTask));
}
public List<Users> EndUpdateusers(IAsyncResult result)
{
try
{
return ((Task<List<Users>>)result).Result;
}
//Why agregateException and not is catched in the UniqueKeyException ???
catch(AgregateException ex)
{
if (innerExceptions[0] is UsuariosValorUnicoException)
{
//I assign manually the data to debug, to discard other problems.
Users myUser = new Users();
myUser.UserName = "Jhon";
myUser.Password = "pass123";
UniqueKeyArgs myArgs = new UniqueUserArgs("unique key error", myUser);
FaultException<UniqueKeyArgs> myException = new FaultException<UniqueKeyArgs>(myArgs);
//Crash here, in the throw myException
throw myException;
}
}
throw;
}
MY CONTRACT
[FaultContract(typeof(UniqueKeyArgs))]
IAsyncResult BeginUpdateUsers(List<Users> paramUser, AsyncCallback callback, object state);
List<Users> EndUpdateUsers(IAsyncResult result);
Crash when I throw myException in the End method.
I see in this post that the solution is catch the exception in the host application too, not only in the service object. However, this solution uses Application.ThreadException, that belong to System.Windows.Forms namespace, and I am using a WPF application.
How could I send the exception to the client from a service hosted in a WPF application?
Thanks.
EDIT1: well, I am use a try/catch block in the line where I throw the exception and I see that the error is that I have not indicated a reason, so when I create my FaultException I do:
FaultException<UniqueKeyArgs> myException = new FaultException<UniqueKeyArgs>(myArgs, new FaultReason("DummyReason");
In this case, the exception message is "DummyReason", the message that I set in the FaultReason, so it says me nothing. The FaultException is not throw, and throw the generic exception to the client.
In this case the host application does not shutdown, but close the connection with the client and I have to reconnect.
It seems that the problem is the creaton of the FaultException, but I don't see the problem.
#Roeal suggests that perhaps is only possible to use faultException with synch methods, but in this link I can see an example in which is used with async methods. I have seen others examples, is not the unique.
Thanks.
EDIT2: I solve my problem. My problem is that in the FaultException, T is an object that have a property that was a self tracking entity, and this is a problem, if I am not wrong, I only can use basic types as properties of the exception.
Then, in the exception, I have implmemented ISerialize. It's needed to be able to send the information to the client, without this, the client receives an exception.Detail with null properties.
Did you also declare the synchronous operation in your service contract? In that case, maybe this helps:
If fault contracts are defined on the service operation contract, the FaultContract attribute should be applied only on the synchronous operations.
-- Juval Lowy, "Programming WCF Services 3rd Edition" (p456)
I solve my problem. My problem is that in the FaultException, T is an object that have a property that was a self tracking entity, and this is a problem, if I am not wrong, I only can use basic types as properties of the exception.
Then, in the exception, I have implmemented ISerialize. It's needed to be able to send the information to the client, without this, the client receives an exception.Detail with null properties.
I have a script which sends a set of records into a file. I'm using Try - Catch block to handle the exceptions. In the catch block I have a code where it has the pointer to next record. But this is not executing . Basically I wan to skip the bad record n move to next record.
while(currentrecord)
{
try
{
writerecord event
}
catch
{
currentrecord = next record
}
}
In most languages (unless you're using something very strange), If 'writerecord event' doesn't throw an exception, the catch block will not be called.
Don't you mean :
while(currentrecord) {
try { writerecord event }
catch { log error }
finally { currentrecord = next record}
}
Are you trying to loop through some records that are returned by a query? Do something like this:
var yourBusObject = TheApplication().GetBusObject("Your Business Object Name");
var yourBusComp = yourBusObject.GetBusComp("Your Business Component Name");
// activate fields that you need to access or update here
yourBusComp.ClearToQuery();
// set search specs here
yourBusComp.ExecuteQuery(ForwardOnly);
if (yourBusComp.FirstRecord()) {
do {
try {
// update the fields here
yourBusComp.WriteRecord();
} catch (e) {
// undo any changes so we can go to the next record
// If you don't do this I believe NextRecord() will implicitly save and trigger the exception again.
yourBusComp.UndoRecord();
// maybe log the error here, or just ignore it
}
} while (yourBusComp.NextRecord());
}
You can use try-finally structure so that whatever inside the finally block will always be executed, regardless of whether the code throws an exception or not. It's often used to clean up resources such as closing files or connections. Without a catch clause, any thrown exception in your try block will abort execution, jump to your finally block and run that code.
Agree that 'finally' might be the best bet here - but do we know what the exception actually is ? - can you output it in your catch loop, so that :
A) you can prove an exception is being thrown (rather than say a 'null' being returned or something)
B) Make sure the exception you get isn't something that could prevent 'nextrecord' working as well...[not sure what the 'finally' would achieve in the case - presumably the exception would have to bubble up to calling code?
So you're trying to move onto the next record if you failed to commit this one. Robert Muller had it right. To explain...
If the WriteRecord fails, then the business component will still be positioned on the dirty record. Attempting to move to the next record will make the buscomp try to write it again--because of a feature called "implicit saving".
Solution: You'll have to undo the record (UndoRecord) to abandon your failing field changes before moving onto the next one.