How to handle exceptions thrown in DataProvider methods centrallyVaadin & Joda DateTimeVaadin: centralizing custom exception handlingHow to set authorization on View level in VaadinVaadin Table throwing Cannot Convert Object to Number Exception on a manual refreshUsing Navigator in Vaadin's ErrorHandlerVaadin Flow &Spring Boot cant find resource via servlet contextProvide a Converter for data-binding by defining a pair of SerializableFunction objectsWhy setDefaultErrorHandler crash my view in vaadin flow?Vaadin 10+: How do I handle uncaught exceptions?View Constructor with Dependency Injection throws NPE
Cutting numbers into a specific decimals
How to say "I only speak one language which is English" in French?
In how many ways we can distribute 7 distinct balls among 3 students such that everyone gets at least 2 balls?
Was the six engine Boeing-747 ever seriously considered by Boeing?
Is the internet in Madagascar faster than in UK?
The meaning of asynchronous vs synchronous
Inspiration for failed idea?
Why can't you say don't instead of won't?
How to prevent a hosting company from accessing a VM's encryption keys?
Defending Castle from Zombies
Is belaying with a hip belay unsafe?
Why might one *not* want to use a capo?
How to handle inventory and story of a player leaving
Are there any to-scale diagrams of the TRAPPIST-1 system?
What is Soda Fountain Etiquette?
Notice period 60 days but I need to join in 45 days
What does GDPR mean to myself regarding my own data?
Why didn't Doc believe Marty was from the future?
Journal published a paper, ignoring my objections as a referee
What to do about my 1-month-old boy peeing through diapers?
Why does this London Underground poster from 1924 have a Star of David atop a Christmas tree?
Why does glibc's strlen need to be so complicated to run quickly?
Alternatives to Network Backup
What's the point of fighting monsters in Zelda BotW?
How to handle exceptions thrown in DataProvider methods centrally
Vaadin & Joda DateTimeVaadin: centralizing custom exception handlingHow to set authorization on View level in VaadinVaadin Table throwing Cannot Convert Object to Number Exception on a manual refreshUsing Navigator in Vaadin's ErrorHandlerVaadin Flow &Spring Boot cant find resource via servlet contextProvide a Converter for data-binding by defining a pair of SerializableFunction objectsWhy setDefaultErrorHandler crash my view in vaadin flow?Vaadin 10+: How do I handle uncaught exceptions?View Constructor with Dependency Injection throws NPE
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
When a DataProvider fetch or count method throws an exception, e.g. because the user is not authorized, how could I handle these exceptions centrally? I know there is HasErrorParameter
interface to show error views when there is an exception thrown when routing. But these error views are not triggered when DataProvider throws the exception.
Example:
new AbstractBackEndDataProvider<String, Void>()
@Override
protected Stream<String> fetchFromBackEnd(Query<String, Void> query)
...
@Override
protected int sizeInBackEnd(Query<String, Void> query)
throw new UnsupportedOperationException("test");
@Route("failed")
public class FailView extends VerticalLayout
implements HasErrorParameter<UnsupportedOperationException> ...
Even if I do a try catch
within the DataProvider methods, I don't see how I could navigate to the appropriate error view just by using the caught exception and not the view component class (this wouldn't trigger setErrorParameter
method).
BTW: I miss the router exception handling topic in Vaadin Flow 13 documentation. I wonder why they removed it.
vaadin vaadin-grid vaadin-flow vaadin10
add a comment |
When a DataProvider fetch or count method throws an exception, e.g. because the user is not authorized, how could I handle these exceptions centrally? I know there is HasErrorParameter
interface to show error views when there is an exception thrown when routing. But these error views are not triggered when DataProvider throws the exception.
Example:
new AbstractBackEndDataProvider<String, Void>()
@Override
protected Stream<String> fetchFromBackEnd(Query<String, Void> query)
...
@Override
protected int sizeInBackEnd(Query<String, Void> query)
throw new UnsupportedOperationException("test");
@Route("failed")
public class FailView extends VerticalLayout
implements HasErrorParameter<UnsupportedOperationException> ...
Even if I do a try catch
within the DataProvider methods, I don't see how I could navigate to the appropriate error view just by using the caught exception and not the view component class (this wouldn't trigger setErrorParameter
method).
BTW: I miss the router exception handling topic in Vaadin Flow 13 documentation. I wonder why they removed it.
vaadin vaadin-grid vaadin-flow vaadin10
1
This is a known issue/limitation/bug in current HesErrorParameter implementation and there is many issue tickets filed related to this github.com/vaadin/flow/issues/4715 github.com/vaadin/flow/issues/4549 github.com/vaadin/flow/issues/4607 github.com/vaadin/flow/issues/3192
– Tatu Lund
Mar 18 at 8:43
add a comment |
When a DataProvider fetch or count method throws an exception, e.g. because the user is not authorized, how could I handle these exceptions centrally? I know there is HasErrorParameter
interface to show error views when there is an exception thrown when routing. But these error views are not triggered when DataProvider throws the exception.
Example:
new AbstractBackEndDataProvider<String, Void>()
@Override
protected Stream<String> fetchFromBackEnd(Query<String, Void> query)
...
@Override
protected int sizeInBackEnd(Query<String, Void> query)
throw new UnsupportedOperationException("test");
@Route("failed")
public class FailView extends VerticalLayout
implements HasErrorParameter<UnsupportedOperationException> ...
Even if I do a try catch
within the DataProvider methods, I don't see how I could navigate to the appropriate error view just by using the caught exception and not the view component class (this wouldn't trigger setErrorParameter
method).
BTW: I miss the router exception handling topic in Vaadin Flow 13 documentation. I wonder why they removed it.
vaadin vaadin-grid vaadin-flow vaadin10
When a DataProvider fetch or count method throws an exception, e.g. because the user is not authorized, how could I handle these exceptions centrally? I know there is HasErrorParameter
interface to show error views when there is an exception thrown when routing. But these error views are not triggered when DataProvider throws the exception.
Example:
new AbstractBackEndDataProvider<String, Void>()
@Override
protected Stream<String> fetchFromBackEnd(Query<String, Void> query)
...
@Override
protected int sizeInBackEnd(Query<String, Void> query)
throw new UnsupportedOperationException("test");
@Route("failed")
public class FailView extends VerticalLayout
implements HasErrorParameter<UnsupportedOperationException> ...
Even if I do a try catch
within the DataProvider methods, I don't see how I could navigate to the appropriate error view just by using the caught exception and not the view component class (this wouldn't trigger setErrorParameter
method).
BTW: I miss the router exception handling topic in Vaadin Flow 13 documentation. I wonder why they removed it.
vaadin vaadin-grid vaadin-flow vaadin10
vaadin vaadin-grid vaadin-flow vaadin10
asked Mar 17 at 18:53
Steffen HarbichSteffen Harbich
1,93619 silver badges43 bronze badges
1,93619 silver badges43 bronze badges
1
This is a known issue/limitation/bug in current HesErrorParameter implementation and there is many issue tickets filed related to this github.com/vaadin/flow/issues/4715 github.com/vaadin/flow/issues/4549 github.com/vaadin/flow/issues/4607 github.com/vaadin/flow/issues/3192
– Tatu Lund
Mar 18 at 8:43
add a comment |
1
This is a known issue/limitation/bug in current HesErrorParameter implementation and there is many issue tickets filed related to this github.com/vaadin/flow/issues/4715 github.com/vaadin/flow/issues/4549 github.com/vaadin/flow/issues/4607 github.com/vaadin/flow/issues/3192
– Tatu Lund
Mar 18 at 8:43
1
1
This is a known issue/limitation/bug in current HesErrorParameter implementation and there is many issue tickets filed related to this github.com/vaadin/flow/issues/4715 github.com/vaadin/flow/issues/4549 github.com/vaadin/flow/issues/4607 github.com/vaadin/flow/issues/3192
– Tatu Lund
Mar 18 at 8:43
This is a known issue/limitation/bug in current HesErrorParameter implementation and there is many issue tickets filed related to this github.com/vaadin/flow/issues/4715 github.com/vaadin/flow/issues/4549 github.com/vaadin/flow/issues/4607 github.com/vaadin/flow/issues/3192
– Tatu Lund
Mar 18 at 8:43
add a comment |
1 Answer
1
active
oldest
votes
I believe all Exceptions that don't occur while routing will be given to the ErrorHandler of the VaadinSession the error occured in.
The best way to set the ErrorHandler seems to be to override the sessionInit
method in a custom SessionInitListener
You can add a custom SessionInitListener
inside the servletInitialized
method of a custom VaadinServlet.
class CustomServlet extends VaadinServlet
@Override
protected void servletInitialized() throws ServletException
super.servletInitialized();
getService().addSessionInitListener(new CustomSessionInitListener());
And that SessionInitListener
(in this example CustomSessionInitListener
) has to set the errorHandler of the sessions that get initialized.
class CustomSessionInitListener implements SessionInitListener
@Override
public void sessionInit(SessionInitEvent event) throws ServiceException
event.getSession().setErrorHandler(new CustomErrorHandler());
For further information on how to create your own Servlet take a look at Vaadin's tutorial page(you need to scroll down to "Customizing Vaadin Servlet")
Edit:
To show the error page you need to get Vaadin to reroute to an error. To achieve that we can use an BeforeEnterEvent
, BeforeEnterEvents
have a rerouteToError
method which we can use to let Vaadin show our ErrorView.
But we also want to pass along the Exception instance, so we have to store that as well. I did exactly that with the following class:
@Route("error-view") // Route shown in the user's browser
public class ErrorViewShower extends Div implements BeforeEnterObserver
// Class to store the current Exception of each UI in
private static class UIExceptionContainer extends HashMap<UI, Exception>
// Method to call when we want to show an error
public static void showError(Exception exception)
UIExceptionContainer exceptionContainer = VaadinSession.getCurrent().getAttribute(UIExceptionContainer.class);
// Creating and setting the exceptionContainer in case it hasn't been set yet.
if (exceptionContainer == null)
exceptionContainer = new UIExceptionContainer();
VaadinSession.getCurrent().setAttribute(UIExceptionContainer.class, exceptionContainer);
// Storing the exception for the beforeEnter method
exceptionContainer.put(UI.getCurrent(), exception);
// Now we navigate to an Instance of this class, to use the BeforeEnterEvent to reroute to the actual error view
UI.getCurrent().navigate(ErrorViewShower.class);// If this call doesn't work you might want to wrap into UI.access
@Override
public void beforeEnter(BeforeEnterEvent event)
UIExceptionContainer exceptionContainer = VaadinSession.getCurrent().getAttribute(UIExceptionContainer.class);
// Retrieving the previously stored exception. You might want to handle if this has been called without setting any Exception.
Exception exception = exceptionContainer.get(UI.getCurrent());
//Clearing out the now handled Exception
exceptionContainer.remove(UI.getCurrent());
// Using the BeforeEnterEvent to show the error
event.rerouteToError(exception, "Possible custom message for the ErrorHandler here");
Usage of it in combination with the error handler looks like this:
public class CustomErrorHandler implements ErrorHandler
@Override
public void error(ErrorEvent event)
// This can easily throw an exception itself, you need to add additional checking before casting.
// And it's possible that this method is called outside the context of an UI(when a dynamic resource throws an exception for example)
Exception exception = (Exception) event.getThrowable();
ErrorViewShower.showError(exception);
Edit2:
As it turns out that Exceptions occuring inside internal method calls don't get handled by the UI's ErrorHandler or the VaadinSession's ErrorHandler but instead by another error handler which causes the client side to terminate and show the Error Notification,
a solution is to catch the Exceptions inside the methods of the DataProvider and pass them to ErrorViewShower.showError()
and still return without any Exception flying the stacktrace upwards. (Or don't throw any Exception yourself and instead simply pass a new to the ErrorViewShower.showError()
method).
By returning normally Vaadin doesn't even know something went wrong.ErrorViewShower.showError()
calls ui.navigate
, that navigation command seems to get "queued" behind the calls to the DataProvider, meaning the view of the user will change in the same request.
Dataprovider with such an implementation:
new AbstractBackEndDataProvider<String, Void>()
@Override
protected Stream<String> fetchFromBackEnd(Query<String, Void> query)
try
//Code that can throw an Exception here
catch(Exception e)
ErrorViewShower.showError(e);
//We have to make sure that query.getLimit and query.getOffset gets called, otherwise Vaadin throws an Exception with the message "the data provider hasn't ever called getLimit() method on the provided query. It means that the the data provider breaks the contract and the returned stream contains unxpected data."
query.getLimit();
query.getOffset();
return Stream.of(); //Stream of empty Array to return without error
@Override
protected int sizeInBackEnd(Query<String, Void> query)
//Second way i mentioned, but this will not catch any Exception you didn't create, where as the try...catch has no way to let any Exception reach Vaadin.
if(badThingsHappened)
ErrorViewShower.showError(new UnsupportedOperationException("Bad things..."));
return 0;//Exiting without error
Indeed, the error handler is called, but that doesn't help me much because navigation orUI.getCurrent().getPage().executeJavaScript("window.location = '/my-error-page'")
does not work within the error handler. My goal is to show an appropriate error page.
– Steffen Harbich
Mar 26 at 8:51
1
@SteffenHarbich i edited my answer to include a way to get Vaadin to reroute to an error view.
– froemijojo
Mar 26 at 11:10
Thank you for your answers. So this code is working in your case? I ask because when I call aUI.getCurrent().navigate
in my error handler nothing happens except the usual Vaadin Flow error panel "Internal Error..take note of unsaved data..." in the upper right corner of the view. No redirect.
– Steffen Harbich
Mar 26 at 12:21
Copied your approach, still getting no redirect to error view.
– Steffen Harbich
Mar 26 at 12:36
1
Nice, that works fine. Let's hope Vaadin will fix the exception handling some day, so this workaround will not be required anymore. Thanks a lot for your help!
– Steffen Harbich
Mar 28 at 6:52
|
show 7 more comments
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55210726%2fhow-to-handle-exceptions-thrown-in-dataprovider-methods-centrally%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
I believe all Exceptions that don't occur while routing will be given to the ErrorHandler of the VaadinSession the error occured in.
The best way to set the ErrorHandler seems to be to override the sessionInit
method in a custom SessionInitListener
You can add a custom SessionInitListener
inside the servletInitialized
method of a custom VaadinServlet.
class CustomServlet extends VaadinServlet
@Override
protected void servletInitialized() throws ServletException
super.servletInitialized();
getService().addSessionInitListener(new CustomSessionInitListener());
And that SessionInitListener
(in this example CustomSessionInitListener
) has to set the errorHandler of the sessions that get initialized.
class CustomSessionInitListener implements SessionInitListener
@Override
public void sessionInit(SessionInitEvent event) throws ServiceException
event.getSession().setErrorHandler(new CustomErrorHandler());
For further information on how to create your own Servlet take a look at Vaadin's tutorial page(you need to scroll down to "Customizing Vaadin Servlet")
Edit:
To show the error page you need to get Vaadin to reroute to an error. To achieve that we can use an BeforeEnterEvent
, BeforeEnterEvents
have a rerouteToError
method which we can use to let Vaadin show our ErrorView.
But we also want to pass along the Exception instance, so we have to store that as well. I did exactly that with the following class:
@Route("error-view") // Route shown in the user's browser
public class ErrorViewShower extends Div implements BeforeEnterObserver
// Class to store the current Exception of each UI in
private static class UIExceptionContainer extends HashMap<UI, Exception>
// Method to call when we want to show an error
public static void showError(Exception exception)
UIExceptionContainer exceptionContainer = VaadinSession.getCurrent().getAttribute(UIExceptionContainer.class);
// Creating and setting the exceptionContainer in case it hasn't been set yet.
if (exceptionContainer == null)
exceptionContainer = new UIExceptionContainer();
VaadinSession.getCurrent().setAttribute(UIExceptionContainer.class, exceptionContainer);
// Storing the exception for the beforeEnter method
exceptionContainer.put(UI.getCurrent(), exception);
// Now we navigate to an Instance of this class, to use the BeforeEnterEvent to reroute to the actual error view
UI.getCurrent().navigate(ErrorViewShower.class);// If this call doesn't work you might want to wrap into UI.access
@Override
public void beforeEnter(BeforeEnterEvent event)
UIExceptionContainer exceptionContainer = VaadinSession.getCurrent().getAttribute(UIExceptionContainer.class);
// Retrieving the previously stored exception. You might want to handle if this has been called without setting any Exception.
Exception exception = exceptionContainer.get(UI.getCurrent());
//Clearing out the now handled Exception
exceptionContainer.remove(UI.getCurrent());
// Using the BeforeEnterEvent to show the error
event.rerouteToError(exception, "Possible custom message for the ErrorHandler here");
Usage of it in combination with the error handler looks like this:
public class CustomErrorHandler implements ErrorHandler
@Override
public void error(ErrorEvent event)
// This can easily throw an exception itself, you need to add additional checking before casting.
// And it's possible that this method is called outside the context of an UI(when a dynamic resource throws an exception for example)
Exception exception = (Exception) event.getThrowable();
ErrorViewShower.showError(exception);
Edit2:
As it turns out that Exceptions occuring inside internal method calls don't get handled by the UI's ErrorHandler or the VaadinSession's ErrorHandler but instead by another error handler which causes the client side to terminate and show the Error Notification,
a solution is to catch the Exceptions inside the methods of the DataProvider and pass them to ErrorViewShower.showError()
and still return without any Exception flying the stacktrace upwards. (Or don't throw any Exception yourself and instead simply pass a new to the ErrorViewShower.showError()
method).
By returning normally Vaadin doesn't even know something went wrong.ErrorViewShower.showError()
calls ui.navigate
, that navigation command seems to get "queued" behind the calls to the DataProvider, meaning the view of the user will change in the same request.
Dataprovider with such an implementation:
new AbstractBackEndDataProvider<String, Void>()
@Override
protected Stream<String> fetchFromBackEnd(Query<String, Void> query)
try
//Code that can throw an Exception here
catch(Exception e)
ErrorViewShower.showError(e);
//We have to make sure that query.getLimit and query.getOffset gets called, otherwise Vaadin throws an Exception with the message "the data provider hasn't ever called getLimit() method on the provided query. It means that the the data provider breaks the contract and the returned stream contains unxpected data."
query.getLimit();
query.getOffset();
return Stream.of(); //Stream of empty Array to return without error
@Override
protected int sizeInBackEnd(Query<String, Void> query)
//Second way i mentioned, but this will not catch any Exception you didn't create, where as the try...catch has no way to let any Exception reach Vaadin.
if(badThingsHappened)
ErrorViewShower.showError(new UnsupportedOperationException("Bad things..."));
return 0;//Exiting without error
Indeed, the error handler is called, but that doesn't help me much because navigation orUI.getCurrent().getPage().executeJavaScript("window.location = '/my-error-page'")
does not work within the error handler. My goal is to show an appropriate error page.
– Steffen Harbich
Mar 26 at 8:51
1
@SteffenHarbich i edited my answer to include a way to get Vaadin to reroute to an error view.
– froemijojo
Mar 26 at 11:10
Thank you for your answers. So this code is working in your case? I ask because when I call aUI.getCurrent().navigate
in my error handler nothing happens except the usual Vaadin Flow error panel "Internal Error..take note of unsaved data..." in the upper right corner of the view. No redirect.
– Steffen Harbich
Mar 26 at 12:21
Copied your approach, still getting no redirect to error view.
– Steffen Harbich
Mar 26 at 12:36
1
Nice, that works fine. Let's hope Vaadin will fix the exception handling some day, so this workaround will not be required anymore. Thanks a lot for your help!
– Steffen Harbich
Mar 28 at 6:52
|
show 7 more comments
I believe all Exceptions that don't occur while routing will be given to the ErrorHandler of the VaadinSession the error occured in.
The best way to set the ErrorHandler seems to be to override the sessionInit
method in a custom SessionInitListener
You can add a custom SessionInitListener
inside the servletInitialized
method of a custom VaadinServlet.
class CustomServlet extends VaadinServlet
@Override
protected void servletInitialized() throws ServletException
super.servletInitialized();
getService().addSessionInitListener(new CustomSessionInitListener());
And that SessionInitListener
(in this example CustomSessionInitListener
) has to set the errorHandler of the sessions that get initialized.
class CustomSessionInitListener implements SessionInitListener
@Override
public void sessionInit(SessionInitEvent event) throws ServiceException
event.getSession().setErrorHandler(new CustomErrorHandler());
For further information on how to create your own Servlet take a look at Vaadin's tutorial page(you need to scroll down to "Customizing Vaadin Servlet")
Edit:
To show the error page you need to get Vaadin to reroute to an error. To achieve that we can use an BeforeEnterEvent
, BeforeEnterEvents
have a rerouteToError
method which we can use to let Vaadin show our ErrorView.
But we also want to pass along the Exception instance, so we have to store that as well. I did exactly that with the following class:
@Route("error-view") // Route shown in the user's browser
public class ErrorViewShower extends Div implements BeforeEnterObserver
// Class to store the current Exception of each UI in
private static class UIExceptionContainer extends HashMap<UI, Exception>
// Method to call when we want to show an error
public static void showError(Exception exception)
UIExceptionContainer exceptionContainer = VaadinSession.getCurrent().getAttribute(UIExceptionContainer.class);
// Creating and setting the exceptionContainer in case it hasn't been set yet.
if (exceptionContainer == null)
exceptionContainer = new UIExceptionContainer();
VaadinSession.getCurrent().setAttribute(UIExceptionContainer.class, exceptionContainer);
// Storing the exception for the beforeEnter method
exceptionContainer.put(UI.getCurrent(), exception);
// Now we navigate to an Instance of this class, to use the BeforeEnterEvent to reroute to the actual error view
UI.getCurrent().navigate(ErrorViewShower.class);// If this call doesn't work you might want to wrap into UI.access
@Override
public void beforeEnter(BeforeEnterEvent event)
UIExceptionContainer exceptionContainer = VaadinSession.getCurrent().getAttribute(UIExceptionContainer.class);
// Retrieving the previously stored exception. You might want to handle if this has been called without setting any Exception.
Exception exception = exceptionContainer.get(UI.getCurrent());
//Clearing out the now handled Exception
exceptionContainer.remove(UI.getCurrent());
// Using the BeforeEnterEvent to show the error
event.rerouteToError(exception, "Possible custom message for the ErrorHandler here");
Usage of it in combination with the error handler looks like this:
public class CustomErrorHandler implements ErrorHandler
@Override
public void error(ErrorEvent event)
// This can easily throw an exception itself, you need to add additional checking before casting.
// And it's possible that this method is called outside the context of an UI(when a dynamic resource throws an exception for example)
Exception exception = (Exception) event.getThrowable();
ErrorViewShower.showError(exception);
Edit2:
As it turns out that Exceptions occuring inside internal method calls don't get handled by the UI's ErrorHandler or the VaadinSession's ErrorHandler but instead by another error handler which causes the client side to terminate and show the Error Notification,
a solution is to catch the Exceptions inside the methods of the DataProvider and pass them to ErrorViewShower.showError()
and still return without any Exception flying the stacktrace upwards. (Or don't throw any Exception yourself and instead simply pass a new to the ErrorViewShower.showError()
method).
By returning normally Vaadin doesn't even know something went wrong.ErrorViewShower.showError()
calls ui.navigate
, that navigation command seems to get "queued" behind the calls to the DataProvider, meaning the view of the user will change in the same request.
Dataprovider with such an implementation:
new AbstractBackEndDataProvider<String, Void>()
@Override
protected Stream<String> fetchFromBackEnd(Query<String, Void> query)
try
//Code that can throw an Exception here
catch(Exception e)
ErrorViewShower.showError(e);
//We have to make sure that query.getLimit and query.getOffset gets called, otherwise Vaadin throws an Exception with the message "the data provider hasn't ever called getLimit() method on the provided query. It means that the the data provider breaks the contract and the returned stream contains unxpected data."
query.getLimit();
query.getOffset();
return Stream.of(); //Stream of empty Array to return without error
@Override
protected int sizeInBackEnd(Query<String, Void> query)
//Second way i mentioned, but this will not catch any Exception you didn't create, where as the try...catch has no way to let any Exception reach Vaadin.
if(badThingsHappened)
ErrorViewShower.showError(new UnsupportedOperationException("Bad things..."));
return 0;//Exiting without error
Indeed, the error handler is called, but that doesn't help me much because navigation orUI.getCurrent().getPage().executeJavaScript("window.location = '/my-error-page'")
does not work within the error handler. My goal is to show an appropriate error page.
– Steffen Harbich
Mar 26 at 8:51
1
@SteffenHarbich i edited my answer to include a way to get Vaadin to reroute to an error view.
– froemijojo
Mar 26 at 11:10
Thank you for your answers. So this code is working in your case? I ask because when I call aUI.getCurrent().navigate
in my error handler nothing happens except the usual Vaadin Flow error panel "Internal Error..take note of unsaved data..." in the upper right corner of the view. No redirect.
– Steffen Harbich
Mar 26 at 12:21
Copied your approach, still getting no redirect to error view.
– Steffen Harbich
Mar 26 at 12:36
1
Nice, that works fine. Let's hope Vaadin will fix the exception handling some day, so this workaround will not be required anymore. Thanks a lot for your help!
– Steffen Harbich
Mar 28 at 6:52
|
show 7 more comments
I believe all Exceptions that don't occur while routing will be given to the ErrorHandler of the VaadinSession the error occured in.
The best way to set the ErrorHandler seems to be to override the sessionInit
method in a custom SessionInitListener
You can add a custom SessionInitListener
inside the servletInitialized
method of a custom VaadinServlet.
class CustomServlet extends VaadinServlet
@Override
protected void servletInitialized() throws ServletException
super.servletInitialized();
getService().addSessionInitListener(new CustomSessionInitListener());
And that SessionInitListener
(in this example CustomSessionInitListener
) has to set the errorHandler of the sessions that get initialized.
class CustomSessionInitListener implements SessionInitListener
@Override
public void sessionInit(SessionInitEvent event) throws ServiceException
event.getSession().setErrorHandler(new CustomErrorHandler());
For further information on how to create your own Servlet take a look at Vaadin's tutorial page(you need to scroll down to "Customizing Vaadin Servlet")
Edit:
To show the error page you need to get Vaadin to reroute to an error. To achieve that we can use an BeforeEnterEvent
, BeforeEnterEvents
have a rerouteToError
method which we can use to let Vaadin show our ErrorView.
But we also want to pass along the Exception instance, so we have to store that as well. I did exactly that with the following class:
@Route("error-view") // Route shown in the user's browser
public class ErrorViewShower extends Div implements BeforeEnterObserver
// Class to store the current Exception of each UI in
private static class UIExceptionContainer extends HashMap<UI, Exception>
// Method to call when we want to show an error
public static void showError(Exception exception)
UIExceptionContainer exceptionContainer = VaadinSession.getCurrent().getAttribute(UIExceptionContainer.class);
// Creating and setting the exceptionContainer in case it hasn't been set yet.
if (exceptionContainer == null)
exceptionContainer = new UIExceptionContainer();
VaadinSession.getCurrent().setAttribute(UIExceptionContainer.class, exceptionContainer);
// Storing the exception for the beforeEnter method
exceptionContainer.put(UI.getCurrent(), exception);
// Now we navigate to an Instance of this class, to use the BeforeEnterEvent to reroute to the actual error view
UI.getCurrent().navigate(ErrorViewShower.class);// If this call doesn't work you might want to wrap into UI.access
@Override
public void beforeEnter(BeforeEnterEvent event)
UIExceptionContainer exceptionContainer = VaadinSession.getCurrent().getAttribute(UIExceptionContainer.class);
// Retrieving the previously stored exception. You might want to handle if this has been called without setting any Exception.
Exception exception = exceptionContainer.get(UI.getCurrent());
//Clearing out the now handled Exception
exceptionContainer.remove(UI.getCurrent());
// Using the BeforeEnterEvent to show the error
event.rerouteToError(exception, "Possible custom message for the ErrorHandler here");
Usage of it in combination with the error handler looks like this:
public class CustomErrorHandler implements ErrorHandler
@Override
public void error(ErrorEvent event)
// This can easily throw an exception itself, you need to add additional checking before casting.
// And it's possible that this method is called outside the context of an UI(when a dynamic resource throws an exception for example)
Exception exception = (Exception) event.getThrowable();
ErrorViewShower.showError(exception);
Edit2:
As it turns out that Exceptions occuring inside internal method calls don't get handled by the UI's ErrorHandler or the VaadinSession's ErrorHandler but instead by another error handler which causes the client side to terminate and show the Error Notification,
a solution is to catch the Exceptions inside the methods of the DataProvider and pass them to ErrorViewShower.showError()
and still return without any Exception flying the stacktrace upwards. (Or don't throw any Exception yourself and instead simply pass a new to the ErrorViewShower.showError()
method).
By returning normally Vaadin doesn't even know something went wrong.ErrorViewShower.showError()
calls ui.navigate
, that navigation command seems to get "queued" behind the calls to the DataProvider, meaning the view of the user will change in the same request.
Dataprovider with such an implementation:
new AbstractBackEndDataProvider<String, Void>()
@Override
protected Stream<String> fetchFromBackEnd(Query<String, Void> query)
try
//Code that can throw an Exception here
catch(Exception e)
ErrorViewShower.showError(e);
//We have to make sure that query.getLimit and query.getOffset gets called, otherwise Vaadin throws an Exception with the message "the data provider hasn't ever called getLimit() method on the provided query. It means that the the data provider breaks the contract and the returned stream contains unxpected data."
query.getLimit();
query.getOffset();
return Stream.of(); //Stream of empty Array to return without error
@Override
protected int sizeInBackEnd(Query<String, Void> query)
//Second way i mentioned, but this will not catch any Exception you didn't create, where as the try...catch has no way to let any Exception reach Vaadin.
if(badThingsHappened)
ErrorViewShower.showError(new UnsupportedOperationException("Bad things..."));
return 0;//Exiting without error
I believe all Exceptions that don't occur while routing will be given to the ErrorHandler of the VaadinSession the error occured in.
The best way to set the ErrorHandler seems to be to override the sessionInit
method in a custom SessionInitListener
You can add a custom SessionInitListener
inside the servletInitialized
method of a custom VaadinServlet.
class CustomServlet extends VaadinServlet
@Override
protected void servletInitialized() throws ServletException
super.servletInitialized();
getService().addSessionInitListener(new CustomSessionInitListener());
And that SessionInitListener
(in this example CustomSessionInitListener
) has to set the errorHandler of the sessions that get initialized.
class CustomSessionInitListener implements SessionInitListener
@Override
public void sessionInit(SessionInitEvent event) throws ServiceException
event.getSession().setErrorHandler(new CustomErrorHandler());
For further information on how to create your own Servlet take a look at Vaadin's tutorial page(you need to scroll down to "Customizing Vaadin Servlet")
Edit:
To show the error page you need to get Vaadin to reroute to an error. To achieve that we can use an BeforeEnterEvent
, BeforeEnterEvents
have a rerouteToError
method which we can use to let Vaadin show our ErrorView.
But we also want to pass along the Exception instance, so we have to store that as well. I did exactly that with the following class:
@Route("error-view") // Route shown in the user's browser
public class ErrorViewShower extends Div implements BeforeEnterObserver
// Class to store the current Exception of each UI in
private static class UIExceptionContainer extends HashMap<UI, Exception>
// Method to call when we want to show an error
public static void showError(Exception exception)
UIExceptionContainer exceptionContainer = VaadinSession.getCurrent().getAttribute(UIExceptionContainer.class);
// Creating and setting the exceptionContainer in case it hasn't been set yet.
if (exceptionContainer == null)
exceptionContainer = new UIExceptionContainer();
VaadinSession.getCurrent().setAttribute(UIExceptionContainer.class, exceptionContainer);
// Storing the exception for the beforeEnter method
exceptionContainer.put(UI.getCurrent(), exception);
// Now we navigate to an Instance of this class, to use the BeforeEnterEvent to reroute to the actual error view
UI.getCurrent().navigate(ErrorViewShower.class);// If this call doesn't work you might want to wrap into UI.access
@Override
public void beforeEnter(BeforeEnterEvent event)
UIExceptionContainer exceptionContainer = VaadinSession.getCurrent().getAttribute(UIExceptionContainer.class);
// Retrieving the previously stored exception. You might want to handle if this has been called without setting any Exception.
Exception exception = exceptionContainer.get(UI.getCurrent());
//Clearing out the now handled Exception
exceptionContainer.remove(UI.getCurrent());
// Using the BeforeEnterEvent to show the error
event.rerouteToError(exception, "Possible custom message for the ErrorHandler here");
Usage of it in combination with the error handler looks like this:
public class CustomErrorHandler implements ErrorHandler
@Override
public void error(ErrorEvent event)
// This can easily throw an exception itself, you need to add additional checking before casting.
// And it's possible that this method is called outside the context of an UI(when a dynamic resource throws an exception for example)
Exception exception = (Exception) event.getThrowable();
ErrorViewShower.showError(exception);
Edit2:
As it turns out that Exceptions occuring inside internal method calls don't get handled by the UI's ErrorHandler or the VaadinSession's ErrorHandler but instead by another error handler which causes the client side to terminate and show the Error Notification,
a solution is to catch the Exceptions inside the methods of the DataProvider and pass them to ErrorViewShower.showError()
and still return without any Exception flying the stacktrace upwards. (Or don't throw any Exception yourself and instead simply pass a new to the ErrorViewShower.showError()
method).
By returning normally Vaadin doesn't even know something went wrong.ErrorViewShower.showError()
calls ui.navigate
, that navigation command seems to get "queued" behind the calls to the DataProvider, meaning the view of the user will change in the same request.
Dataprovider with such an implementation:
new AbstractBackEndDataProvider<String, Void>()
@Override
protected Stream<String> fetchFromBackEnd(Query<String, Void> query)
try
//Code that can throw an Exception here
catch(Exception e)
ErrorViewShower.showError(e);
//We have to make sure that query.getLimit and query.getOffset gets called, otherwise Vaadin throws an Exception with the message "the data provider hasn't ever called getLimit() method on the provided query. It means that the the data provider breaks the contract and the returned stream contains unxpected data."
query.getLimit();
query.getOffset();
return Stream.of(); //Stream of empty Array to return without error
@Override
protected int sizeInBackEnd(Query<String, Void> query)
//Second way i mentioned, but this will not catch any Exception you didn't create, where as the try...catch has no way to let any Exception reach Vaadin.
if(badThingsHappened)
ErrorViewShower.showError(new UnsupportedOperationException("Bad things..."));
return 0;//Exiting without error
edited Mar 27 at 21:14
answered Mar 21 at 15:26
froemijojofroemijojo
714 bronze badges
714 bronze badges
Indeed, the error handler is called, but that doesn't help me much because navigation orUI.getCurrent().getPage().executeJavaScript("window.location = '/my-error-page'")
does not work within the error handler. My goal is to show an appropriate error page.
– Steffen Harbich
Mar 26 at 8:51
1
@SteffenHarbich i edited my answer to include a way to get Vaadin to reroute to an error view.
– froemijojo
Mar 26 at 11:10
Thank you for your answers. So this code is working in your case? I ask because when I call aUI.getCurrent().navigate
in my error handler nothing happens except the usual Vaadin Flow error panel "Internal Error..take note of unsaved data..." in the upper right corner of the view. No redirect.
– Steffen Harbich
Mar 26 at 12:21
Copied your approach, still getting no redirect to error view.
– Steffen Harbich
Mar 26 at 12:36
1
Nice, that works fine. Let's hope Vaadin will fix the exception handling some day, so this workaround will not be required anymore. Thanks a lot for your help!
– Steffen Harbich
Mar 28 at 6:52
|
show 7 more comments
Indeed, the error handler is called, but that doesn't help me much because navigation orUI.getCurrent().getPage().executeJavaScript("window.location = '/my-error-page'")
does not work within the error handler. My goal is to show an appropriate error page.
– Steffen Harbich
Mar 26 at 8:51
1
@SteffenHarbich i edited my answer to include a way to get Vaadin to reroute to an error view.
– froemijojo
Mar 26 at 11:10
Thank you for your answers. So this code is working in your case? I ask because when I call aUI.getCurrent().navigate
in my error handler nothing happens except the usual Vaadin Flow error panel "Internal Error..take note of unsaved data..." in the upper right corner of the view. No redirect.
– Steffen Harbich
Mar 26 at 12:21
Copied your approach, still getting no redirect to error view.
– Steffen Harbich
Mar 26 at 12:36
1
Nice, that works fine. Let's hope Vaadin will fix the exception handling some day, so this workaround will not be required anymore. Thanks a lot for your help!
– Steffen Harbich
Mar 28 at 6:52
Indeed, the error handler is called, but that doesn't help me much because navigation or
UI.getCurrent().getPage().executeJavaScript("window.location = '/my-error-page'")
does not work within the error handler. My goal is to show an appropriate error page.– Steffen Harbich
Mar 26 at 8:51
Indeed, the error handler is called, but that doesn't help me much because navigation or
UI.getCurrent().getPage().executeJavaScript("window.location = '/my-error-page'")
does not work within the error handler. My goal is to show an appropriate error page.– Steffen Harbich
Mar 26 at 8:51
1
1
@SteffenHarbich i edited my answer to include a way to get Vaadin to reroute to an error view.
– froemijojo
Mar 26 at 11:10
@SteffenHarbich i edited my answer to include a way to get Vaadin to reroute to an error view.
– froemijojo
Mar 26 at 11:10
Thank you for your answers. So this code is working in your case? I ask because when I call a
UI.getCurrent().navigate
in my error handler nothing happens except the usual Vaadin Flow error panel "Internal Error..take note of unsaved data..." in the upper right corner of the view. No redirect.– Steffen Harbich
Mar 26 at 12:21
Thank you for your answers. So this code is working in your case? I ask because when I call a
UI.getCurrent().navigate
in my error handler nothing happens except the usual Vaadin Flow error panel "Internal Error..take note of unsaved data..." in the upper right corner of the view. No redirect.– Steffen Harbich
Mar 26 at 12:21
Copied your approach, still getting no redirect to error view.
– Steffen Harbich
Mar 26 at 12:36
Copied your approach, still getting no redirect to error view.
– Steffen Harbich
Mar 26 at 12:36
1
1
Nice, that works fine. Let's hope Vaadin will fix the exception handling some day, so this workaround will not be required anymore. Thanks a lot for your help!
– Steffen Harbich
Mar 28 at 6:52
Nice, that works fine. Let's hope Vaadin will fix the exception handling some day, so this workaround will not be required anymore. Thanks a lot for your help!
– Steffen Harbich
Mar 28 at 6:52
|
show 7 more comments
Got a question that you can’t ask on public Stack Overflow? Learn more about sharing private information with Stack Overflow for Teams.
Got a question that you can’t ask on public Stack Overflow? Learn more about sharing private information with Stack Overflow for Teams.
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55210726%2fhow-to-handle-exceptions-thrown-in-dataprovider-methods-centrally%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
This is a known issue/limitation/bug in current HesErrorParameter implementation and there is many issue tickets filed related to this github.com/vaadin/flow/issues/4715 github.com/vaadin/flow/issues/4549 github.com/vaadin/flow/issues/4607 github.com/vaadin/flow/issues/3192
– Tatu Lund
Mar 18 at 8:43