How to use Observable.fromCallable() with a checked Exception? - java

Observable.fromCallable() is great for converting a single function into an Observable. But how do you handle checked exceptions that might be thrown by the function?
Most of the examples I've seen use lambdas and "just work". But how would you do this without lambdas? For example, see the quote below from this great article:
Observable.fromCallable(() -> downloadFileFromNetwork());
It's a one-liner now! It deals with checked exceptions, no more weird Observable.just() and Observable.error() for such easy thing as deferring code execution!
When I attempt to implement the above Observable without a lambda expression, based on other examples I've seen, and how Android Studio auto-completes, I get the following:
Observable.fromCallable(new Func0<File>() {
#Override
public File call() {
return downloadFileFromNetwork();
}
}
But if downloadFileFromNetwork() throws a checked exception, I have to try-catch it and wrap it in a RuntimeException. There's got to be a better way! How does the above lambda support this?!?!

Rather than using a Func0 with Observable.fromCallable(), use Callable. For example:
Observable.fromCallable(new Callable<File>() {
#Override
public File call() throws Exception {
return downloadFileFromNetwork();
}
}
Since Callable's method call() throws Exception, you don't have to wrap your function in a try-catch! This must be what the lambda is using under the hood.

You could also do this to return checked exceptions:
return Observable.fromCallable(() -> {
sharedPreferences.edit()
.putString(DB_COMPANY, LoganSquare.serialize(
CompanyDBTransformation.get(user.getCompany())
))
.apply();
return user;
}).onErrorResumeNext(
throwable -> Observable.error(new CompanySerializationException(throwable))
);
So here I'm serializing taking the IOException risk, and I'm giving back a more descriptive description.

Related

Mocking the CompletableFuture.join() for IntegrationTests

Iam writing the Integration test cases and i was stuck at point where i was not able to mock the
CompletableFuture.join()
Firstly,
I will make an async call and add all the responses to list
#Async("AsyncTaskExecutor")
public <T> CompletableFuture<ResponseEntity<T>> callCarrierPost(
ServiceConfig serviceConfig, Class<T> responseType, ExecutionContext executionContext,
AdapterContext adapterContext) {
ResponseEntity<T> responseEntity = carrierInvoker.postForObject(
serviceConfig, responseType, executionContext, adapterContext);
return CompletableFuture.completedFuture(responseEntity);
}
Once the async call is made then i will process the responses of the async calls like below,
private <T> List<ResponseEntity<T>> processResponseFutureList(List<CompletableFuture<ResponseEntity<T>>> responseEntityFutureList) {
List<ResponseEntity<T>> responseEntityList = new ArrayList<>();
responseEntityFutureList.forEach(responseEntityFuture -> {
try {
responseEntityList.add(responseEntityFuture.join());
} catch (CompletionException ex) {
if (ex.getCause() instanceof HttpStatusCodeException) {
HttpStatusCodeException httpStatusCodeException = ((HttpStatusCodeException) ex.getCause());
ResponseEntity<T> response = new ResponseEntity<>((T) httpStatusCodeException.getResponseBodyAsString(),
httpStatusCodeException.getResponseHeaders(),
httpStatusCodeException.getStatusCode());
responseEntityList.add(response);
} else if (ex.getCause() instanceof ResourceAccessException &&
ex.getCause().getCause() instanceof SocketTimeoutException) {
responseEntityList.add(getErrorResponseEntity(HttpStatus.SERVICE_UNAVAILABLE,
TimeOutException.Code.PROVIDER_TIME_OUT.getVal(), ex.getMessage()));
} else {
responseEntityList.add(getErrorResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR,
InternalServerException.Code.INTERNAL_M2_BROKER_ERROR.getVal(), ex.getMessage()));
}
}
});
return responseEntityList;
}
From processResponseFutureList method, Iam trying to mock the response of the completableFuture.join() to cover all the exceptional scenarios
So i tried to mock completableFuture, but no luck, it was not throwing an exception with below changes, instead it gives the original response.
#MockBean
private CompletableFuture completableFuture;
Mockito.when(completableFuture.join())
.thenReturn(new ResourceAccessException("I/O error on /uri", new SocketTimeoutException("Read Timeout")));
Iam actually new to testing and also never got an chance to work with CompletableFuture
Can someone help to mock the CompletableFuture.join() to throw an exception.
In general, don't mock types you don't own. In particular, CompletableFuture is an enormous API with very complicated semantics and I can't recommend mocking it. (Your team's opinion may vary, but CompletableFuture's large and non-encapsulated API is known as a design issue, particularly in how a CompletableFuture can be controlled from outside its source.)
Furthermore, join will never return a ResourceAccessException, nor throw one directly. Futures represent the result of some other asynchronous process, probably on another thread; if that process throws a ResourceAccessException, then as in the code you posted, join will throw a CompletionException with a getCause() value that is the underlying ResourceAccessException.
In Java 9 or better, you can use failedFuture as a static factory, passing in the raw ResourceAccessException because the real CompletableFuture implementation will wrap it for you:
// You'll probably need to specify your generics here, but I can't see
// enough of your test to fill them in realistically.
CompletableFuture</* ... */> completableFuture
= CompletableFuture.failedFuture(new ResourceAccessException(
"I/O error on /uri",
new SocketTimeoutException("Read Timeout")));
In Java 8, in absence of a static factory as in the SO question "CompletableFuture already completed with an exception", just create a real CompletableFuture and complete it exceptionally (taking advantage of the aforementioned external-control design issue):
CompletableFuture</* ... */> completableFuture
= new CompletableFuture</* ... */>();
completableFuture.completeExceptionally(
new ResourceAccessException(/*...*/));

Java does not catch exception

I am trying to implement lambda expression for constructor. My constructor can throw an IllegalArgumentException. I tried different ways. First way is just calling lambda expression:
catchThrowable(() -> new SomeClass(testVar1, null, testVar2));
It works perfectly fine, I can catch Exception and then parse it. The problem occurs when I try to use my own interface:
interface SomeClassFactory{
SomeClass create (String testVar1, String persId, String testVar2) throws IllegalArgumentException;
}
SomeClassFactory factory = SomeClass::new;
and then I use it as:
catchThrowable((ThrowableAssert.ThrowingCallable) factory.create(testVar1, null, testVar3));
But the last line of code does not catch any exceptions, my code gives runtime exception and stops. Can you please explain why it happens and, if possible, how to fix it?
What happens is that factory.create(...) is executed and the result is passed to catchThrowable, so the exception is actually thrown before the catchThrowable execution.
To fix it, you can either use a lambda:
catchThrowable( () -> factory.create(testVar1, null, testVar3));
or you can define your own interface extending ThrowableAssert.ThrowingCallable:
interface SomeClassFactory extends ThrowableAssert.ThrowingCallable {
#Override
SomeClass call() throws IllegalArgumentException;
}
which would allow you to call:
catchThrowable(factory);
Note that the custom interface does not allow parameters on the overridden method.

Lambda return method which calls method that throws exception

I have following issue.
I'm working within a method 1 and this method 1 should return an object of a certain class.
For my return statement I call another method 2 (which of course returns an object of said class). Though this other method 2 throws an exception. How should I write my return statement in my initial method 1?
Like this?
public class testClass {
public testClass() {
}
public <T> T method1(parameter1, ...) {
if(parameter1) {
return () -> {
try {
method2(parameter1, parameter2...);
}
catch (CloneNotSupportedException ex) {
System.err.print("Error while cloning programmer");
}
};
} else {
return null;
}
}
But I guess if I do this it will only return null?
Should i put the return null after the last bracket? Or should i write this in a totally different way?
Edit. You wrote
Basically normally the exception should never be thrown
That's a perfect usecase for a RuntimeException. It's basically a transparent exception. Users of your code won't see it, but it will appear like a wild Pokemon when something extraordinary happens, and will make your application come to a stop, giving you a chance to fix it.
Your standard code flow won't be affected, and you'll avoid returning a null value.
Lambda expressions aren't allowed to throw checked Exceptions.
CloneNotSupportedException extends Exception.
Now, you have two options
Handle the Exception in-place, as you did
Propagate the Exception by wrapping it in a RuntimeException
return () -> {
try {
method2(parameter1, parameter2...);
} catch (final CloneNotSupportedException e) {
throw YourCustomRuntimeException("Error while cloning", e /* Original cause */);
}
};
This depends on the usecase, but I think CloneNotSupportedException signals a bug, which should be evident to you, developer. So let it surface.
The custom Exception just need to extend RuntimeException, and, maybe, provide additional fields to store relevant data.
YourCustomRuntimeException extends RuntimeException { ... }
Do not throw the base RuntimeException, use custom ones.

Use Lambda to wrap methods with same exception handling

I have dozens of methods that I want to wrap with the same try/catch handling. I think lambdas can help me out here, but I'm having difficulty figuring out the syntax.
Here's the context of what I'm trying to achieve.
method1(..., result -> method2(result, ...));
method2 is a handler for the results of method1. I would like to wrap method2 with a common try/catch statement that's common to a large number of handlers, without having to copy/paste the statement to all handlers.
Note: These are unchecked exceptions.
*edit - Concrete example of what I'm trying to do.
I'm using Vert.x, and they use a common design pattern of Handlers. Here's an example of their SQL interface
query(String sql, Handler<AsyncResult<ResultSet>> resultHandler)
Handler is a simple 1 function interface:
void handle(E event)
So basically, the query defined in "sql" is executed, and the results are sent to the resultHandler. Here would be an example of this in use:
connection.query("SELECT * from table1", asyncResult -> {
// do something with results
}
The above uses their documentation's standard coding style. I personally prefer to handle the results in named functions various reasons, so it changes to:
connection.query("SELECT * from table1", asyncResult -> method1(asyncResult));
void method1(AsyncResult<ResultSet> asyncResult) {
// do something with results
}
I do not have control over the query() interface, so I'm stuck with this pattern. I'm not sure if Tagir's solution will work in this context, but I'll play around with it in the morning.
*edit2 - I should note that I'm trying to wrap method1 in the above example in the exception wrapper, so ideally, I'd add the wrapper call inside the query() call. So what I'm looking for is something like:
connection.query("SELECT * from table1", wrap(asyncResult -> method1(asyncResult)));
Obviously, I can't use it that way, because it'll evaluate the original lambda as a parameter, but conceptually, that's where I want the wrapping to be added.
You may use Runnable functional interface to implement the method which handles exceptions:
public static void handleExceptions(Runnable r) {
try {
r.run();
}
catch(RuntimeException ex) {
ex.printStackTrace();
}
}
And call it like this:
handleExceptions(() -> method2(foo, bar));
If your method2 produces a result, you should determine what will be the default result in case if exception occurred (and you don't rethrow it in the handler). You may use the Supplier functional interface for such case:
public static <T> T handleExceptions(Supplier<T> r, T defaultValue) {
try {
return r.get();
}
catch(RuntimeException ex) {
ex.printStackTrace();
return defaultValue;
}
}
And call like this:
// set result to null if exception occurred
result = handleExceptions(() -> method2(foo, bar), null);
Or
// do not modify the result if exception occurred
result = handleExceptions(() -> method2(foo, bar), result);

Throwing exception from lambda [duplicate]

This question already has answers here:
Java 8 Lambda function that throws exception?
(27 answers)
Closed 7 years ago.
Given this java 8 code
public Server send(String message) {
sessions.parallelStream()
.map(Session::getBasicRemote)
.forEach(basic -> {
try {
basic.sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
});
return this;
}
how do we properly make this IOException be delegated up the stack of the method call? (in nutshell how to make this method throw this IOException ?)
Lambdas in java does not look very friendly to error handling...
My approach would be to sneakily throw it from the lambda, but take care to have the send method declare it in its throws clause. Using the Exceptional class I posted here:
public Server send(String message) throws IOException {
sessions.parallelStream()
.map(Session::getBasicRemote)
.forEach(basic -> Exceptional.from(() -> basic.sendText(message)).get());
return this;
}
This way you're effectively making the compiler "look away" for just a bit, disabling its exception checking at one spot in your code, but by declaring the exception on your send method, you restore the regular behavior for all its callers.
I wrote an extension to the Stream API which allows for checked exceptions to be thrown.
public Server send(String message) throws IOException {
ThrowingStream.of(sessions, IOException.class)
.parallelStream()
.map(Session::getBasicRemote)
.forEach(basic -> basic.sendText(message));
return this;
}
The problem is indeed that all #FunctionalInterfaces used in lambdas do not allow exceptions to be thrown, save for unchecked exceptions.
One solution is using a package of mine; with it, your code can read:
sessions.parallelStream()
.map(Session::getBasicRemote)
.forEach(Throwing.consumer(basic -> basic.sendText(message)));
return this;

Categories