Not sure how to handle checked exception in the Mono flow.
return Mono.when(monoPubs)
.zipWhen((monos) -> repository.findById(...))
.map((tuple) -> tuple.getT2())
.zipWhen((org) -> createMap(org))
.map((tuple) -> tuple.getT2())
.zipWhen((map) -> emailService.sendEmail(...))
.flatMap(response -> {
return Mono.just(userId);
});
Here, the sendEmail method is declared with throws Exception.
public Mono<Boolean> sendEmail(...)
throws MessagingException, IOException
So, How to handle this checked exception in the zipWhen flow.
Also, How to handle
.zipWhen((map) -> emailService.sendEmail(...))
if the method returns void.
You need to review implementation of the sendEmail. You cannot throw checked exceptions from the publisher and need to wrap any checked exception into an unchecked exception.
The Exceptions class provides a propagate method that could be used to wrap any checked exception into an unchecked exception.
try {
...
}
catch (SomeCheckedException e) {
throw Exceptions.propagate(e);
}
As an alternative, you could use lombok #SneakyThrows to wrap non-reactive method.
Exceptions are thrown from Mono method, you can use onError* methods to handle the exception the way you like
var result = Mono.just("test")
.zipWhen((map) -> sendEmail())
.onErrorMap(SendEmailException.class, e -> new RuntimeException(e.getMessage()))
.flatMap(Mono::just);
Also it is not very clear from your post that if sendEmail takes param or not, sendEmail is not taking any input, I would just use doOnNext as it is a void method.
Related
I am experimenting a bit with flows in kotlin and asked myself a question: Will my flows be cancelled if one of the operations within the flow throws an exception even If I use .catch?
If not, how can I cancel my flow when an exception occurs even while using .catch?
Example
fun testFlow() = flow {
emit("Test")
emit(Exception("Error"))
emit("Test2") // This should not be emitted
}.catch { e -> println("Showing UI $e") }
Another Example
fun testFlow2() = flow {
emit("Test")
throw Exception("Error")
emit("Test2") // This should not be emitted
}.catch { e -> println("Showing UI $e") }
If the execution of the Flow throws an Exception, it will cancel and complete the Flow during collection. The collect() function call will throw the Exception if the Flow.catch operator was not used.
If you emit an Exception like in your example, it's just another object in the Flow. Since you have not specified the Flow's type, it's implicitly choosing a type that's common between String and Exception. I think you have a Flow<Serializable> since that's a common supertype of both. If you had specified Flow<String>, it would not allow you to emit an Exception.
I'm still learning Kotlin and I just learned about the "use" and how it is a replacement for a try, catch and finally block.
However I am curious if it is possible to customize it's exception handling for example:
var connection: Connection? = null
try {
connection = dataSource.connection
connection.prepareStatement(query).execute()
} catch (e: SQLException) {
logger.log("Specific error for that query")
e.printStackTrace()
} finally {
if (connection != null && !connection.isClosed) {
connection.close()
}
}
That code is my current one, I have a specific error I would like to display on the catch, would that be possible using use?
This is my current use code:
dataSource.connection.use { connection ->
connection.prepareStatement(query).execute()
}
As commented by #Tenfour04, and from the documentation
[use] Executes the given block function on this resource and then closes it down correctly whether an exception is thrown or not.
In particular it is implemented like this:
public inline fun <T : AutoCloseable?, R> T.use(block: (T) -> R): R {
var exception: Throwable? = null
try {
return block(this)
} catch (e: Throwable) {
exception = e
throw e
} finally {
this.closeFinally(exception)
}
}
That piece of code should look familiar if you're a Java developer, but basically it executes block passing this (i.e. the receiver object) as an argument to your block of code. At the end it closes the AutoCloseable resource. If at any point an exception is thrown (either inside block or while closing the resource), that exception is thrown back to the caller, i.e. your code.
As an edge case you could have 2 exceptions, one when executing block and one when closing the resource. This is handled by closeFinally (whose source is available in the same file linked above) and the exception thrown while closing the resource is added as a suppressed exception to the one thrown from block – that's because only up to 1 exception can be thrown by a method, so they had to choose which one to throw. The same actually applies to the try-with-resources statement in Java.
I'm trying to use the inline function use with a FileInputStream instead of the classic try/catch IOException so that
try {
val is = FileInputStream(file)
// file handling...
}
catch (e: IOException) {
e.printStackTrace()
}
becomes
FileInputStream(file).use { fis ->
// do stuff with file
}
My question is, why use the function use if it stills throws exception? Do I have to wrap use in a try/catch? This seems ridiculous.
From Kotlin documentation:
Executes the given block function on this resource and then closes it
down correctly whether an exception is thrown or not.
When you use an object that implements the Closeable interface, you need to call the close() method when you are done with it, so it releases any system resources associated with the object.
You need to be careful and close it even when an exception is thrown. In this kind of situation that is error prone, cause you might not know or forget to handle it properly, it is better to automate this pattern. That's exactly what the use function does.
Your try-catch does not close the resource so you are comparing apples to oranges. If you close the resource in finally block:
val is = FileInputStream(file)
try {
...
}
catch (e: IOException) {
...
}
finally {
is.close()
}
is definitely more verbose than use which handles closing the resource.
I'm developing an application using Play 2.3.1.
I'm annotating all my controllers with the following Action :
#Override
public Promise<Result> call(final Context ctx) throws Throwable {
try {
return delegate.call(ctx);
} catch (MyCustomException e) {
return handleCustomException(e);
} catch (Exception e) {
return handleUnexpectedError(e);
}
}
The aim of this action is to catch any exception thrown by a controller method in order to send a clean message to the user.
MyCustomException is my application specific exception that extends Exception.
The problem is that even if I throw a MyCustomException in the method of my controller, the corresponding catch statement is never executed.
I always have a RuntimeException caused by my MyCustomException.
The consequence is that no matter what exception occured, the user always sees the result sent by handleUnexpectedError(e).
What am I doing wrong ? Thanks.
After some investigation, the guilty is the Security action of Play.
More details here : https://groups.google.com/forum/#!topic/play-framework/AY4NuQziYyM
Because I added my custom actions at AbstractController level and the #Authenticated(Authenticator.class) annotation at the controller level, the security action composition is the last one to be executed.
Because of the Security.java at line 51, even if my exception is expected, Play throws a RuntimeException.
So the solution is to add the security annotation at method level in order to be sure that it is executed before the first execution of the method.
I am currently developing a Windows Phone 7 App that calls a WCF web service which I also control. The service offers an operation that returns the current user's account information when given a user's login name and password:
[ServiceContract]
public interface IWindowsPhoneService
{
[OperationContract]
[FaultContract(typeof(AuthenticationFault))]
WsAccountInfo GetAccountInfo(string iamLogin, string password);
}
Of course, there is always the possibility of an authentication failure and I want to convey that information to the WP7 app. I could simply return null in that case, but I would like to convey the reason why the authentication failed (i.e. login unknown, wrong password, account blocked, ...).
This is my implementation of the above operation (for testing purposes, all it does is throwing an exception):
public WsAccountInfo GetAccountInfo(string iamLogin, string password)
{
AuthenticationFault fault = new AuthenticationFault();
throw new FaultException<AuthenticationFault>(fault);
}
Now, if I call this operation in my WP7 app, like this:
Global.Proxy.GetAccountInfoCompleted += new EventHandler<RemoteService.GetAccountInfoCompletedEventArgs>(Proxy_GetAccountInfoCompleted);
Global.Proxy.GetAccountInfoAsync(txbLogin.Text, txbPassword.Password);
void Proxy_GetAccountInfoCompleted(object sender, RemoteService.GetAccountInfoCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
return;
}
}
The debugger breaks in Reference.cs, saying that FaultException'1 was unhandled, here:
public PhoneApp.RemoteService.WsAccountInfo EndGetAccountInfo(System.IAsyncResult result) {
object[] _args = new object[0];
PhoneApp.RemoteService.WsAccountInfo _result = ((PhoneApp.RemoteService.WsAccountInfo)(base.EndInvoke("GetAccountInfo", _args, result)));
return _result;
}
BEGIN UPDATE 1
When pressing F5, the exception bubbles to:
public PhoneApp.RemoteService.WsAccountInfo Result {
get {
base.RaiseExceptionIfNecessary(); // <-- here
return ((PhoneApp.RemoteService.WsAccountInfo)(this.results[0]));
}
}
and then to:
private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
if (System.Diagnostics.Debugger.IsAttached)
{
// An unhandled exception has occurred; break into the debugger
System.Diagnostics.Debugger.Break();
}
}
After that, the app terminates (with or without the debugger).
END UPDATE 1
Now, I would love to catch the exception in my code, but I am never given the chance, since my Completed handler is never reached.
Based on similar questions on this site, I have already tried the following:
Re-add the service reference --> no change
Re-create a really simple WCF service from scratch --> same problem
Start the app without the debugger to keep the app from breaking into the debugger --> well, it doesn't break, but the exception is not caught either, the app simply exits
Tell VS 2010 not to break on FaultExceptions (Debug > Options) --> does not have any effect
wrap every line in my app in try { ... } catch (FaultException) {} or even catch (Exception) --> never called.
BEGIN UPDATE 2
What I actually would like to achieve is one of the following:
ideally, reach GetAccountInfoCompleted(...) and be able to retrieve the exception via the GetAccountInfoCompletedEventArgs.Error property, or
be able to catch the exception via a try/catch clause
END UPDATE 2
I would be grateful for any advice that would help me resolve this issue.
The framework seems to read your WsAccountInfo.Result property.
This rethrows the exception on client side.
But you should be the first to read this property.
I don't know your AuthenticationFault class, does it have a DataContractAttribute and is it a known type like the example in
http://msdn.microsoft.com/en-us/library/system.servicemodel.faultcontractattribute.aspx ?
I believe I had the same problem. I resolved it by extending the proxy class and calling the private Begin.../End... methods within the Client object rather than using the public auto-generated methods on the Client object.
For more details, please see:
http://cbailiss.wordpress.com/2014/02/09/wcf-on-windows-phone-unable-to-catch-faultexception/