How To throw RuntimeExcpetions from CompletableFuture.whenComplete exception block? - java

I need to re-throw the runtime exception from the CompletableFuture Exception block to the parent method, but looks like the runtimeException is getting logged at the exception block itself and not propagating back to the parent method. Can anyone please advise/suggest me what I am doing wrong here or is this the right way to throw?
I have a function call like below :
void method1(String msg)
{
try
{
method2(msg);
}
catch(RuntimeException e)
{
throw new CustomException("");
}
}
void method2(String msg)
{
CompletableFuture<Void> future = asyncTask.process(msg);
future.whenComplete((res,ex) ->
if(ex != null)
{
log.error("");
throw RuntimeException("abc");
}
else
{ postProcessTasks(msg);
}
);
}

The calling code doesn't wait for the Future to complete or get the status. Here's the core of what needs to be added.
CompletableFuture<Void> future = asyncTask.process(msg)
.thenAccept(this::postProcessTasks);
try {
future.get();
} catch (ExecutionException e) {
Throwable asyncException = e.getCause();
// .. do something here
}
If you intend to propagate an asynchronous Exception back to the caller then whenComplete is probably not the call to use; It is meant to handle exceptions within the asynch call.

Related

How does Callable return or deal with exceptions?

Im trying to throw an exception in one of the processes under tasks.add (the exception occurs in paymentDao,savePayment() method) , but that exception never shows up in my logs even though I see the thrown exception line being reached in the debugger. I expected the exception to be caught in one of the below catches but it never reaches there. Can someone explain how callable treats an exception that occurs within one of the tasks
private final ExecutorService service = Executors.newFixedThreadPool(100,namedThreadFactory);
List<Callable<Object>> tasks = new ArrayList<>();
try {
if (cacheService.isPayment(
(PaidPending) logProcessor.getCache().asMap().get(fileName), fileName)) {
tasks.add(
() -> {
long startTime = System.currentTimeMillis();
paymentDao.savePayment(paymentR, fileName);
log.info(
"Time taken by savePaymentSummary Key {} : {}",
key,
System.currentTimeMillis() - startTime);
return null;
});
service.invokeAll(tasks);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new CustomException("Failed to insert payment " , e);
} catch (CustomeException e) {
log.error("Error here {}", e);
throw new CustomException("Failed to fetch Payment", e);
}
If a Callable task, c, that you submit to a thread pool throws any Throwable object, th, then th will be stored in the Future object, f, that was returned by the submit(c) call. A subsequent call to f.get() will then throw an ExecutionException, exex, and you can call exex.getCause() to obtain the original Throwable, th.
Your example calls service.invokeAll(tasks), which returns a list of Future objects, but you do not bother to save the list.
Try this:
List<Future<ResultType>> futures = new ArrayList<>();
try {
...
futures = service.invokeAll(tasks);
}
catch (...) {
...
}
...optionally do something else before awaiting results...
for (Future<ResultType> future : futures) {
try {
ResultType result = future.get();
...do something with result...
}
catch (ExecutionException ex) {
Throwable originalException = ex.getCause();
...do something with originalException...
}
}
Note: ResultType is a proxy for whatever your Callable tasks return. I am not sure what type that should be, since in your example, the only value returned is null. Maybe ResultType should just be Object.

What causes BlockingOperationException in Netty 4?

Recently, I find some BlockingOperationException in my netty4 project.
Some people said that when using the sync() method of start netty's ServerBootstrap can cause dead lock, because sync() will invoke await() method, and there is a method called 'checkDeadLock' in await().
But I don't think so. ServerBootstrap use the EventLoopGroup called boosGroup, and Channel use the workerGroup to operation IO, I don't think they will influence each other, they have different EventExecutor.
And in my practice, Deadlock exception doesn't appear in the Netty startup process, most of which occurs after the Channel of the await writeAndFlush.
Analysis source code, checkDeadLock, BlockingOperationException exception thrown is when the current thread and executor thread of execution is the same.
My project code is blow:
private void channelWrite(T message) {
boolean success = true;
boolean sent = true;
int timeout = 60;
try {
ChannelFuture cf = cxt.write(message);
cxt.flush();
if (sent) {
success = cf.await(timeout);
}
if (cf.isSuccess()) {
logger.debug("send success.");
}
Throwable cause = cf.cause();
if (cause != null) {
this.fireError(new PushException(cause));
}
} catch (LostConnectException e) {
this.fireError(new PushException(e));
} catch (Exception e) {
this.fireError(new PushException(e));
} catch (Throwable e) {
this.fireError(new PushException("Failed to send messageā€œ, e));
}
if (!success) {
this.fireError(new PushException("Failed to send message"));
}
}
I know Netty officials advise not to use sync() or await() method, but I want to know what situation will causes deadlocks in process and the current thread and executor thread of execution is the same.
I change my project code.
private void pushMessage0(T message) {
try {
ChannelFuture cf = cxt.writeAndFlush(message);
cf.addListener(new ChannelFutureListener() {
#Override
public void operationComplete(ChannelFuture future) throws PushException {
if (future.isSuccess()) {
logger.debug("send success.");
} else {
throw new PushException("Failed to send message.");
}
Throwable cause = future.cause();
if (cause != null) {
throw new PushException(cause);
}
}
});
} catch (LostConnectException e) {
this.fireError(new PushException(e));
} catch (Exception e) {
this.fireError(new PushException(e));
} catch (Throwable e) {
this.fireError(new PushException(e));
}
}
But I face a new problem, I can't get the pushException from the ChannelHandlerListener.
BlockingOperationException will be throw by netty if you call sync*or await* on a Future in the same thread that the EventExecutor is using and to which the Future is tied to. This is usually the EventLoop that is used by the Channel itself.
Can not call await in IO thread is understandable. However, there are 2 points.
1. If you call below code in channel handler, no exception will be reported, because the the most of the time the check of isDone in await returns true, since you are in IO thread, and IO thread is writing data synchronously. the data has been written when await is called.
ChannelPromise p = ctx.writeAndFlush(msg);
p.await()
If add a handler in different EventExecutorGroup, this check is not necessary, since that executor is newly created and is not the same one with the channel's IO executor.

How to catch the exceptions thrown from CompletableFuture.completeExceptionally() while using CompletableFuture.get()?

How to catch the exceptions thrown from CompletableFuture.completeExceptionally() while using CompletableFuture.get()?
Here is some code
public CompletableFuture<Hello> sayHelloAsync() {
CompletableFuture<Hello> future = new CompletableFuture<>();
try{
sayHello(); //throws HelloException
} catch (HelloException ex) {
future.completeExceptionally(new MyException("hello exception"));
return future;
}
return future;
}
Now I want to do .get() or .join on this as follows
CompletableFuture<Hello> resultFuture = sayHelloAsync();
try{
result.get(); // throws ExecutionException but I want to catch My Exception in the simplest way possible but not by throwing another exception while catching the Execution exception and so on.
} catch(ExecutionException ex) {
throw ex.getCause();
} catch (MyException e) {
e.printStackTrace()
}
This is very ugly. Again I just want to catch MyException in few lines of code as possible and in the cleanest way possible. Not sure if isCompletedExceptionally(), exceptionally, join() can help somehow to catch MyException in the easiest way possible. If so how?

rethrow java exception with new message, preserving the exception type if it is in the method declaration list

I am trying to create a helper method that will eliminate the need of having code like this:
void foo() throws ExceptionA, ExceptionB, DefaultException {
try {
doSomething(); // that throws ExceptionA, ExceptionB or others
} catch (Exception e) {
if (e instanceof ExceptionA)
throw new ExceptionA("extra message", e);
if (e instanceof ExceptionB)
throw new ExceptionB("extra message", e);
throw new DefaultException("extra message", e);
}
}
The problem is that I need to maintain the throws list in the function declaration and in the body of the function at the same time. I am looking how to avoid that and to make changing the throws list sufficient and my code to looks like:
void foo() throws ExceptionA, ExceptionB, DefaultException {
try {
doSomething(); // that throws ExceptionA, ExceptionB or others
} catch (Exception e) {
rethrow(DefaultException.class, "extra message", e);
}
}
Where rethrow method will be smart enough to recognize the throws list from the method declaration.
This way when I change the list of type that my method propagates in the throws list I to not need to change the body.
The following is a function that could solve the problem. The problem is because it does not know what type of exception it will throw its throws declaration has to say Exception, but if it does this, the method that is going to use it will need to specify it as well, and the whole idea of using the throws list goes to hell.
Any suggestions how this could be solved?
#SuppressWarnings("unchecked")
public static void rethrow(Class<?> defaultException, String message, Exception e) throws Exception
{
final StackTraceElement[] ste = Thread.currentThread().getStackTrace();
final StackTraceElement element = ste[ste.length - 1 - 1];
Method method = null;
try {
method = getMethod(element);
} catch (ClassNotFoundException ignore) {
// ignore the Class not found exception - just make sure the method is null
method = null;
}
boolean preserveType = true;
if (method != null) {
// if we obtained the method successfully - preserve the type
// only if it is in the list of the thrown exceptions
preserveType = false;
final Class<?> exceptions[] = method.getExceptionTypes();
for (Class<?> cls : exceptions) {
if (cls.isInstance(e)) {
preserveType = true;
break;
}
}
}
if (preserveType)
{
// it is throws exception - preserve the type
Constructor<Exception> constructor;
Exception newEx = null;
try {
constructor = ((Constructor<Exception>) e.getClass().getConstructor());
newEx = constructor.newInstance(message, e);
} catch (Exception ignore) {
// ignore this exception we prefer to throw the original
newEx = null;
}
if (newEx != null)
throw newEx;
}
// if we get here this means we do not want, or we cannot preserve the type
// just rethrow it with the default type
Constructor<Exception> constructor;
Exception newEx = null;
if (defaultException != null) {
try {
constructor = (Constructor<Exception>) defaultException.getConstructor();
newEx = constructor.newInstance(message, e);
} catch (Exception ignore) {
// ignore this exception we prefer to throw the original
newEx = null;
}
if (newEx != null)
throw newEx;
}
// if we get here we were unable to construct the default exception
// there lets log the message that we are going to lose and rethrow
// the original exception
log.warn("this message was not propagated as part of the exception: \"" + message + "\"");
throw e;
}
Update 1:
I can use RuntimeException to avoid the need of throws declaration, but in this case I am losing the type of the exception which is one of the most important points.
Ideas how I can resolve this?
I'm guessing that code where you're doing real work (ie. the part where you're not tinkering with exceptions) looks like this.
public void doSomeWork( ... ) throws ExceptionA, ExceptionB, DefaultException
{
try
{
// some code that could throw ExceptionA
...
// some code that could throw OtherExceptionA
...
// some code that could throw ExceptionB
...
// some code that could throw OtherExceptionB
}
catch (Exception e)
{
if( e instanceof ExceptionA )
{
throw new ExceptionA("extra message", e);
}
if( e instanceof ExceptionB )
{
throw new ExceptionB("extra message", e);
}
throw new DefaultException("extra message", e);
}
}
There are two better approaches
First Approach
public void doSomeWork( ... ) throws ExceptionA, ExceptionB, DefaultException
{
// some code that could throw ExceptionA
...
try
{
// some code that could throw OtherExceptionA
...
}
catch (Exception e)
{
throw new DefaultException("extra message", e);
}
// some code that could throw ExceptionB
...
try
{
// some code that could throw OtherExceptionB
}
catch (Exception e)
{
throw new DefaultException("extra message", e);
}
}
Second Approach
public void doSomeWork( ... ) throws ExceptionA, ExceptionB, DefaultException
{
try
{
// some code that could throw ExceptionA
...
// some code that could throw OtherExceptionA
...
// some code that could throw ExceptionB
...
// some code that could throw OtherExceptionB
}
catch (OtherExceptionA | OtherExceptionB e)
{
throw new DefaultException("extra message", e);
}
}
The first approach is good if you want to continue execution at all costs and catch and wrap RuntimeExceptions if you run into them. Generally you don't want to do this, and it's better to let them propagate up, as you probably can't handle them.
The second approach is generally the best. Here you're explicitly pointing out which exceptions you can handle, and dealing with them by wrapping them. Unexpected RuntimeExceptions propagate up, as they should unless you have some way of dealing with them.
Just a general comment: playing with StackTraceElements isn't considered to be a great idea. You may end up getting an empty array from Thread.currentThread().getStackTrace() (although you most likely will not if using a modern Oracle JVM), and the depth of the calling method isn't always length-2, it may be length-1 particularly in older versions of the Oracle JVM.
You can read more about this problem in this question.
To elaborate on what )some) people are telling you, this is MyFunctionFailedException, ofcourse it should be named something more sensible:
public class MyFunctionFailedException extends Exception {
public MyFunctionFailedException(String message, Throwable cause) {
super(message, cause);
}
}
Then your catch block becomes something like this.
try {
...
} catch (Exception e) {
throw new MyFunctionFailedException("extra message", e);
}
If you really want to rethrow a lower level exception, you should use multiple catch blocks. Be aware tho' that not all types of Exceptions necessarily has a constructor that let's you add a cause. And you really should think about why it makes sense for your method to let for instance an uncaught SQLException bubble up the call stack.

How to improve ugly catch block using exception instanceof

Please pay attention: caller throws parentexception only!!
Say that aexception, and bexception inherit from parentexception.
In method af, it throws aexception, bexception and parentexception.
void af() throws aexception, bexception, parentexception {}
The method caller calls af and throw parentexception only.
void caller() throws parentexception
Here we lost the information of subclasses of parentexception.
The method rootCaller calls the method caller and rootcaller can only catch parentexception thrown by caller and using the following exception process catch block:
void rootCaller() {
try {
caller();
} catch(parentexception e) {
if(e instanceof aexception) {
......
} else if(e instanceof bexception) {
......
} else if(e instanceof parentexception) {
......
} else {
......
}
}
This is so ugly and very easy to forget some subclass of parentexception if the subclasses are too many.
Is there anyway to improve such code?
Current answer can not give me any idea:
1, rootCaller cannnot use multi-catch to simplify the process cause caller only throw parentexception.
2, because caller only throw parentexception, there is not any other exception check if the af is changed latter to throws more than aexception and bexception, say cexception.
As others have suggested in the comments, you should be using multiple catch clauses.
void rootCaller() {
try {
caller();
} catch (AException e) {
// ...
} catch (ParentException e) {
// ...
} catch (BException e) {
// ...
} catch (AnotherException e) {
// ...
} catch (Exception e) {
// ...
}
}
The order of the catches matters too. The Exception will be tested against each case in turn and only trigger the first one that matches.
So for example with AException and BException extending ParentException in my above code the catch (BException e) block can never be reached as catch (ParentException e) is reached and executed first.

Categories