So many hours trying to figure this out, I have read so many questions, forums, answers.. but it still will not update the UI.
My end goal is to take a search term from user, and send a httprequest to PHP scrip that replies with JSON. This works fine so I will not delve into it.
My problem is then updating the UI after this is done. I can get the HTTP results, but for now, I am just trying to update the UI with a basic string before implementing the big changes such as buttons with listeners etc with all the results. For now, just simple String addition to the UI.
The onPreExecute() adds a string to the UI and this works fine somehow, as implemented below.
The problem is in onPostExecute.. like I said, for now, just a String, to test (it will be a list or something eventually). It doesn't work at all, always throwing exception.
public class DisplaySearchActivity extends ListActivity {
ArrayList<String> listItems=new ArrayList<String>();
ArrayAdapter<String> adapter = null;
private class updateUI extends AsyncTask<String, Void, String>{
#Override
protected void onPreExecute() {
listItems.add("Retrieving Results...");
// This actually works just like that
}
#Override
protected String doInBackground(String... message) {
final List<HashMap<String,String>> blist = httpSearch.search(message[0]);
return "It has done";
}
#Override
protected void onPostExecute(String b){
Log.v("ok", "shane - "+ b);
listItems.add("Business: "+ b);
adapter.notifyDataSetChanged();
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_search);
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,listItems);
setListAdapter(adapter);
// final String message = getIntent().getStringExtra("input");
final String message = "third+level";
new updateUI().execute(message);
} // end onCreate
}
Here is the exception
03-15 13:38:41.190: V/ok(15732): shane - It has done
03-15 13:38:41.190: D/AndroidRuntime(15732): Shutting down VM
03-15 13:38:41.190: W/dalvikvm(15732): threadid=1: thread exiting with uncaught exception (group=0x4142a2a0)
03-15 13:38:41.200: E/AndroidRuntime(15732): FATAL EXCEPTION: main
03-15 13:38:41.200: E/AndroidRuntime(15732): java.lang.NullPointerException
03-15 13:38:41.200: E/AndroidRuntime(15732): at ie.whereis.DisplaySearchActivity$updateUI.onPostExecute(DisplaySearchActivity.java:34)
03-15 13:38:41.200: E/AndroidRuntime(15732): at ie.whereis.DisplaySearchActivity$updateUI.onPostExecute(DisplaySearchActivity.java:1)
03-15 13:38:41.200: E/AndroidRuntime(15732): at android.os.AsyncTask.finish(AsyncTask.java:631)
03-15 13:38:41.200: E/AndroidRuntime(15732): at android.os.AsyncTask.access$600(AsyncTask.java:177)
03-15 13:38:41.200: E/AndroidRuntime(15732): at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:644)
03-15 13:38:41.200: E/AndroidRuntime(15732): at android.os.Handler.dispatchMessage(Handler.java:99)
03-15 13:38:41.200: E/AndroidRuntime(15732): at android.os.Looper.loop(Looper.java:137)
03-15 13:38:41.200: E/AndroidRuntime(15732): at android.app.ActivityThread.main(ActivityThread.java:4898)
03-15 13:38:41.200: E/AndroidRuntime(15732): at java.lang.reflect.Method.invokeNative(Native Method)
03-15 13:38:41.200: E/AndroidRuntime(15732): at java.lang.reflect.Method.invoke(Method.java:511)
03-15 13:38:41.200: E/AndroidRuntime(15732): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1006)
03-15 13:38:41.200: E/AndroidRuntime(15732): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:773)
03-15 13:38:41.200: E/AndroidRuntime(15732): at dalvik.system.NativeStart.main(Native Method)
I think it is being thrown by the line:
adapter.notifyDataSetChanged();
But I just don't really understand what the adapter does, even after much reading. I don't know why the
listItems.add("Retrieving Results...");
in pre Execute works :S but the one in post does not.
Any help is so greatly appreciated.
Thank you, I have commented the solution. Apologies for not being able to deal out up votes. <15 karma
IN your Oncreate replace
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,listItems);
with
adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,listItems);
remove the final ArrayAdapter
use
DisplaySearchActivity.this.adapter.notifyDataSetChanged();
instead of
adapter.notifyDataSetChanged();
to access adapter instance from onPostExecute method of updateUI class because you have declared adapter=null
You are hiding instance field adapter in onCreate method.
Instead of
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,listItems);
use
this.adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,listItems);
your adapter is null . the one you set to list is bounded till oncreate() only . don't define again inside oncreate() . simply assing by
adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,listItems);
When you call adapter.notifyDataSetChanged(); the adapter will use the old data, you need to repass the modified list data before calling adapter.notifyDataSetChanged();
Firsty of all, why do you have your adapter declared as final?
It looks like you are trying to modify the view when the activity is not visible. You should instantiate the asynctask to a member variable, and stop it in the onStop method of your Activity: myAsyncTask.cancel(true);
Related
When trying to use Quarkus (version 2.9.2.Final) EventBus requestAndForget with a #ConsumeEvent method that returns void, the following exception occurs in the logs, even though the processing occurs without any problem.
OK
2022-06-07 09:44:04,064 ERROR [io.qua.mut.run.MutinyInfrastructure]
(vert.x-eventloop-thread-1) Mutiny had to drop the following
exception: (TIMEOUT,-1) Timed out after waiting 30000(ms) for a reply.
address: __vertx.reply.3, repliedAddress: receivedSomeEvent
The consumer code:
#ApplicationScoped
public class ConsumerManiac{
#ConsumeEvent(value = "receivedSomeEvent")
public void consume(SomeEvent someEvent ) {
System.out.println("OK");
}
}
The Producer code (a REST Endpoint):
public class SomeResource {
private final EventBus eventBus;
#Inject
public SomeResource (EventBus eventBus) {
this.eventBus = eventBus;
}
#POST
public Response send(#Valid SomeEvent someEvent) {
eventBus.requestAndForget("receivedSomeEvent", someEvent);
return Response.accepted().build();
}
}
If the consumer method is changed to return some value, then the exception in logs does not occur.
#ApplicationScoped
public class ConsumerManiac{
#ConsumeEvent(value = "receivedSomeEvent")
public String consume(SomeEvent someEvent ) {
System.out.println("OK");
return "ok";
}
}
Is there any missing piece of code that is missing so the exception does not occur (even though processing concludes without any problem)?
Reference: https://quarkus.io/guides/reactive-event-bus#implementing-fire-and-forget-interactions
Full stacktrace:
2022-06-07 09:44:04,064 ERROR [io.qua.mut.run.MutinyInfrastructure]
(vert.x-eventloop-thread-1) Mutiny had to drop the following
exception: (TIMEOUT,-1) Timed out after waiting 30000(ms) for a reply.
address: __vertx.reply.3, repliedAddress: receivedSomeEvent at
io.vertx.core.eventbus.impl.ReplyHandler.handle(ReplyHandler.java:76)
at
io.vertx.core.eventbus.impl.ReplyHandler.handle(ReplyHandler.java:24)
at
io.vertx.core.impl.VertxImpl$InternalTimerHandler.handle(VertxImpl.java:893)
at
io.vertx.core.impl.VertxImpl$InternalTimerHandler.handle(VertxImpl.java:860)
at io.vertx.core.impl.EventLoopContext.emit(EventLoopContext.java:50)
at
io.vertx.core.impl.DuplicatedContext.emit(DuplicatedContext.java:168)
at io.vertx.core.impl.AbstractContext.emit(AbstractContext.java:53)
at
io.vertx.core.impl.VertxImpl$InternalTimerHandler.run(VertxImpl.java:883)
at io.netty.util.concurrent.PromiseTask.runTask(PromiseTask.java:98)
at
io.netty.util.concurrent.ScheduledFutureTask.run(ScheduledFutureTask.java:170)
at
io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
at
io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:469)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:503) at
io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)
at
io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at
io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:833)
I had to return arbitrary value to avoid this exception.
I am trying to implement spring-retry(version - 1.3.1) in my spring boot application. I have to retry webservice operation to read the record if not found in first request.
sample code:
#Retryable(include = {IllegalArgumentException.class}, backoff = #Backoff(500), maxAttempts = 3, recover ="readFallback")
Object read(String Id);
#Recover
Object readFallback(RuntimeException e, String Id);
void deletePayment(String paymentId);
Problem :
I am getting correct response from read method(annotated with #Retryable) in exception scenario but I am getting RetryExhaustedException with nested original exception when I am getting exception on my delete method. As you see, delete method doesn't annotated with #Retryable . Delete method is in different package.
**Sample exception response ** : "Retry exhausted after last attempt with no recovery path; nested exception is exception.NotFoundException: Not found"
Expected : Delete method should not be impacted by #Retryable. Can someone help me to find what am i missing or doing wrong. I have tried but unable to not found the solution of this problem on internet.
Thanks in advance !
Works as expected for me:
#SpringBootApplication
#EnableRetry
public class So71546747Application {
public static void main(String[] args) {
SpringApplication.run(So71546747Application.class, args);
}
#Bean
ApplicationRunner runner(SomeRetryables retrier) {
return args -> {
retrier.foo("testFoo");
try {
Thread.sleep(1000);
retrier.bar("testBar");
}
catch (Exception e) {
e.printStackTrace();
}
};
}
}
#Component
class SomeRetryables {
#Retryable
void foo(String in) {
System.out.println(in);
throw new RuntimeException(in);
}
#Recover
void recover(String in, Exception ex) {
System.out.println("recovered");
}
void bar(String in) {
System.out.println(in);
throw new RuntimeException(in);
}
}
testFoo
testFoo
testFoo
recovered
testBar
java.lang.RuntimeException: testBar
at com.example.demo.SomeRetryables.bar(So71546747Application.java:52)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:789)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)
at org.springframework.retry.annotation.AnnotationAwareRetryOperationsInterceptor.invoke(AnnotationAwareRetryOperationsInterceptor.java:166)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698)
at com.example.demo.SomeRetryables$$EnhancerBySpringCGLIB$$e61dd199.bar(<generated>)
at com.example.demo.So71546747Application.lambda$0(So71546747Application.java:26)
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:768)
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:758)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:310)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1312)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301)
at com.example.demo.So71546747Application.main(So71546747Application.java:17)
Please provide an MCRE that exhibits the behavior you see so we can see what's wrong.
I am using annotation "#PreAuthorize" for my resolver class and as a consequence I get AccessDeniedException. That's what i want but it is thrown to my log console on server.
I tried lots of things to get off this error and handle it some way just to maybe print one line for example "unauthorized attempt" but not whole stack trace. Do you have any idea where should I handle it?
2020-05-16 12:21:27.026 WARN 12308 --- [0.1-1100-exec-1] g.e.SimpleDataFetcherExceptionHandler : Exception while fetching data (/somePath) : Access is denied
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84) ~[spring-security-core-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233) ~[spring-security-core-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:65) ~[spring-security-core-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE]```
You can provide your own extension of the AsyncExecutionStrategy and then construct it with your own DataFetchingExceptionHandler like this:
#Component
public class QueryExecutionStrategy extends AsyncExecutionStrategy {
public QueryExecutionStrategy() {
super(new GraphQLExceptionHandler());
}
#Override
public CompletableFuture<ExecutionResult> execute(ExecutionContext executionContext,
ExecutionStrategyParameters parameters)
throws NonNullableFieldWasNullException {
return super.execute(executionContext, parameters);
}
}
While the ExceptionHandler could look something like this:
public class GraphQLExceptionHandler implements DataFetcherExceptionHandler {
private final Logger log = LoggerFactory.getLogger(GraphQLExceptionHandler.class);
#Override
public DataFetcherExceptionHandlerResult onException(DataFetcherExceptionHandlerParameters handlerParameters) {
Throwable exception = handlerParameters.getException();
SourceLocation sourceLocation = handlerParameters.getSourceLocation();
ExecutionPath path = handlerParameters.getPath();
if (exception instanceof AccessDeniedException) {
log.warn("unauthorized to access " +
path);
}
ExceptionWhileDataFetching error = new ExceptionWhileDataFetching(path, exception, sourceLocation);
log.warn(error.getMessage(), exception);
return DataFetcherExceptionHandlerResult.newResult().error(error).build();
}
}
You can also then just completely disable any errors reported to the client by returning a DataFetcherExceptionHandlerResult without any errors attached inside the if statement.
Using spring 4.0.6.RELEASE, Hibernate 4.3.6.Final and hsqldb 2.3.2. My integration test looks like the following;
#Test(expected = DataIntegrityViolationException.class)
public final void testDuplicateItems() {
final ServerEntity serverEntity1 = new ServerEntity("DuplicateItem");
opService.save(serverEntity1);
opService.save(serverEntity1);
}
This works as expected. However, when I run my standalone java component i can save the first item, the second item which is a duplicate is not saved but Im unable to catch the exception. Here is the log file
WARN org.hibernate.engine.jdbc.spi.SqlExceptionHelper: SQL Error: -104, SQLState: 23505
2014-08-27 14:52:06,843 ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper: integrity constraint violation: unique constraint or index violation; UK_NFU7LXMMDFVIR1WD08662085N table: SERVERENTITY
[WARNING]
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:293)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [UK_NFU7LXMMDFVIR1WD08662085N]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.springframework.orm.hibernate4.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:161)
at org.springframework.orm.hibernate4.HibernateTransactionManager.convertHibernateAccessException(HibernateTransactionManager.java:681)
at org.springframework.orm.hibernate4.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:563)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:478)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:272)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy38.execute(Unknown Source)
at com.opserver.simpleapp.MainApp.start(MainApp.java:60)
at com.opserver.simpleapp.MainApp.main(MainApp.java:37)
... 6 more
Both the service and dao implementations have #Transactional at class level. I've a component class that is calling the service class, this component class is not transactional! The component class prints a response, does the session need to be flushed here?
Need to figure out why the save method in the dao is not throwing the exception, I can actually see it an id being created and then rolled back.
J
My component class is very basic;
boolean isValid = opServerService.loadXMLFile("Server.xml");
try{
if (isValid) {
System.out.println("Entity has been added");
} else {
System.out.println("Entity has not been added");
}
}catch (Exception ex){
System.out.println("that was a focked up");
}
The problem is that "Entity has been added" gets printed to console and then I see the above error in console.
DAO looks like this
#Override
#Transactional
public final void save(final ServerEntity serverEntity) throws DataIntegrityViolationException {
LOGGER.debug(">>start(serverEntity=" + serverEntity + ")");
Preconditions.checkNotNull(serverEntity);
this.getCurrentSession().save(serverEntity);
}
Service method with #Transactional at class level, looks like this
#Override
public final void save(ServerEntity serverEntity) {
opServerDao.save(serverEntity);
}
And Component looks like this
#Component
public class AddCommand implements Command {
#Autowired
OpService opService;
public AddServerCommand() {
super();
}
#Override
public void execute(String[] options) {
try{
boolean isValid = opService.save("Server.xml");
if (isValid) {
System.out.println("Entity has been added");
} else {
System.out.println("Entity has not been added");
}
}catch (Exception ex){
System.out.println("Exception found");
}
}
}
You should catch your exception in the component that's calling the service.
Found the solution, was missing from the applicationContext.xml. The wrapped try/catch around the opService now catches the exception. Need to implement my own custom exception handler but for now at least I know the component class is handling the exception which is being thrown from the service class.
Thanks for your help.
J
I am facing an issue since I enabled turned a synchronous method into an asynchronous one: if an exception is thrown from within the body of the method, I can no longer rethrow it.
Let me first show the code:
My async/task executor configuration:
#Configuration
#EnableAsync
public class AsyncConfiguration implements AsyncConfigurer {
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(5);
taskExecutor.setMaxPoolSize(10);
taskExecutor.setQueueCapacity(25);
taskExecutor.initialize();
return taskExecutor;
}
}
My asynchronous method:
#Async
#Override
public void sendPasswordResetInfo(String email) {
Assert.hasText(email);
Member member = memberRepository.findByEmail(email);
try {
mailerService.doMailPasswordResetInfo(member);//EXCEPTION THROWN HERE
} catch (MessagingException | MailSendException e) {
log.error("MessagingException | MailSendException", e);
// TODO: not thrown since #Async is used
throw new MailerException("MessagingException | MailSendException");//NOT CALLED
}
}
All I see in the console when an exception is raised by mailerService.doMailPasswordResetInfo is the following stacktrace:
2014-06-20 18:46:29,249 [ThreadPoolTaskExecutor-1] ERROR com.bignibou.service.preference.PreferenceServiceImpl - MessagingException | MailSendException
org.springframework.mail.MailSendException: Failed messages: javax.mail.SendFailedException: Invalid Addresses;
nested exception is:
com.sun.mail.smtp.SMTPAddressFailedException: 550 5.1.1 Adresse d au moins un destinataire invalide. Invalid recipient. OFR204_418 [418]
; message exception details (1) are:
Failed message 1:
javax.mail.SendFailedException: Invalid Addresses;
nested exception is:
com.sun.mail.smtp.SMTPAddressFailedException: 550 5.1.1 Adresse d au moins un destinataire invalide. Invalid recipient. OFR204_418 [418]
at com.sun.mail.smtp.SMTPTransport.rcptTo(SMTPTransport.java:1294)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:635)
at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:424)
at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:346)
at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:341)
at com.bignibou.service.mailer.MailerServiceImpl.doMailPasswordResetInfo(MailerServiceImpl.java:82)
at com.bignibou.service.preference.PreferenceServiceImpl.sendPasswordResetInfo_aroundBody10(PreferenceServiceImpl.java:112)
at com.bignibou.service.preference.PreferenceServiceImpl$AjcClosure11.run(PreferenceServiceImpl.java:1)
at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96cproceed(AbstractTransactionAspect.aj:59)
at org.springframework.transaction.aspectj.AbstractTransactionAspect$AbstractTransactionAspect$1.proceedWithInvocation(AbstractTransactionAspect.aj:65)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96c(AbstractTransactionAspect.aj:63)
at com.bignibou.service.preference.PreferenceServiceImpl.sendPasswordResetInfo_aroundBody12(PreferenceServiceImpl.java:108)
at com.bignibou.service.preference.PreferenceServiceImpl$AjcClosure13.run(PreferenceServiceImpl.java:1)
at org.springframework.scheduling.aspectj.AbstractAsyncExecutionAspect.ajc$around$org_springframework_scheduling_aspectj_AbstractAsyncExecutionAspect$1$6c004c3eproceed(AbstractAsyncExecutionAspect.aj:58)
at org.springframework.scheduling.aspectj.AbstractAsyncExecutionAspect.ajc$around$org_springframework_scheduling_aspectj_AbstractAsyncExecutionAspect$1$6c004c3e(AbstractAsyncExecutionAspect.aj:62)
at com.bignibou.service.preference.PreferenceServiceImpl.sendPasswordResetInfo(PreferenceServiceImpl.java:108)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.interceptor.AsyncExecutionInterceptor$1.call(AsyncExecutionInterceptor.java:97)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: com.sun.mail.smtp.SMTPAddressFailedException: 550 5.1.1 Adresse d au moins un destinataire invalide. Invalid recipient. OFR204_418 [418]
at com.sun.mail.smtp.SMTPTransport.rcptTo(SMTPTransport.java:1145)
... 28 more
FYI, MailerException is a custom exception I used in the app. What really strikes me is that this MailerException exception does not appear to be caught nor rethrown...
Can anyone please help?
edit 1: I have modified my async service method as follows:
#Async
#Override
public Future<Void> sendPasswordResetInfo(String email) {
Assert.hasText(email);
Member member = memberRepository.findByEmail(email);
try {
mailerService.doMailPasswordResetInfo(member);
return new AsyncResult<Void>(null);
} catch (MessagingException | MailSendException e) {
log.error("MessagingException | MailSendException", e);
//HERE: HOW DO I SEND THE MailerException USING THE FUTURE??
throw new MailerException("MessagingException | MailSendException");
}
}
However, I am not sure how to send the MailerException to the web layer using the AsyncResult from within the catch block above...
Your logs show
2014-06-20 18:46:29,249 [ThreadPoolTaskExecutor-1] ERROR com.bignibou.service.preference.PreferenceServiceImpl - MessagingException | MailSendException
which is logged by
log.error("MessagingException | MailSendException", e);
the Exception that is then thrown
throw new MailerException("MessagingException | MailSendException");//NOT CALLED
is caught by the Thread executed by the underlying ThreadPoolTaskExecutor. This code is run asynchronously so the exception is thrown in a different thread than the thread that invokes the method.
someCode();
yourProxy.sendPasswordResetInfo(someValue()); // exception thrown in other thread
moreCode();
If you make your method return a Future as shown here you'll be able to invoke get() on it and that will rethrow any exception that was thrown inside the #Async method, wrapped in an ExecutionException.
By following this link http://www.baeldung.com/spring-async, you should create:
CustomAsyncExceptionHandler that implements AsyncUncaughtExceptionHandler
#Slf4j
public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
#Override
public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {
log.error("**********************************************");
log.error("Exception message - " + throwable.getMessage());
log.error("Method name - " + method.getName());
for (Object param : obj) {
log.error("Parameter value - " + param);
}
log.error("**********************************************");
}
}
SpringAsyncConfig that implements AsyncConfigurer
#Configuration
#EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {
#Override
public Executor getAsyncExecutor() {
return new ThreadPoolTaskExecutor();
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new CustomAsyncExceptionHandler();
}
}
The solution i had was fixed by creating a configuration class that extends AsyncConfigurerSupport, since the above solutions did not work in my implementation. In this configuration class, i had to define SimpleAsyncTaskExecutor and an async exception handler. Inside the handler, i checked the throwable instance and based on its value, i implemented the needed behavior:
if ( throwable instanceOf CustomException) {
// TODO add code
} else {
// TODO
}
Reference: Effective advice on spring async exception handler