@@ -481,7 +481,6 @@ initialization parameters ( `init-param` elements) to the Servlet declaration in
481
481
Note that if <<mvc-default-servlet-handler,default servlet handling>> is
482
482
also configured, then unresolved requests are always forwarded to the default servlet
483
483
and a 404 would never be raised.
484
-
485
484
|===
486
485
487
486
@@ -2830,22 +2829,75 @@ controller-specific ``Formatter``'s:
2830
2829
public ResponseEntity<String> handle(IOException ex) {
2831
2830
// ...
2832
2831
}
2832
+ }
2833
+ ----
2834
+
2835
+ The exception may match against a top-level exception being propagated (i.e. a direct
2836
+ `IOException` thrown), or against the immediate cause within a top-level wrapper exception
2837
+ (e.g. an `IOException` wrapped inside an `IllegalStateException`).
2838
+
2839
+ For matching exception types, preferably declare the target exception as a method argument
2840
+ as shown above. When multiple exception methods match, a root exception match is generally
2841
+ preferred to a cause exception match. More specifically, the `ExceptionDepthComparator` is
2842
+ used to sort exceptions based on their depth from the thrown exception type.
2843
+
2844
+ Alternatively, the annotation declaration may narrow the exception types to match:
2845
+
2846
+ [source,java,indent=0]
2847
+ [subs="verbatim,quotes"]
2848
+ ----
2849
+ @ExceptionHandler({FileSystemException.class, RemoteException.class})
2850
+ public ResponseEntity<String> handle(IOException ex) {
2851
+ // ...
2852
+ }
2853
+ ----
2854
+
2855
+ Or even a list of specific exception types with a very generic argument signature:
2833
2856
2857
+ [source,java,indent=0]
2858
+ [subs="verbatim,quotes"]
2859
+ ----
2860
+ @ExceptionHandler({FileSystemException.class, RemoteException.class})
2861
+ public ResponseEntity<String> handle(Exception ex) {
2862
+ // ...
2834
2863
}
2835
2864
----
2836
2865
2837
- The annotation can list the exception types to match. Or simply declare the target
2838
- exception as a method argument as shown above. When multiple exception methods match,
2839
- a root exception match is generally preferred to a cause exception match. More formally
2840
- the `ExceptionDepthComparator` is used to sort exceptions based on their depth from the
2841
- thrown exception type.
2866
+ [NOTE]
2867
+ ====
2868
+ The distinction between root and cause exception matching can be surprising:
2869
+
2870
+ In the `IOException` variant above, the method will typically be called with
2871
+ the actual `FileSystemException` or `RemoteException` instance as the argument
2872
+ since both of them extend from `IOException`. However, if any such matching
2873
+ exception is propagated within a wrapper exception which is an `IOException`
2874
+ itself, the passed-in exception instance will be that wrapper exception.
2875
+
2876
+ The behavior is even simpler in the `handle(Exception)` variant: This will
2877
+ always be invoked with the wrapper exception in a wrapping scenario, with the
2878
+ actually matching exception to be found through `ex.getCause()` in that case.
2879
+ The passed-in exception will only be the actual `FileSystemException` or
2880
+ `RemoteException` instance when these are thrown as top-level exceptions.
2881
+ ====
2882
+
2883
+ We generally recommend to be as specific as possible in the argument signature,
2884
+ reducing the potential for mismatches between root and cause exception types.
2885
+ Consider breaking a multi-matching method into individual `@ExceptionHandler`
2886
+ methods, each matching a single specific exception type through its signature.
2842
2887
2843
2888
In a multi-`@ControllerAdvice` arrangement, please declare your primary root exception
2844
2889
mappings on a `@ControllerAdvice` prioritized with a corresponding order. While a root
2845
- exception match is preferred to a cause, this is mainly among the methods of a given
2846
- controller or `@ControllerAdvice`. That means a cause match on a higher-priority
2847
- `@ControllerAdvice` is preferred to any match (e.g. root) on a lower-priority
2848
- `@ControllerAdvice`.
2890
+ exception match is preferred to a cause, this is defined among the methods of a given
2891
+ controller or `@ControllerAdvice` class. This means a cause match on a higher-priority
2892
+ `@ControllerAdvice` bean is preferred to any match (e.g. root) on a lower-priority
2893
+ `@ControllerAdvice` bean.
2894
+
2895
+ Last but not least, an `@ExceptionHandler` method implementation may choose to back
2896
+ out of dealing with a given exception instance by rethrowing it in its original form.
2897
+ This is useful in scenarios where you are only interested in root-level matches or in
2898
+ matches within a specific context that cannot be statically determined. A rethrown
2899
+ exception will be propagated through the remaining resolution chain, just like if
2900
+ the given `@ExceptionHandler` method would not have matched in the first place.
2849
2901
2850
2902
Support for `@ExceptionHandler` methods in Spring MVC is built on the `DispatcherServlet`
2851
2903
level, <<mvc-exceptionhandlers,HandlerExceptionResolver>> mechanism.
0 commit comments