Exception handling is very important in software projects because it will decide what are next steps that software should handle when an exception happens in run time. For example, if an exception happens in loading data in database so we can notify to FE a message with is friendly and familiar with user/business so they can know what is happening to take action. For developers they will know where this exception happened and find root causes easier by reading or searching logs. Moreover, in special software regarding to finance and banking, developers have to handle all exceptions that can occur closely with business cases.
MessageSource is a powerful feature available in Spring applications. This helps application developers handle various complex scenarios with writing much extra code, such as environment-specific configuration, internationalization or configurable values. One more scenario could be modifying the default validation messages to more user-friendly/custom messages.
In spring boot MessageSource has been added as default, so you don't need to add any dependency for this feature. However, you have to create a configuration for using. So, let's create a configuration class AppConfig and put configuration codes as below
Note: by default the name of the bean is the method name, so you have to add @Bean(name = "messageSource") if you are using a custom method name. Then you need to set Basenames for messageSource which include the path and the suffix of your properties files. Let's see the image below.
Then you need to create properties files to contain messages, I will create 3 properties file with 3 different languages.
Note: By default when you use Intellij to create properties files, your files will be encoded as ISO-88591. So when you put other languages, for example: Japanese or Vietnamese languages, the messages can not be encoded to UTF-8 then you can not read your messages in these languages. To solve this issue you need to create properties files with UTF-8 encoding.
So you need to open File -> Settting of Intellij, then you choose the path to your properties files with Encoding is UTF-8 and choose default encoding for properties files as UTF-8 too. let's see the image below.
Next, createerror.properties file as in the image, it will contain default language as English, so we will define an example message as below.
Next, createerror.properties file as in the image, it will contain default language as English, so we will define an example message as below.
service.customer.email.1=can not find any customer following email {0}
In the error_ja.properties file we will add Japanese message as below:
We will create a custom exception from RuntimeException class, because it is the top and represent for unchecked exception in Java. If you don't know what is the checked exception or unchecked exception you can view Java Core Introduction for more details.
So, we will create an exception name ResourceNotFoundException and it is extended from RuntimeException. Then we will create 3 constructors and 2 attributes as below.
Next, We will create an exception handler class named GlobalExceptionHandler which will extends from ResponseEntityExceptionHandler class, by default the ResponseEntityExceptionHandler will provide an @ExceptionHandler method for handling internal Spring MVC exceptions which include exceptions below.
HttpRequestMethodNotSupportedException.class
HttpMediaTypeNotSupportedException.class
HttpMediaTypeNotAcceptableException.class
MissingPathVariableException.class
MissingServletRequestParameterException.class
ServletRequestBindingException.class
ConversionNotSupportedException.class
TypeMismatchException.class
HttpMessageNotReadableException.class
HttpMessageNotWritableException.class
MethodArgumentNotValidException.class
MissingServletRequestPartException.class
BindException.class
NoHandlerFoundException.class
AsyncRequestTimeoutException.class
In our case, we want to handle our custom exception and return custom response body so that is the reason why we extends from ResponseEntityExceptionHandler.
We will define the exception that we want to resolve in @ExceptionHandler(value = {<your custome exception class>}). Then We also use the MessageSource to get the message that we defined in properties file following the default Locale. Form the custom exception ResourceNotFoundException we can get some information and put it into the reponse body ErrorResponse.
For the Entity and Repository, please view full source code in SUMMARY path of this post or you can create them by yourself.
Finally, we will add some configuration in to application.yml, I would like to set the default Locale as Japan. So I should got the error message with Japanese languages.
Now, start the service and use postman to call api, then you will see the result as below.
- Then when we configure locale as VietNam so, we will received a Vietnamese message.
application.yml
1234
spring:web:locale:vi_VNlocale-resolver:fixed
- If we do not configure default Locale or we configure a locale that does not existed in our messages resource, so the service will automatically return the default message in error.properties file.
application.yml
1 2 3 4 5 6 7 8 91011
spring:web:locale:it_ITlocale-resolver:fixed# or comment out as below.# spring:# web:# locale: it_IT# locale-resolver: fixed
In conclusion, Exception handling is very important in software development, it is not only help users know what happened in system but also help developer can determine quickly and exactly the root causes.
We create a custom exception by extend RuntimeException class because it is the top of unchecked exceptions. It means every exception happened at runtime will be navigated to RuntimeException.
We can create an exception handler with a class using @ControllerAdvice and extended from ResponseEntityExceptionHandler. In this class methods can handle one or more Exceptions with support of @ExceptionHandler. From information of custom exceptions we can build the response body following what we want.
With the supports from Spring Framework, MessageSource is very helpful when we want to change error message language or simply use it as a place to contain all error messages which will help us maintain error messages and use them easier.
To view full source code you can go to this github link