Why are exceptions not caught in a Spring Reactive function? - spring-boot

I am trying to catch an exception thrown when running a reactive function (this function returns a Mono. I am using code inspired by
information at the following URL:
https://www.woolha.com/tutorials/project-reactor-error-handling-examples
I have a test application with the following function:
private Mono myMethod() {
return Mono.error(new Exception("My error"));
}
The test code is fairly simple: I simply call the myMethod() function and seek to catch the error:
public void errorProcessor()
{
Mono.defer(()-> myMethod())
.doOnError(exe -> System.out.println("FAILURE! "+exe.getMessage());
.subscribe(System.out::println);
}
What I was expecting was a printout of the failure message I specified. Instead, I am getting a stack trace!
reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.Exception: My error
Caused by: java.lang.Exception: My error
at net.factor3.apps.glucoseserv.control.GlucoseDataControllerTest.myMethod(GlucoseDataControllerTest.java:148) ~[test-classes/:na]
at net.factor3.apps.glucoseserv.control.GlucoseDataControllerTest.lambda$0(GlucoseDataControllerTest.java:177) ~[test-classes/:na]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:44) ~[reactor-core-3.4.18.jar:3.4.18]
at reactor.core.publisher.Mono.subscribe(Mono.java:4400) ~[reactor-core-3.4.18.jar:3.4.18]
at reactor.core.publisher.Mono.subscribeWith(Mono.java:4515) ~[reactor-core-3.4.18.jar:3.4.18]
at reactor.core.publisher.Mono.subscribe(Mono.java:4371) ~[reactor-core-3.4.18.jar:3.4.18]
at reactor.core.publisher.Mono.subscribe(Mono.java:4307) ~[reactor-core-3.4.18.jar:3.4.18]
at reactor.core.publisher.Mono.subscribe(Mono.java:4254) ~[reactor-core-3.4.18.jar:3.4.18]
<the rest left ut for brevity>
I have debugged the errorProcessor() function, only to discover that the doOnError is not being called. None of what I am attempting to
print out is being printed out.This means that while the exception is being generated, it is not being caught.
Why is the doOnError() function not being called on error? How is it that an eception generated is not being properly caught? How does one actually catch and process
an exception in a Reactor- based function?

It turns out that (1) when a failure occurs there is a stack trace printed out and the error message that I put in the doOnError() method is printed out. One can seldom tell, however, exactly when the message would be printed out.
(2) My goal for the test was to be able to process an "error" in a manner similar to the way a try- catch block does. I expected that using the doOnError() function would display my error message and eliminate the stack trace. I was incorrect.
What I needed to use in order to reach my goal was a variation of the subscribe() method, as shown below:
public void errorProcessor()
{
Mono.defer(()-> myMethod())
.subscribe(data->{
System.out.println(data);
},error->{
System.out.println("FAILURE: "+error.getMessage());
});
}
This subscribe variant "catches" the exception in the same way that a catch block does. It outputs my failure message and eliminates the stack trace.

Related

Guidewire Exception handling in UI

when internal Guidewire code throws an exception you get a nicely formatted error message box. However, when custom code throws an exception you are directed to the error page (with the red stack trace text & back to application button). Is there anything in the Guidewire framework to make proper UI handling of errors nicer?
such as: < TextBox value="user.someMethod()"/>
//someMethod code...
try{
return user.someOtherCode()
}catch(e : Exception){
//TODO: gracefully display erorr mesage on page
//e.g. showErrorMessage()
return null
}
You have a simpler way to do this,
The below piece of code can be written in helper class or any Enhancement or even in PCF code tab, this will return a nice formatted error message.
gw.api.util.LocationUtil.addRequestScopedErrorMessage("Your error message")
After some searching through Guidewire OOTB code UserDisplayableExceptions are what you need - answering myself in case someone else has this thought.
function goToPolicy(bulkDocumentDownload : BulkDocDownload_Avi) {
try {
throw new IndexOutOfBoundsException("Ops! some index out of bounds exception was thrown")
} catch (e : Exception) {
throw new com.guidewire.pl.web.controller.UserDisplayableException(e.Message)
}
}

What does "RemoteException" mean in general in HDFS?

1) May anyone help me about the concept of "Remoteexception"? What does it mean in general?
2) Also what does it mean by unwrapRemoteException? Was not sure it means by "if this remote exception wraps up one of the lookupTypes"
/**
* If this remote exception wraps up one of the lookupTypes
* then return this exception.
* <p>
* Unwraps any IOException.
*
* #param lookupTypes the desired exception class.
* #return IOException, which is either the lookupClass exception or this.
*/
public IOException unwrapRemoteException(Class<?>... lookupTypes) {
if(lookupTypes == null)
return this;
for(Class<?> lookupClass : lookupTypes) {
if(!lookupClass.getName().equals(getClassName()))
continue;
try {
return instantiateException(lookupClass.asSubclass(IOException.class));
} catch(Exception e) {
// cannot instantiate lookupClass, just return this
return this;
}
}
// wrapped up exception is not in lookupTypes, just return this
return this;
}
(Hadoop_HDFS_Open_Source: https://github.com/apache/hadoop)
Thanks in advance! Any help will be much appreciated!
1) May anyone help me about the concept of "Remoteexception"? What does it mean in general?
Remote Exception is thrown(created) in the server side. Server throws such exception because client sent invalid request, or server has internal error or something else. The RPC server in the server side serialized the exception, and sent it to client side. Client side deserializes the exception, and gets the exception.
2) Also what does it mean by unwrapRemoteException?
The question is "why we need to wrap exception". First, RemoteException is a wrapper not the real exception. The real exception thrown by server could be AccessControlException(the user has no previleage), FileNotFoundException(invalid request). We wrap them up inside a RemoteException. But why? Because the code is cleaner and more readable.
Was not sure it means by "if this remote exception wraps up one of the lookupTypes"
For example, in DFSClient.java
public HdfsFileStatus getFileInfo(String src) throws IOException {
checkOpen();
try {
return namenode.getFileInfo(src);
} catch(RemoteException re) {
throw re.unwrapRemoteException(AccessControlException.class,
FileNotFoundException.class,
UnresolvedPathException.class);
}
}
If the re wraps a FileNotFoundException, then the getFileInfo only returns the FileNotFoundException. Then the user can see a shorter & cleaner exception message. The user only need to know the file is not found, don't care if it's remote or not.
But if the re wraps a SafeModeException or some unknown exception. It's probably some server's internal bug or configuration error. We throw the re(RemoteException) exactly. So the user can know the error is from remote(server side), even though the user doesn't know the wrapped SafeModeException(or some unknown exception). The user can ask help from tech support.

How does exception dispatching change with an unhandled exception handler?

In short, MSDN describes exception dispatching for user mode application like this:
the debugger gets notified of the first chance exception (if attached)
an exception handler aka. try/catch is invoked (if available)
the debugger gets notified of the second chance exception (if attached)
the system cares about the unhandled exception (typically: terminate the process)
This sequence does not consider the presence of an unhandled exception handler. How does exception dispatching change when an unhandled exception handler is present?
The unhandled exception handlers insert at position 3. The sequence is:
the debugger gets notified of the first chance exception (if attached)
an exception handler aka. try/catch is invoked (if available)
the unhandled exception handlers (note the plural) are called (if available)
the debugger gets notified of the second chance exception (if attached)
the system cares about the unhandled exception (typically: terminate the process)
The following C# program demonstrates it. Depending on the .NET version, you'll a message of another unhandled exception handler, which is the .NET framework printing the exception and the call stack.
using System;
namespace UnhandledException
{
static class Program
{
static void Main()
{
Console.WriteLine("Please attach the debugger now and press Enter.");
Console.ReadLine();
AppDomain.CurrentDomain.UnhandledException += (sender, e) => Unhandled1();
AppDomain.CurrentDomain.UnhandledException += (sender, e) => Unhandled2();
try
{
Console.WriteLine("Throwing now.");
// Will cause a first chance, because in try/catch
throw new Exception("Any exception will do");
}
catch (Exception)
{
// Will cause first chance and second chance, because in NOT try/catch
Console.WriteLine("In catch block.");
throw;
}
}
static void Unhandled1() => Console.WriteLine("In unhandled exception handler 1");
static void Unhandled2() => Console.WriteLine("In unhandled exception handler 2");
}
}
Commands required in the debugger (WinDbg):
.symfix
.reload
sxe clr
g; *** for the breakpoint due to attaching the debugger
g; *** first chance in try/catch
g; *** first chance outside try/catch
g; *** second chance

How to handle only a specific type of Exception using the HandleError and let the rest of the Exceptions be thrown normally?

I'm working on a team-project and I am in the following situation:
I created my own Exception class, and I want all the thrown exceptions of type myException to be handled and automatically redirected to the Error view where I would nicely display the error, which is ok to do. This is what I added in my Web.config:
<customErrors mode="On" defaultRedirect="Error" />
The issue is I want all the rest of the exceptions to be thrown normally, seeing all the information about it, including the stack trace, the source file and the line error, which would be really good for the team-project.
I've tried the [HandleError(ExceptionType=typeof(myException)], but it is no use.
I also tried to override the OnException function of the controller and if the exception is not myException then i would throw it again, but i still get in the Error view.
protected override void OnException(System.Web.Mvc.ExceptionContext filterContext)
{
if (filterContext.Exception.GetType() != typeof(myException)) {
throw filterContext.Exception;
}
base.OnException(filterContext);
}
Any idea which could work?
Thanks.
You may get the result you want by leaving custom errors Off (so that for all the errors you get the stack trace displayed), and redirecting the exceptions you want to the controller/view you need (so that a friendly-looking page will be displayed).
You could define a base controller for all your controllers, and override its OnException method with something like below:
if (filterContext.Exception.GetType() == typeof(YourCustomException))
{
filterContext.ExceptionHandled = true;
filterContext.Result = RedirectToAction("ActionName", "ControllerName", new { customMessage = "You may want to pass a custom error message, or any other parameters here"});
}
else
{
base.OnException(filterContext);
}

Getting an Unhandled Exception in VS2010 debugger even though the exception IS handled

I have an issue with VS2010 where the debugger stops with an Unhandled Exception. However, the exception is definitely handled. In fact, if I put code in the catch block, I'll hit it when I press F5. In Debug -> Exceptions, I definitely do not have the "Thrown" checkbox checked, so IMO there is absolutely no reason for the unhandled exception dialog to pop up...
I can't post the exact code, but will work on a sample soon. The basic idea behind the offending code section is that I have a thread that talks to hardware, and if I have an error talking to it, then I throw a HardwareException. The thread is launched with BeginInvoke, and the exception is caught in the callback handler when I call EndInvoke.
When the exception is thrown in the debugger, I get a messagebox that says 'HardwareException not handled by user code". But it is!!!
EDIT -- Well, this is driving me crazy. I've got sample code that is representative of the code I have in my application, and it looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Messaging;
using System.Threading;
namespace ConsoleApplication1
{
public class HardwareException : ApplicationException
{
public HardwareException( string message) : base(message) {}
}
class Program
{
delegate void HardwareTestDelegate();
static void Main(string[] args)
{
HardwareTestDelegate d = new HardwareTestDelegate( HardwareTestThread);
d.BeginInvoke( HardwareTestComplete, null);
while( true);
}
static void HardwareTestThread()
{
throw new HardwareException( "this is a test");
}
static void HardwareTestComplete( IAsyncResult iar)
{
try {
AsyncResult ar = (AsyncResult)iar;
HardwareTestDelegate caller = (HardwareTestDelegate)ar.AsyncDelegate;
caller.EndInvoke( iar);
} catch( Exception ex) {
Console.WriteLine( "Should see this line without getting an unhandled exception message in the IDE");
}
}
}
}
I throw my HardwareException from the thread, and then handle the exception when EndInvoke is called. I guess Murphy was right, because when I run this sample code, it does what I expect -- i.e. no unhandled exception error message pops up in the IDE!
Here is the response from Microsoft, case 111053102422121. Allen Weng writes the following:
Analysis:
For your information, CLR will re-throw the exception inside the callback when you call EndInvoke(). Below is a simplified version of EndInvoke():
public object EndInvoke(IAsyncResult asyncResult)
{
using (new MultithreadSafeCallScope())
{
ThreadMethodEntry entry = asyncResult as ThreadMethodEntry;
............
if (entry.exception != null)
{
throw entry.exception;
}
}
}
The exception will be handled in the call back function or in the asynchronous method if an exception handler is provided. This is how it works without a debugger attached.
When you run it in VS.NET, the debugger seems checking only the presence of the exception handler in the asynchronous method. If there is no such handler, the debugger would think the exception is not handled and pop up an error message notifying you of this.
Suggestion:
The application should work as expected when you run it stand alone. If the error message is annoying in debugging for you, you can disable it by unchecking “User unhandled” for “Common Language Runtime Exceptions”in the Exception dialog box (Debug|Exceptions or press CTRL+ATL+E). Or you can add try/catch in the asynchronous method. In the latter case, the exception is set to null and won’t be re-thrown in EndInvoke().
I'm having this same problem, so I'll post this possible workaround for posterity's sake:
In your code that throws an exception into the .NET code (HardwareTestThread() in the example above,) catch the exception that's being thrown and wrap it in some esoteric .NET exception type for which you can disable the "user-unhandled" option in the Debug>Exceptions dialog. For my case, I needed to allow an IOException to propagate through some .NET code back to my code, so I just caught the IOException and wrapped in an AppDomainUnloadedException before letting it propagate through the .NET code back to my catch block. I chose AppDomainUnloadedException because user-unhandled is unchecked for it by default and it's in the System.dll assembly, so it was already being imported in my project, though any exception should work, so long as you disable the "user-unhandled" option for it and you don't care that the debugger won't break on that type of exception in the future.
Here's my code that wraps the IOException I was needing to propagate:
public override int Read(byte[] buffer, int offset, int count)
{
try { return innerStream.Read(buffer, offset, count); }
catch (IOException ex) { throw new AppDomainUnloadedException("Exception from innerStream: " + ex.Message, ex); }
}
And here's my code where I'm catching it on the other side of the .NET code it needed to propagate through:
try { bytesRead = sslStream.Read(buffer, offset, count); }
catch (Exception ex) { /* ex handled here. */ }

Resources