Expecting the same results from these two CompletableFutures - java

However testCase2 does not handles the exception and throws an error. Am I missing something? Sorry if I did, quite new to this.
#Test
public void testCase1() throws Exception {
CompletableFuture.supplyAsync(() -> {
if (true) throw new RuntimeException();
return "Promise";
}).exceptionally((ex) -> {
return "Fake Promise";
}).get();
}
#Test
public void testCase2() throws Exception {
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
if (true) throw new RuntimeException();
return "Promise";
});
cf.exceptionally((ex) -> {
return "Fake Promise";
});
cf.get();
}

However testCase2 does not handles the exception
Your testCase2 did handled the exception, you can add extra print statement to check it.
The reason testCase2 throws an Exception is that code:
cf.exceptionally((ex) -> {
System.out.println("Fake Promise: " + System.nanoTime());
return "Fake Promise";
})
will return a new CompletableFuture but you just discard it, the variable cf in cf.get is still not registered with any exception handler. The code should be:
#Test
public void testCase2() throws Exception {
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
if (true) throw new RuntimeException();
return "Promise";
});
CompletableFuture<String> handledCf = cf.exceptionally((ex) -> {
return "Fake Promise";
});
return handledCf.get();
}

Related

I threw CompletionException, but ExecutionException arises. Why?

Below is exception handling java code using CompletableFuture.
I intentionally raise InvalidParameterException in the subthread.
public CompletableFuture<Object> myCompletableFuture() throws CompletionException {
return CompletableFuture.supplyAsync(() -> {
try {
// While doing some tasks...
// InvalidParameterException arises in here...
// ...
});
} catch (Exception e){
throw new CompletionException(e);
}
});
}
(Edited) And above Future is activated by calling whenCompleteAsync.
DeferredResult<Object> myFunc() throws CompletionException {
DeferredResult<Object> deferredResult = new DeferredResult<>();
myCompletableFuture().whenCompleteAsync((result, executor) -> {
if (executor != null) {
deferredResult.setErrorResult(executor);
} else {
deferredResult.setResult(result);
}
});
return deferredResult;
}
What I'v expected:
java.util.concurrent.CompletionException: InvalidParameterException(param:myparam)
Actual:
java.util.concurrent.ExecutionException: InvalidParameterException(param:myparam)
Question:
Why exception wraps ExecutionException instead of CompletionException?

Completable Future getting stuck and halts processing indefintely

Hi can someone help as to why the main in below never completes. When I pass 1 to the test method it get stuck completely. However passing 2 makes the run ok. Want to understand the actual issue and also what would be the correct way to code this.
public class Test {
private static final ScheduledExecutorService EXECUTOR = Executors.newScheduledThreadPool(1, r -> {
Thread t = defaultThreadFactory().newThread(r);
t.setDaemon(true);
return t;
});
public static void main(String[] args) {
Test t = new Test();
t.test(1).toCompletableFuture().join();
System.out.println("DONE");
}
public CompletionStage<Void> run(int i) {
if (i == 1) throw new RuntimeException();
CompletableFuture<Void> future = new CompletableFuture<>();
future.completeExceptionally(new RuntimeException());
return future;
}
public CompletionStage<Void> test(int i) {
CompletableFuture<Void> future = new CompletableFuture<>();
EXECUTOR.schedule(() -> run(i).handle((output, error) -> {
if (error instanceof CompletionException) {
error = error.getCause();
}
if (error != null) {
CompletableFuture<Void> failedFuture = new CompletableFuture<>();
failedFuture.completeExceptionally(error);
return failedFuture;
}
return completedFuture(output);
}).thenCompose(u -> u).thenApply(future::complete).exceptionally(future::completeExceptionally), 0, TimeUnit.SECONDS);
return future;
}
}
EDIT: used solution suggested by holger and working fine. In this solution the handle catches the runtime exception. Why not previously?
public class Test {
private static final ScheduledExecutorService EXECUTOR = Executors.newScheduledThreadPool(1, r -> {
Thread t = defaultThreadFactory().newThread(r);
t.setDaemon(true);
return t;
});
public static void main(String[] args) {
Test t = new Test();
System.out.println("STARTED");
t.test(1).toCompletableFuture().join();
System.out.println("DONE");
}
public CompletionStage<Void> run(int i) {
if (i == 1)
throw new RuntimeException();
CompletableFuture<Void> future = new CompletableFuture<>();
future.completeExceptionally(new RuntimeException());
return future;
}
public CompletionStage<Void> test(int i) {
return completedFuture(i).thenComposeAsync(this::run, r -> EXECUTOR.schedule(r, 0, TimeUnit.SECONDS))
.handle((res, ex) -> {
if (ex == null)
return completedFuture(res);
if (ex instanceof CompletionException) {
ex = ex.getCause();
}
CompletableFuture<Void> failedFuture = new CompletableFuture<>();
failedFuture.completeExceptionally(ex);
return failedFuture;
}).thenCompose(u -> u);
}
}

What is the correct way to handle CompletableFuture exception?

What is the correct way to handle CompletableFuture exception in this situation?
I have a piece of code that return a CompletableFuture, but it has a potential of completeExceptionally.
I want to chain CompletableFuture, but I don't want it to execute the next method if it receive an error.
And I do not want to recover from the error either.
So my solution is throw new CompletionException(error).
public static void main(String[] args) {
calculateThings()
.handle((number, error) -> {
if(error != null) {
throw new CompletionException(error);
}
// ...
})
.thenApply(number -> {
// i don't want this part to execute when error happen!
System.out.println("should not execute");
return 100;
})
.whenComplete((result, error) -> {
if(error != null) {
System.out.println("output this line!"); // <-- output
}
});
}
public static CompletableFuture<Integer> calculateThings() {
CompletableFuture<Integer> future = new CompletableFuture<>();
CompletableFuture.runAsync(() -> {
future.completeExceptionally(new IllegalStateException());
});
return future;
}
Is this correct? I feel like this isn't a right thing to do.
I see a couple of example return failedStage or completedStage but I don't know how to unwrap the object.
Thanks!

Unit testing a void method with Redis async command in java

I'm trying to write a unit test for the following function.
responseHandler and ErrorHandler are both methods that are passes using the Command Pattern
and are used to continue the program's flow.
futureCommand is a lettuce object (Redis implementation in java).
I'm having difficulties with how to test this method since is both using a future and does not return anything.
public void getOfferData(EventRequestContext<? extends BaseEvent> ctx, int offerId, ResponseHandler<T1Offer> responseHandler,
ErrorHandler<Throwable> errorHandler) throws Exception {
String redisKey = keyPrefix + offerId;
RedisFuture<List<String>> futureCommand = connectionWrapper.getHashValues(redisKey, getRequiredParams());
futureCommand.thenAccept(valuesList -> {
TrackerScheduler.processT1GenreicPool.execute(ctx, () -> {
Map<String, String> resultMap = reconstructMapValues(valuesList, getRequiredParams(), redisKey, ctx);
T1Offer offerData;
if(!resultMap.isEmpty()) {
offerData = new T1Offer(resultMap);
} else {
offerData = new T1Offer();
}
if(!offerData.isValid()) {
errorHandler.onError(new Exception("Invalid fields in offerData"));
} else {
responseHandler.onResponse(offerData);
}
});
});
}
My best attempt was to send the assertion using the responseHandler method like this:
#Test
public void getOfferData_offerFullData_parseSuccess() throws Exception {
T1ClickOfferDao.instance.getOfferData(null, Integer.parseInt(OFF_ID), resultOffer -> {
Assert.assertEquals("", resultOffer.getActivationDate());
}, error -> {
});
}
but the Test context is finished before the future is evaluated. And even if I Threas.sleep for a second - the assertion does not affect the test result.
How about
#Test
public void getOfferData_offerFullData_parseSuccess() throws Exception {
final String lock = new String("lock");
T1ClickOfferDao.instance.getOfferData(null, Integer.parseInt(OFF_ID), resultOffer -> {
Assert.assertEquals("", resultOffer.getActivationDate());
synchronized(lock){
lock.notifyAll();
}
}, error -> {
});
synchronized(lock){
try{
lock.wait(1000*2);
} catch (InterruptedException ex) {
fail("Timeout");
}
}
}

Throwing exception from CompletableFuture

I have the following code:
// How to throw the ServerException?
public void myFunc() throws ServerException{
// Some code
CompletableFuture<A> a = CompletableFuture.supplyAsync(() -> {
try {
return someObj.someFunc();
} catch(ServerException ex) {
// throw ex; gives an error here.
}
}));
// Some code
}
someFunc() throws a ServerException. I don't want to handle this here but throw the exception from someFunc() to caller of myFunc().
Your code suggests that you are using the result of the asynchronous operation later in the same method, so you’ll have to deal with CompletionException anyway, so one way to deal with it, is
public void myFunc() throws ServerException {
// Some code
CompletableFuture<A> a = CompletableFuture.supplyAsync(() -> {
try { return someObj.someFunc(); }
catch(ServerException ex) { throw new CompletionException(ex); }
});
// Some code running in parallel to someFunc()
A resultOfA;
try {
resultOfA = a.join();
}
catch(CompletionException ex) {
try {
throw ex.getCause();
}
catch(Error|RuntimeException|ServerException possible) {
throw possible;
}
catch(Throwable impossible) {
throw new AssertionError(impossible);
}
}
// some code using resultOfA
}
All exceptions thrown inside the asynchronous processing of the Supplier will get wrapped into a CompletionException when calling join, except the ServerException we have already wrapped in a CompletionException.
When we re-throw the cause of the CompletionException, we may face unchecked exceptions, i.e. subclasses of Error or RuntimeException, or our custom checked exception ServerException. The code above handles all of them with a multi-catch which will re-throw them. Since the declared return type of getCause() is Throwable, the compiler requires us to handle that type despite we already handled all possible types. The straight-forward solution is to throw this actually impossible throwable wrapped in an AssertionError.
Alternatively, we could use an alternative result future for our custom exception:
public void myFunc() throws ServerException {
// Some code
CompletableFuture<ServerException> exception = new CompletableFuture<>();
CompletableFuture<A> a = CompletableFuture.supplyAsync(() -> {
try { return someObj.someFunc(); }
catch(ServerException ex) {
exception.complete(ex);
throw new CompletionException(ex);
}
});
// Some code running in parallel to someFunc()
A resultOfA;
try {
resultOfA = a.join();
}
catch(CompletionException ex) {
if(exception.isDone()) throw exception.join();
throw ex;
}
// some code using resultOfA
}
This solution will re-throw all “unexpected” throwables in their wrapped form, but only throw the custom ServerException in its original form passed via the exception future. Note that we have to ensure that a has been completed (like calling join() first), before we query the exception future, to avoid race conditions.
For those looking for other ways on exception handling with completableFuture
Below are several ways for example handling Parsing Error to Integer:
1. Using handle method - which enables you to provide a default value on exception
CompletableFuture correctHandler = CompletableFuture.supplyAsync(() -> "A")
.thenApply(Integer::parseInt)
.handle((result, ex) -> {
if (null != ex) {
ex.printStackTrace();
return 0;
} else {
System.out.println("HANDLING " + result);
return result;
}
})
.thenAcceptAsync(s -> {
System.out.println("CORRECT: " + s);
});
2. Using exceptionally Method - similar to handle but less verbose
CompletableFuture parser = CompletableFuture.supplyAsync(() -> "1")
.thenApply(Integer::parseInt)
.exceptionally(t -> {
t.printStackTrace();
return 0;
}).thenAcceptAsync(s -> System.out.println("CORRECT value: " + s));
3. Using whenComplete Method - using this will stop the method on its tracks and not execute the next thenAcceptAsync
CompletableFuture correctHandler2 = CompletableFuture.supplyAsync(() -> "A")
.thenApply(Integer::parseInt)
.whenComplete((result, ex) -> {
if (null != ex) {
ex.printStackTrace();
}
})
.thenAcceptAsync(s -> {
System.out.println("When Complete: " + s);
});
4. Propagating the exception via completeExceptionally
public static CompletableFuture<Integer> converter(String convertMe) {
CompletableFuture<Integer> future = new CompletableFuture<>();
try {
future.complete(Integer.parseInt(convertMe));
} catch (Exception ex) {
future.completeExceptionally(ex);
}
return future;
}
Even if other's answer is very nice. but I give you another way to throw a checked exception in CompletableFuture.
IF you don't want to invoke a CompletableFuture in another thread, you can use an anonymous class to handle it like this:
CompletableFuture<A> a = new CompletableFuture<A>() {{
try {
complete(someObj.someFunc());
} catch (ServerException ex) {
completeExceptionally(ex);
}
}};
IF you want to invoke a CompletableFuture in another thread, you also can use an anonymous class to handle it, but run method by runAsync:
CompletableFuture<A> a = new CompletableFuture<A>() {{
CompletableFuture.runAsync(() -> {
try {
complete(someObj.someFunc());
} catch (ServerException ex) {
completeExceptionally(ex);
}
});
}};
I think that you should wrap that into a RuntimeException and throw that:
throw new RuntimeException(ex);
Or many be a small utility would help:
static class Wrapper extends RuntimeException {
private Wrapper(Throwable throwable) {
super(throwable);
}
public static Wrapper wrap(Throwable throwable) {
return new Wrapper(throwable);
}
public Throwable unwrap() {
return getCause();
}
}
public static void go() {
CompletableFuture<String> a = CompletableFuture.supplyAsync(() -> {
try {
throw new Exception("Just because");
} catch (Exception ex) {
throw Wrapper.wrap(ex);
}
});
a.join();
}
And then you could unwrap that..
try {
go();
} catch (Wrapper w) {
throw w.unwrap();
}

Categories