@@ -20,15 +20,16 @@ Requires Java 17+, Spring boot 3.2.0+ and Jakarta EE 10
20
20
7 . [ Error Key, the central concept behind error attribute's externalization] ( #error-key )
21
21
8 . [ Error response characteristics] ( #error-response )
22
22
9 . [ Message resolvers to externalize error response in ` properties ` files] ( #message-resolvers )
23
- 10 . [ Creating and throwing exceptions in your applications] ( #creating-and-throwing-exceptions )
24
- 11 . [ Stack trace embedded in error response] ( #stack-traces )
25
- 12 . [ Cause chains embedded in error response] ( #cause-chains )
26
- 13 . [ Customizations of default behaviour] ( #customizations )
23
+ 10 . [ Message Internalization or i18n] ( #message-internalization )
24
+ 11 . [ Creating and throwing exceptions in your applications] ( #creating-and-throwing-exceptions )
25
+ 12 . [ Stack trace embedded in error response] ( #stack-traces )
26
+ 13 . [ Cause chains embedded in error response] ( #cause-chains )
27
+ 14 . [ Customizations of default behaviour] ( #customizations )
27
28
- [ Customize error response] ( #customize-error-response )
28
29
- [ Customize or Override advices] ( #customize-or-override-advices )
29
- 14 . [ Define new advices] ( #define-new-advices )
30
- 15 . [ Testing support] ( #testing-support )
31
- 16 . [ Example error responses in different scenarios] ( #example-error-responses )
30
+ 15 . [ Define new advices] ( #define-new-advices )
31
+ 16 . [ Testing support] ( #testing-support )
32
+ 17 . [ Example error responses in different scenarios] ( #example-error-responses )
32
33
33
34
## Introduction
34
35
@@ -49,7 +50,7 @@ all can be done with zero custom code but by specifying error details in `proper
49
50
50
51
## Installation
51
52
52
- > ** Current version: 1.9.2 ** Refer to [ Release notes] ( https://github.com/officiallysingh/spring-boot-problem-handler/releases ) while upgrading
53
+ > ** Current version: 1.9.3 ** Refer to [ Release notes] ( https://github.com/officiallysingh/spring-boot-problem-handler/releases ) while upgrading
53
54
54
55
Add the ` spring-boot-problem-handler ` jar to application dependencies. That is all it takes to get a default working
55
56
exception handling mechanism in a Spring boot application.
@@ -62,12 +63,12 @@ Maven
62
63
<dependency >
63
64
<groupId >io.github.officiallysingh</groupId >
64
65
<artifactId >spring-boot-problem-handler</artifactId >
65
- <version >1.9.2 </version >
66
+ <version >1.9.3 </version >
66
67
</dependency >
67
68
```
68
69
Gradle
69
70
``` groovy
70
- implementation 'io.github.officiallysingh:spring-boot-problem-handler:1.9.2 '
71
+ implementation 'io.github.officiallysingh:spring-boot-problem-handler:1.9.3 '
71
72
```
72
73
73
74
It does all hard part, A lot of advices are out of box available that are autoconfigured as ` ControllerAdvice ` s
@@ -505,9 +506,82 @@ To minimize the number of properties following defaults are taken if `HttpStatus
505
506
> ` status. ` (error key) property is considered only for exceptions where no explicit advice is defined,
506
507
otherwise ` HttpStatus ` is specified in the java code.
507
508
509
+ ## Message internalization
510
+ The error messages are read from configured resource bundles,
511
+ by [ ProblemMessageProvider] ( src/main/java/com/ksoot/problem/spring/config/ProblemMessageProvider.java )
512
+ for current request ` Locale ` given by ` LocaleContextHolder.getLocale() ` .
513
+ By default, spring boot autoconfigures ` AcceptHeaderLocaleContextResolver ` to get ` Locale ` from ` Accept-Language ` request header.
514
+
515
+ If the ` Accept-Language ` header is ` fr ` then the error messages are read from ` _fr.properties ` file from configured resource bundles.
516
+ Following request in demo project [ ** ` problem-handler-web-demo ` ** ] ( https://github.com/officiallysingh/problem-handler-web-demo )
517
+
518
+ ``` curl
519
+ curl --location 'http://localhost:8080/api/states' \
520
+ --header 'accept: */*' \
521
+ --header 'Content-Type: application/json' \
522
+ --header 'Accept-Language: fr' \
523
+ --header 'Cookie: JSESSIONID=9EF49EB9744759DF7A1EE71BD2154A53' \
524
+ --data '{
525
+ "name": "Haryana",
526
+ "gstCode": "6"
527
+ }'
528
+ ```
529
+
530
+ returns following error message in French language as specified in
531
+ [ ** ` errors_fr.properties ` ** ] https://github.com/officiallysingh/problem-handler-web-demo/blob/main/src/main/resources/i18n/errors_fr.properties file.
532
+ ``` properties
533
+ ```json
534
+ {
535
+ " type" : " http://localhost:8080/problems/help.html#401" ,
536
+ " title" : " Non autorisé" ,
537
+ " status" : 401,
538
+ " detail" : " Le jeton d'autorisation de l'en-t�te est manquant ou invalide" ,
539
+ " instance" : " /api/states" ,
540
+ " method" : " POST" ,
541
+ " timestamp" : " 2025-04-19T14:53:30.285582+05:30" ,
542
+ " code" : " 401"
543
+ }
544
+ ```
545
+
546
+ > [ !IMPORTANT]
547
+ > ` LocaleContextHolder.getLocale() ` gets the current request ` Locale ` from ` ThreadLocal ` , which does not work in case of reactive applications (Webflux)
548
+ > as each operator in reactive pipeline can execute in a different thread, and the context is not inherited from calling thread, but explicitly need to be propagated.
549
+ > Similar to [ ** ` ReactiveSecurityContextHolder ` ** ] ( https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/core/context/ReactiveSecurityContextHolder.html ) there is no reactive context holder.
550
+
551
+ For demo purpose, defining the following bean serves the purpose, but not recommended in production.
552
+ ``` java
553
+ @Bean
554
+ public HttpHandler httpHandler(ApplicationContext applicationContext) {
555
+ LocaleContextHolder . getLocaleContext(). getLocale();
556
+ HttpHandler delegate = WebHttpHandlerBuilder
557
+ .applicationContext(applicationContext). build();
558
+ return new HttpWebHandlerAdapter (((HttpWebHandlerAdapter ) delegate)) {
559
+ @Override
560
+ protected ServerWebExchange createExchange (ServerHttpRequest request ,
561
+ ServerHttpResponse response ) {
562
+ ServerWebExchange serverWebExchange = super
563
+ .createExchange(request, response);
564
+ LocaleContext localeContext = serverWebExchange. getLocaleContext();
565
+ if (localeContext != null ) {
566
+ LocaleContextHolder . setLocaleContext(localeContext, true );
567
+ }
568
+ return serverWebExchange;
569
+ }
570
+ };
571
+ }
572
+ ```
573
+
574
+ You can define your own [ ** ` ProblemMessageProvider ` ** ] ( src/main/java/com/ksoot/problem/spring/config/ProblemMessageProvider.java ) bean as follows, that should be able to find current request ` Locale ` somehow.
575
+ ``` java
576
+ @Bean
577
+ ProblemMessageProvider problemMessageProvider(final MessageSource messageSource) {
578
+ return new YourReactiveProblemMessageProvider (messageSource);
579
+ }
580
+ ```
581
+
508
582
## Creating and throwing exceptions
509
583
510
- Apart from exceptions thrown by frameworks or java, every application need to throw custom exceptions.
584
+ Apart from exceptions thrown by frameworks or java, every application needs to throw custom exceptions.
511
585
[ ** ` ApplicationProblem ` ** ] ( src/main/java/com/ksoot/problem/core/ApplicationProblem.java ) and
512
586
[ ** ` ApplicationException ` ** ] ( src/main/java/com/ksoot/problem/core/ApplicationException.java )
513
587
classes are available in the library to throw an unchecked or checked exception respectively.
0 commit comments