How to handle exceptions created in a Wicket custom model?

I have a component with a custom model (extension of the calibration standard class of the model). My model loads data from a database / web service when Wicket calls getObject() .

This search may fail for several reasons. I would like to handle this error by displaying a good message with the component on the webpage. What is the best way to do this?

 public class MyCustomModel extends Model { @Override public String getObject() { try { return Order.lookupOrderDataFromRemoteService(); } catch (Exception e) { logger.error("Failed silently..."); // How do I propagate this to the component/page? } return null; } 

Note that the error occurs inside the model, which is separated from the components.

+4
source share
5 answers

Your model may implement IComponentAssignedModel, which allows you to access your own component.

But I wonder how often you can reuse MyCustomModel? I know that some developers advocate the creation of autonomous model implementations (often in separate packages). Although there are general cases where this is useful (e.g. FeedbackMessagesModel), in my experience itโ€™s easier to just create inner classes that are component specific.

+6
source

Handling the exception that occurs in the getObject () model is a difficult task, because by this time we are usually in the depth of the response phase of the entire request cycle, and it is too late to change the hierarchy of components. Thus, the only place to handle the exception is very non-local, nowhere near your component or model, but in RequestCycle .

However, there is a way around. We use a combination of a Behavior and IRequestCycleListener to solve this problem:
  • IRequestCycleListener#onException allows you to examine any exception that was thrown during the request. If you return an IRequestHandler from this method, this handler will be launched and displayed instead of what else was done in advance.

    We use this on our own to catch things like Hibernate StaleObjectException in order to redirect the user to the โ€œsomeone else changed your objectโ€ page. If you

  • For more specific cases, we add the RuntimeExceptionHandler behavior:

     public abstract class RuntimeExceptionHandler extends Behavior { public abstract IRequestHandler handleRuntimeException(Component component, Exception ex); } 

    At IRequestCycleListener we look at the current tree of page components to see if any component has an instance of RuntimeExceptionHandler . If we find one, we call its handleRuntimeException method, and if it returns an IRequestHandler one we will use. That way you can have the actual handling of a local error on your page.

    Example:

     public MyPage() { ... this.add(new RuntimeExceptionHandler() { @Override public IRequestHandler handleRuntimeException(Component component, Exception ex) { if (ex instanceof MySpecialException) { // just an example, you really can do anything you want here. // show a feedback message... MyPage.this.error("something went wrong"); // then hide the affected component(s) so the error doesn't happen again... myComponentWithErrorInModel.setVisible(false); // ... // ...then finally just re-render this page: return new RenderPageRequestHandler(new PageProvider(MyPage.this)); } else { return null; } } }); } 

    Note. This is not something that comes with Wicket, we rode on our own. We simply combined the IRequestCycleListener and Behavior Wicket functions to come up with this.

+7
source

The main problem here is that Model by design, separated from the hierarchy of components, it is possible to implement a Model that supports a component that will report all errors in relation to a specific component.

Remember to make sure that it implements Detachable so that the related Component disconnected.

If Model performs an expensive operation, you might be interested in using LoadableDetachableModel instead (note that Model.getObject() can be called multiple times).

 public class MyComponentAwareModel extends LoadableDetachableModel { private Component comp; public MyComponentAwareModel(Component comp) { this.comp = comp; } protected Object load() { try { return Order.lookupOrderDataFromRemoteService(); } catch (Exception e) { logger.error("Failed silently..."); comp.error("This is an error message"); } return null; } protected void onDetach(){ comp.detach(); } } 

Maybe you should try Session.get().error()) .

+2
source

I would add a FeedbackPanel to the page and cause an error ("some description") in the catch clause.

0
source

You might want to simply return null to getObject and add logic to the controller class to display a message if getObject returns null.

If you need special messages for various causes of failures, you can add to the model, as String errorMessage; , a property that is set when an exception is getObject in getObject , so your controller class can do something like this

 if(model.getObject == null) { add(new Label("label",model.getErrorMessage())); } else { /* display your model object*/ } 
0
source

Source: https://habr.com/ru/post/1434563/


All Articles