@@ -12,233 +12,100 @@ configuration class.
1212Overriding whole ` ProblemEnhancedExceptionHandler ` is not recommended, although such necessities are sometimes
1313understandable.
1414
15- ## ` AsyncRequestTimeoutException `
15+ ## Occurrences of ` ProblemException `
1616
17- What triggers it: An async request (e.g. ` DeferredResult ` , ` Callable ` , WebAsync) exceeded configured timeout before
18- producing a value.
19-
20- Mapping: [ ` AsyncRequestTimeoutMapping ` ] [ AsyncRequestTimeoutMapping ]
21-
22- Example:
23-
24- ``` json
25- {
26- "status" : 500 ,
27- "title" : " Internal Server Error"
28- }
29- ```
30-
31- ## ` ConversionNotSupportedException `
32-
33- What triggers it: Spring's type conversion system could not convert a controller method return value or property to the
34- required type (fatal conversion issue, not just a simple mismatch).
35-
36- Mapping: [ ` ConversionNotSupportedMapping ` ] [ ConversionNotSupportedMapping ]
37-
38- Example:
39-
40- ``` json
41- {
42- "status" : 500 ,
43- "title" : " Internal Server Error"
44- }
45- ```
46-
47- ## ` ErrorResponseException `
48-
49- What triggers it: Explicitly thrown ` ErrorResponseException ` (or subclasses like ` ResponseStatusException ` ). Each of
50- these exceptions carry HTTP status within it as well as details to be used in ` application/problem+json ` response.
51-
52- Mapping: [ ` ErrorResponseMapping ` ] [ ErrorResponseMapping ]
53-
54- Example:
17+ Explicitly thrown ` ProblemException ` (or subclasses created by its users). Each of these exceptions carry HTTP status
18+ within it as well as details to be used in ` application/problem+json ` response.
5519
5620``` json
5721{
5822 "type" : " https://example.org/problem-type" ,
5923 "title" : " Some Error" ,
6024 "status" : 400 ,
6125 "detail" : " Explanation of the error" ,
62- "instance" : " https://example.org/instances/123" ,
63- "extraKey" : " extraValue"
64- }
65- ```
66-
67- ## ` HttpMediaTypeNotAcceptableException `
68-
69- What triggers it: Client ` Accept ` header doesn't match any producible media type from controller.
70-
71- Mapping: [ ` HttpMediaTypeNotAcceptableMapping ` ] [ HttpMediaTypeNotAcceptableMapping ]
72-
73- ``` json
74- {
75- "status" : 406 ,
76- "title" : " Not Acceptable"
77- }
78- ```
79-
80- ## ` HttpMediaTypeNotSupportedException `
81-
82- What triggers it: Request ` Content-Type ` not supported by any ` HttpMessageConverter ` for the target endpoint.
83-
84- Mapping: [ ` HttpMediaTypeNotSupportedMapping ` ] [ HttpMediaTypeNotSupportedMapping ]
85-
86- ``` json
87- {
88- "status" : 415 ,
89- "title" : " Unsupported Media Type"
90- }
91- ```
92-
93- ## ` HttpMessageNotReadableException `
94-
95- What triggers it: Incoming request body couldn't be parsed/deserialized (malformed JSON, wrong structure, EOF, etc.).
96-
97- Mapping: [ ` HttpMessageNotReadableMapping ` ] [ HttpMessageNotReadableMapping ]
98-
99- ``` json
100- {
101- "status" : 400 ,
102- "title" : " Bad Request"
103- }
104- ```
105-
106- ## ` HttpMessageNotWritableException `
107-
108- What triggers it: Server failed to serialize the response body (e.g. Jackson serialization problem) after controller
109- returned a value.
110-
111- Mapping: [ ` HttpMessageNotWritableMapping ` ] [ HttpMessageNotWritableMapping ]
112-
113- ``` json
114- {
115- "status" : 500 ,
116- "title" : " Internal Server Error"
117- }
118- ```
119-
120- ## ` HttpRequestMethodNotSupportedException `
121-
122- What triggers it: HTTP method not supported for a particular endpoint (e.g. ` POST ` to an endpoint allowing only ` GET ` ).
123-
124- Mapping: [ ` HttpRequestMethodNotSupportedMapping ` ] [ HttpRequestMethodNotSupportedMapping ]
125-
126- ``` json
127- {
128- "status" : 405 ,
129- "title" : " Method Not Allowed"
130- }
131- ```
132-
133- ## ` MaxUploadSizeExceededException `
134-
135- What triggers it: Multipart upload exceeds configured max file or request size.
136-
137- Mapping: [ ` MaxUploadSizeExceededMapping ` ] [ MaxUploadSizeExceededMapping ]
138-
139- ``` json
140- {
141- "status" : 413 ,
142- "title" : " Content Too Large" ,
143- "detail" : " Max upload size exceeded" ,
144- "max" : 1048576
26+ "instance" : " https://example.org/instances/123"
14527}
14628```
14729
148- ## ` MethodArgumentNotValidException `
30+ ** Note** that the main reason behind this project is to make ` ProblemException ` a base class for all custom exception in
31+ your application code.
14932
150- What triggers it: Bean Validation (JSR 380) failed for a ` @Valid ` annotated argument (e.g. request body DTO) during data
151- binding.
33+ ## Validation
15234
153- Mapping: [ ` MethodArgumentNotValidMapping ` ] [ MethodArgumentNotValidMapping ]
35+ Library overrides default responses for ` jakarta.validation ` exceptions for both ` @RequestBody ` and any other
36+ ` @RestController ` arguments.
15437
15538``` json
15639{
15740 "status" : 400 ,
15841 "title" : " Bad Request" ,
15942 "detail" : " Validation failed" ,
160- "errors" : [
161- {
162- "field" : " email" ,
163- "error" : " must be a well-formed email address"
164- },
165- {
166- "field" : " age" ,
167- "error" : " must be greater than or equal to 18"
168- }
169- ]
43+ "errors" : [ {
44+ "field" : " email" ,
45+ "error" : " must be a well-formed email address"
46+ }, {
47+ "field" : " age" ,
48+ "error" : " must be greater than or equal to 18"
49+ } ]
17050}
17151```
17252
173- Field names convention may be formatted (e.g. ` snake_case ` ) by configuring ` spring.jackson.property-naming-strategy ` .
174-
175- ## ` MissingPathVariableException `
176-
177- What triggers it: A required URI template variable was not provided (e.g. handler expected ` {id} ` path variable that was
178- absent in request mapping resolution).
53+ More notably, for ` @RequestParam ` , ` @RequestHeader ` etc., there's a tweak that comes from settings configuration
54+ property ` spring.validation.method.adapt-constraint-violations ` to ` true ` . Enabling it, switches default validation to
55+ not rely on raw ` ConstraintViolationException ` , but rather on ` MethodValidationException ` , which contains more details
56+ about validated element.
17957
180- Mapping: [ ` MissingPathVariableMapping ` ] [ MissingPathVariableMapping ]
58+ Let's say we have following ` @RestController ` , where ` idx ` query param has different Java parameter name.
18159
182- ``` json
183- {
184- "status" : 400 ,
185- "title" : " Bad Request" ,
186- "detail" : " Missing path variable" ,
187- "name" : " id"
60+ ``` java
61+ @Validated
62+ @RestController
63+ static class RequestParamController {
64+ @GetMapping (" /orders" )
65+ String endpoint (@RequestParam (" customerId" ) @Size (min = 5 , max = 30 ) String customerIdParam ) {
66+ return " OK" ;
67+ }
18868}
18969```
19070
191- ## ` MissingServletRequestParameterException `
71+ The ` errors.$.field ` will differ, depending on whether ` spring.validation.method.adapt-constraint-violations ` is enabled
72+ or not. For ` true ` it will use value from ` @RequestParam ` (if able) (the same goes for ` @PathVariable ` ,
73+ ` @RequestHeader ` , ` @CookieValue ` etc.).
19274
193- What triggers it: Required query parameter is missing (e.g. ` @RequestParam(required=true) ` not supplied by client).
194-
195- Mapping: [ ` MissingServletRequestParameterMapping ` ] [ MissingServletRequestParameterMapping ]
196-
197- ``` json
75+ <table >
76+ <tr >
77+ <td align =" center " ><code >ConstraintViolationException</code ></td >
78+ <td align =" center " ><code >MethodValidationException</code ></td >
79+ </tr >
80+ <tr >
81+ <td ><pre lang =" json " >
19882{
19983 "status": 400,
20084 "title": "Bad Request",
201- "detail" : " Missing request param" ,
202- "param" : " q" ,
203- "kind" : " string"
85+ "detail": "Validation failed",
86+ "errors": [ {
87+ "field": "customerIdParam",
88+ "error": "size must be between 5 and 30"
89+ } ]
20490}
205- ```
206-
207- ## ` MissingServletRequestPartException `
208-
209- What triggers it: Required multipart request part missing (e.g. file field in a multipart/form-data POST not provided).
210-
211- Mapping: [ ` MissingServletRequestPartMapping ` ] [ MissingServletRequestPartMapping ]
212-
213- ``` json
91+ </pre ></td >
92+ <td ><pre lang =" json " >
21493{
21594 "status": 400,
21695 "title": "Bad Request",
217- "detail" : " Missing request part" ,
218- "param" : " file"
219- }
220- ```
221-
222- ## ` ServletRequestBindingException `
223-
224- What triggers it: General binding issues with request parameters, headers, path variables (e.g. missing header required
225- by ` @RequestHeader ` ).
226-
227- Mapping: [ ` ServletRequestBindingMapping ` ] [ ServletRequestBindingMapping ]
228-
229- ``` json
230- {
231- "status" : 400 ,
232- "title" : " Bad Request"
96+ "detail": "Validation failed",
97+ "errors": [ {
98+ "field": "customerId",
99+ "error": "size must be between 5 and 30"
100+ } ]
233101}
234- ```
102+ </pre ></td >
103+ </tr >
104+ </table >
235105
236- ## ` TypeMismatchException `
106+ ## Occurrences of ` TypeMismatchException `
237107
238- What triggers it: Failed to bind a web request parameter/path variable to a controller argument due to type mismatch (
239- e.g. ` age=abc ` where ` age ` expects an integer).
240-
241- Mapping: [ ` TypeMismatchMapping ` ] [ TypeMismatchMapping ]
108+ Triggered for example when trying to pass ` String ` value into ` @RequestParam("param") Integer param ` .
242109
243110``` json
244111{
@@ -250,48 +117,67 @@ Mapping: [`TypeMismatchMapping`][TypeMismatchMapping]
250117}
251118```
252119
253- ## Fallback / Unknown Exceptions
120+ ## Occurrences of ` ErrorResponseException `
121+
122+ Similar to ` ProblemException ` , but comes from Spring and relies on mutable ` ProblemDetails ` object.
254123
255- What triggers it: Any unhandled exception flowing through ` ResponseEntityExceptionHandler ` without a dedicated mapping.
256- Result example:
124+ Explicitly thrown ` ErrorResponseException ` (or subclasses like ` ResponseStatusException ` ). Each of these exceptions
125+ carry HTTP status within it as well as details to be used in ` application/problem+json ` response.
126+
127+ Example:
257128
258129``` json
259130{
260- "status" : 500 ,
261- "title" : " Internal Server Error"
262- }
263- ```
131+ "type" : " https://example.org/problem-type" ,
132+ "title" : " Some Error" ,
133+ "status" : 400 ,
134+ "detail" : " Explanation of the error" ,
135+ "instance" : " https://example.org/instances/123"
136+ }
137+ ```
138+
139+ ## General HTTP Stuff
140+
141+ 1 . If trying to call ` POST ` for and endpoint with only ` GET ` (or any other similar situation), service will write
142+ following response.
143+ ``` json
144+ {
145+ "status" : 405 ,
146+ "title" : " Method Not Allowed"
147+ }
148+ ```
149+ 2 . If calling REST API with invalid ` Accept ` header, service will write following response.
150+ ``` json
151+ {
152+ "status" : 406 ,
153+ "title" : " Not Acceptable"
154+ }
155+ ```
156+ 3 . If calling REST API with invalid ` Content-Type ` header, service will write following response.
157+ ``` json
158+ {
159+ "status" : 415 ,
160+ "title" : " Unsupported Media Type"
161+ }
162+ ```
163+ 4 . If passing request body that has invalid JSON syntax, service will write following response.
164+ ``` json
165+ {
166+ "status" : 400 ,
167+ "title" : " Bad Request"
168+ }
169+ ```
170+ 5 . If passing request that's too large by configuration, service will write following response. Note that reason phrase
171+ for ` 413 ` was changed into ` Content Too Large ` in [ RFC 9110 §15.5.14] [ rfc9110-15.5.4 ] .
172+ ``` json
173+ {
174+ "status" : 413 ,
175+ "title" : " Content Too Large"
176+ }
177+ ```
178+
179+ [ rfc9110-15.5.4 ] : https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.14
264180
265181[ ExceptionMapping ] : src/main/java/io/github/malczuuu/problem4j/spring/web/mapping/ExceptionMapping.java
266182
267183[ ExceptionMappingConfiguration ] : src/main/java/io/github/malczuuu/problem4j/spring/web/mapping/ExceptionMappingConfiguration.java
268-
269- [ AsyncRequestTimeoutMapping ] : src/main/java/io/github/malczuuu/problem4j/spring/web/mapping/AsyncRequestTimeoutMapping.java
270-
271- [ ConversionNotSupportedMapping ] : src/main/java/io/github/malczuuu/problem4j/spring/web/mapping/ConversionNotSupportedMapping.java
272-
273- [ ErrorResponseMapping ] : src/main/java/io/github/malczuuu/problem4j/spring/web/mapping/ErrorResponseMapping.java
274-
275- [ HttpMediaTypeNotAcceptableMapping ] : src/main/java/io/github/malczuuu/problem4j/spring/web/mapping/HttpMediaTypeNotAcceptableMapping.java
276-
277- [ HttpMediaTypeNotSupportedMapping ] : src/main/java/io/github/malczuuu/problem4j/spring/web/mapping/HttpMediaTypeNotSupportedMapping.java
278-
279- [ HttpMessageNotReadableMapping ] : src/main/java/io/github/malczuuu/problem4j/spring/web/mapping/HttpMessageNotReadableMapping.java
280-
281- [ HttpMessageNotWritableMapping ] : src/main/java/io/github/malczuuu/problem4j/spring/web/mapping/HttpMessageNotWritableMapping.java
282-
283- [ HttpRequestMethodNotSupportedMapping ] : src/main/java/io/github/malczuuu/problem4j/spring/web/mapping/HttpRequestMethodNotSupportedMapping.java
284-
285- [ MaxUploadSizeExceededMapping ] : src/main/java/io/github/malczuuu/problem4j/spring/web/mapping/MaxUploadSizeExceededMapping.java
286-
287- [ MethodArgumentNotValidMapping ] : src/main/java/io/github/malczuuu/problem4j/spring/web/mapping/MethodArgumentNotValidMapping.java
288-
289- [ MissingPathVariableMapping ] : src/main/java/io/github/malczuuu/problem4j/spring/web/mapping/MissingPathVariableMapping.java
290-
291- [ MissingServletRequestParameterMapping ] : src/main/java/io/github/malczuuu/problem4j/spring/web/mapping/MissingServletRequestParameterMapping.java
292-
293- [ MissingServletRequestPartMapping ] : src/main/java/io/github/malczuuu/problem4j/spring/web/mapping/MissingServletRequestPartMapping.java
294-
295- [ ServletRequestBindingMapping ] : src/main/java/io/github/malczuuu/problem4j/spring/web/mapping/ServletRequestBindingMapping.java
296-
297- [ TypeMismatchMapping ] : src/main/java/io/github/malczuuu/problem4j/spring/web/mapping/TypeMismatchMapping.java
0 commit comments