It is possible to throw exception inside onFailure() method of GWT's RPC call? Because this method will be called later, after server response, I apologize that here may happen something bad..
For example:
public void method() {
try {
rpc.invoke(new AsyncCallback<Void>() {
#Override
public void onSuccess(Void arg0) {}
#Override
public void onFailure(Throwable arg0) {
throw new RuntimeException("Error message"); //HERE
}
});
}
catch (Exception e) {
Window.alert(e.getMessage()); // AND CATCH ABOVE EXCEPTION HERE
}
}
I usually use the following approach on my GWT projects:
1) Create an MyExceptionsHandler:
#Singleton
public class MyExceptionsHandler implements
GWT.UncaughtExceptionHandler,
RpcFailureEvent.Handler, // create corresponding GwtEvent-s
AnyOtherErrorEvent.Handler {
public MyExceptionsHandler(EventBus evenBus) {
eventBus.addHandler(RpcFailureEvent.TYPE, this);
eventBus.addHandler(AnyOtherErrorEvent.TYPE, this);
}
// implement corresponding methods for interfaces
}
2) On entry point:
GWT.setUnchaughtExceptionHandler(myExceptionHandler);
3) In any other place you have an error, which you don't know how to handle:
rpc.invoke(new AsyncCallback<Void>() {
#Override
public void onSuccess(Void arg0) {}
#Override
public void onFailure(Throwable arg0) {
eventBus.fireEvent(new RpcFailureEvent(<any context info you think helpful>));
}
});
Yes, it's possible.
#Override
public void onFailure(Throwable arg0) {
throw new RuntimeException(arg0);
}
This code is absolutely valid. But to what purpose are you creating and throwing a new instance of RuntimeException?
At that if you write
new RuntimeException("Error message")
you lose all information about occurred exception.
And don't forget that in GWT all calls from client to a remote service are handled asynchronously. And the onFailure() callback method are called immediatly when an asynchronous call fails to complete normally.
No, you can't. Well, you can throw the exception, but it won't be handled by the catch block you defined, since the AsyncCallback is an anonymous class that does not run in the same scope and is not called at the same time as your catch block.
You can however try to use GWT.setUncaughtExceptionHandler(), see the details at http://google-web-toolkit.googlecode.com/svn/javadoc/latest/com/google/gwt/core/client/GWT.html.
Related
I have a callback which may throw a custom exception.
I'm trying to throw it, but it's not being catched on the outer scope, nor the compiler let me catch it, it says: "Exception is never thrown is the corresponding try block", even though it is.
this is my code:
public void openAsync(MessageAsyncCallback callback) {
try {
this.sendChannelOpen(this.getChannel(), getChannelOpenData().getFlags(), new MessageAsyncCallback() {
#Override
public void onComplete() throws NanoException {
// INanoPacket message = transport.getMessageByClassName(AudioServerHandshake.class.getName());
INanoPacket message = transport.getMessageByClassName(AudioClientHandshake.class.getName());
Log.info("Got audio server handshake, trying to client-handshake it");
sendClientHandshakeAsync((AudioServerHandshake) message, callback);
}
});
} catch (NanoException e) {
System.exit(-2);
}
}
and it doesn't let me catch NanoException
EDIT:
inside transport.getMessageByClassName I throw a NanoException.
EDIT2:
this is the method who invokes the exception:
public INanoPacket getMessageByClassName(String destClassName) throws NanoException {//} throws NanoException {
long startTime = System.currentTimeMillis(); // fetch starting time
INanoPacket message = this.getMessageFromTCPQueue();
while (!(message.getClass().getName().equals(destClassName)) && isRuntimeValid(startTime)) {
this.insertToTCPQueue(message); // put message back in queue
message = this.getMessageFromTCPQueue();
}
if (!(message.getClass().getName().equals(destClassName))) {
// timeout...
throw new NanoException("Couldn't find destination message: " + destClassName);
}
return message;
}
and I want to handle the exception not even in openAsync but on the method that calls openAsync.
why? because I'm handling messages coming from a remote device, this is why it's async. and I'm using some kind of timeout to wait for a specific message, and if the message isn't coming I want to restart the whole program.
Please notice that in your code you are not invoking onComplete method, you are defining it.
The exception would be thrown in a separate part of the code, possibly separate Thread (as it seems to be async). Therefore the "Exception is never thrown is the corresponding try block" message is right, as the exception will never be thrown when invoking this.sendChannelOpen(...) method.
Your try-catch statement needs to wrap the place where you invoke the onComplete method. As only by invoking onComplete method can you expect NanoException.
EDIT based on comments:
If you need to handle the exception throw in getMessageByClassName you can do it in onComplete method and not rethrow it. If you want to handle it somewhere else, you'd need to provide us the code of sendChannelOpen method or a place where the callback is invoked.
EDIT2 (based on question edits):
Please see the code below, as an example of how you can communicate between threads. I've used Latch, but there are other classes in java.util.concurrent that you may find useful.
BTW, I'm not going into the discussion why you want to restart the whole app on your NanoException, although there might be other options worth considering for recovering from that Exception.
import java.util.concurrent.CountDownLatch;
class NanoException extends Exception {}
interface MessageAsyncCallback {
void onComplete() throws NanoException;
}
public class AsyncApp {
private static final CountDownLatch errorLatch = new CountDownLatch(1);
public static void main(String[] args) {
new AsyncApp().run();
}
void run() {
sendChannelOpen("something", new MessageAsyncCallback() {
#Override
public void onComplete() throws NanoException {
// the whole try-catch-sleep is not really needed, just to wait a bit before exception is thrown
try {
// not needed, just to wait a bit before exception is thrown
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new NanoException();
}
throw new NanoException();
}
});
try {
System.out.println("This is a main thread and we wait here, while the other thread executes...");
errorLatch.await();
System.out.println("Latch has reached 0, will now exit.");
System.exit(-2);
} catch (InterruptedException e) {
System.out.println("Error in main thread.");
System.exit(-1);
}
}
void sendChannelOpen(String notImportant, MessageAsyncCallback troublesomeCallback) {
runSomethingInSeparateThread(troublesomeCallback);
}
void runSomethingInSeparateThread(MessageAsyncCallback troublesomeCallback) {
new Thread(() -> {
try {
troublesomeCallback.onComplete();
} catch (NanoException e) {
System.out.println("You can catch it here, and do system exit here or synchronize with main Thread as below");
errorLatch.countDown();
}
}).start();
}
}
I would like to two have two different methods running in catch and final blocks. I have found AutoCloseable interface, but I need something to fire in case of exception only.
Like:
SomeService service = CreateService().andOpenTransaction()
try {
service.doSomeMessyThingsInsideDB();
} catch (Exception e) {
service.rollbackTransaction();
throw e;
} finally {
service.closeConnection();
}
Is there any way to make it simpler? As I said I am familiar with AutoCloseable, but it helps me only with finally block. I still cannot use it inside the catch.
Well you could define your own interface, and then some static runner method:
public interface ErrorHandlingCloseable extends AutoCloseable {
void run() throws Exception;
void onError(Exception e);
static void execute(ErrorHandlingClosable ehc) throws Exception {
try(ErrorHandlingClosable temp = ehc) {
ehc.run();
} catch(Exception e) {
ehc.onError(e);
throw e;
}
}
}
Which you then could then call like this:
SomeService service = CreateService().andOpenTransaction();
ErrorHandlingCloseable.execute(new ErrorHandlingCloseable() {
public void run() throws Exception { service.doSomeMessyThingsInsideDB(); }
public void onError(Exception e) { service.rollbackTransaction(); }
public void close() throws Exception { service.closeConnection(); }
});
But you see, it's still messy.
You could even implement this interface in your SomeService but then you're restricted that the run() method will always call doSomeMessyThingsInsideDB().
Another way but still similar would be to use Java8 and create a helper functional interface:
public interface ThrowingRunnable {
void run() throws Exception;
}
And then a static method somewhere:
public static void execute(ThrowingRunnable action,
ThrowingRunnable onCatch,
ThrowingRunnable onFinally) throws Exception {
try(AutoCloseable ao = onFinally) {
action.run();
} catch(Exception e) {
onCatch.run();
throw e;
}
}
The interesting part is probably this: try(AutoCloseable ao = onFinally), which "registers" your onFinally method to be called when finally is reached.
This could then be called like this:
execute(
service::doSomeMessyThingsInsideDB,
service::rollbackTransaction,
service::closeConnection
);
You said you are familiar with AutoCloseable, but you don't use it.
Have you considered using try-with-resources statement?
Your code can be simplified to:
try (SomeService service = CreateService().andOpenTransaction()) {
service.doSomeMessyThingsInsideDB();
} catch(exception e){
service.rollbackTransaction();
throw e;
}
Oracle has great doc for that, including examples.
Note: A try-with-resources statement can have catch and finally blocks just like an ordinary try statement. In a try-with-resources statement, any catch or finally block is run after the resources declared have been closed.
Answering your question, this is as simple as it can get.
If your class doesn't implement Closeable then you can either implement it or use finally.
First step: Handling the exception
You evidently want the exception handled before some close. Then you need inside a try-with-resources to handle the exception.
/** throws RuntimeException */
void process(Callable<Void> work, Consumer<Exception> onFail) {
try {
work.call();
} catch (Exception e) {
onFail(e);
}
}
try (SomeService service = CreateService().andOpenTransaction()) {
process(() -> service.doSomeMessyThingsInsideDB(),
e -> {
service.rollbackTransaction();
throw new IllegalStateException(e);
});
}
This is not very satisfactory, but again also integrating the AutoCloseable, might give too few use-cases.
Second step: with AutoCloseable
<SV extends AutoCloseable> void processAutoClosing(Supplier<SV> serviceFactory,
Callable<Void> work, Consumer<Exception> onFail) {
try (SV service = serviceFactory.get()) {
process(work, onFail);
}
}
processAutoClosing(...);
I have a method that has an anonymous inner class. I want to throw an unchecked exception from inside the anonymous inner class, and catch it outside of the class. I'm having trouble doing this.
#Override
public void showAchievements(){
androidLauncher.runOnUiThread(new Runnable() {
#Override
public void run() {
try {
loadingView.showLoadingView();
Games.getAchievementsClient(androidLauncher, signedInAccount)
.getAchievementsIntent()
.addOnSuccessListener(new OnSuccessListener<Intent>() {
#Override
public void onSuccess(Intent intent) {
throw new RuntimeException("Test exception");
}
});
} catch (Exception e){
// Not catching
}
}
});
}
My exception is not being caught. What am I doing wrong?
You are throwing an exception in a callback method.
Either the callback method is never invoked, it is not invoked synchronously, or
the code that ultimately invokes the callback method is catching it.
Without seeing more of your code, it is impossible to say which.
This is because you have to move your try-catch-statement inside the onSuccess method. The listener is called at a later point.
Here is a simple example:
Completable c = Completable.create(new CompletableOnSubscribe() {
#Override
public void subscribe(#NonNull CompletableEmitter e) throws Exception {
throw new Exception("Oh No!");
}
});
try {
c.subscribe(new Action() {
#Override
public void run() throws Exception {
Timber.v("It's ok");
}
});
}
catch (Exception e) {
e.printStackTrace();
Timber.v("Error");
}
In this case, I would have expected the exception to be caught however it causes the app to crash. So how are we supposed to handle the exception thrown by the inner class method?
I know that we could handle this differently by subscribing with a CompletableObserver but that adds extra verbosity that I'd like to avoid and I feel that there must be a way to handle this kind of Exception other the Action consumer wouldn't be very useful.
First of all RxJava already has a mechanism to catch Exceptions, But you need to implement onError Action.
have a look at following code:
Completable c = Completable.create(new CompletableOnSubscribe() {
#Override
public void subscribe(#NonNull CompletableEmitter e) throws Exception {
throw new Exception("Oh No!");
}
})
c.subscribe(new Action() {
#Override
public void run() throws Exception {
Timber.v("It's ok");
}
}, new Consumer<Throwable>() { // Second argument is onError Action
#Override
public void accept(Throwable e) {
// Handle you exception here.
Timber.v("Error");
}
});
Let's come to why your code is unable to catch exception even when you have put everything in try-catch, because exception being thrown is instance of RuntimeException class and your are catching instance of Exception class.
Try using RuntimeException, thrown exception should be caught then.
But it is not ideal way to catch exception instead use onError action described in above code snippet. And if your code is throwing Runtime exception then convert it into Exception using try-catch inside Observables.
Hope it helps.
There is an overload for handling errors:
c.subscribe(new Action() {
#Override
public void run() throws Exception {
Timber.v("It's ok");
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable e) {
e.printStackTrace();
Timber.v("Error");
}
});
What is the requirement in a Service implementation so that the ErrorCallback will be able to print the error message on the UI like.
I tried injecting a ErrorCallback in the Service call code, and when I print the Message object its null.
What should be the Service implementation look like, should I put throws SomeException on the implementation method? Or?
myService.call(new RemoteCallback<String>() {
#Override
public void callback(String response) {
Multimap<String, String> state = ArrayListMultimap.create();
state.put("hash", response);
submit.go(state);
}
}, new ErrorCallback() {
#Override
public boolean error(Message message, Throwable throwable) {
throwable.printStackTrace();
Window.alert("Error: " + message);
return false;
}
}).createmy(my);
Your code should work as stated in the question. The exception thrown by the remote service should be delivered to you in the throwable parameter to your ErrorCallback.error() method.
You only need to put a throws clause on the remote interface if you want to throw a checked exception. Unchecked exceptions should work as you've done it. In fact, there is a disadvantage to declaring checked exceptions on remote interfaces: you will have to surround your RPC calls with a useless try/catch block, like this:
#Remote public interface MyService {
Result dangerousOperation() throws MyCheckedException;
}
and the calling code:
try {
myService.call(new RemoteCallback<Result>() {
#Override
public void callback(final Result result) {
Window.alert("Yay, got a result: " + result);
}
},
new BusErrorCallback() {
#Override
public boolean error(Message message, Throwable throwable) {
Window.alert("Got an exception from the remote service: " + throwable);
return false;
}
}).dangerousOperation();
}
catch (MyCheckedException e) {
throw new AssertionError(); // can't happen: caller stub won't throw this
}
So you're probably better off with the unchecked exception.