Alexey Zvolinskiy

About Alexey Zvolinskiy

Alexey is a test developer with solid experience in automation of web-applications using Java, TestNG and Selenium. He is so much into QA that even after work he provides training courses for junior QA engineers.

Spring REST: Exception handling vol. 1

Table of contents

Hi everyone, it’s time to continue publish new articles in my blog. So I’m happy to announce that I’m planning to write a couple of technical series of posts. In the current post I’m going to start talking about a Spring REST Exception handling. Spring suggests to us several ways of REST exception handling, but I want to concentrate your attention on two of them:Spring-Exception-Handling

  • @ExceptionHandler on a @Controller level
  • @ExceptionHandler on a @ControllerAdvice level

All code examples will be developed with an application which I used in my previous posts about REST services. JQuery will provide interaction with REST services on a client side.

So after the concise introduction I want to summarize. We will consider three examples of REST exception handlers. Each of these three cases will describe solution of some real situation which can occur in any project. All development will be done on a top of already existed application.

Preparation

The first thing which I want to do – it’s to add MessageSource to the application. It’s not very hard and I don’t want to stop on this in details, because I have explained how to do this in a separate post. A purpose of the MessageSource is to store error messages which I want to return to a client in a case if exception was thrown.

So here is a messages.properties file:

error.bad.smartphone.id = Smartphone can't have id:

After MessageSource was successfuly added we can continue with exception handling on a @Controller level.

Exception handling

In this paragraph I want to highlight code snippets where exception can occur. Let’s examine some methods from the SmartphoneController.

...
	@RequestMapping(value="/edit/{id}", method=RequestMethod.GET)
	public ModelAndView editSmartphonePage(@PathVariable int id) {
		ModelAndView mav = new ModelAndView("phones/edit-phone");
		Smartphone smartphone = smartphoneService.get(id);
		mav.addObject("sPhone", smartphone);
		return mav;
	}
...
	@RequestMapping(value="/edit/{id}", method=RequestMethod.PUT, 
			produces = MediaType.APPLICATION_JSON_VALUE,
			consumes = MediaType.APPLICATION_JSON_VALUE)
	@ResponseBody
	public Smartphone editSmartphone(@PathVariable int id, 
			@Valid @RequestBody Smartphone smartphone) {
		smartphone.setId(id);
		return smartphoneService.update(smartphone);
	}
...
	@RequestMapping(value="/delete/{id}", method=RequestMethod.DELETE, 
			produces = MediaType.APPLICATION_JSON_VALUE,
			consumes = MediaType.APPLICATION_JSON_VALUE)
	@ResponseBody
	public Smartphone deleteSmartphone(@PathVariable int id) {
		return smartphoneService.delete(id);
	}
...

These three methods have one common feature – @PathVariable int id. This circumstance is important, because Spring documentation said that if method argument annotated with @PathVariable can’t be casted to specified type (in our case to int), it will be exposed as String. Hence it can cause a TypeMismatchException.

To handle this I will use @ExceptionHandler annotation on @Controller level. Such approach suits for this situation as no one else. I just need to make 2 changes in the SmartphoneController:

  • Add MessageSource field
  • Add exception handler method
...
	@Autowired
	private MessageSource messageSource;
...
	@ExceptionHandler(TypeMismatchException.class)
	@ResponseStatus(value=HttpStatus.NOT_FOUND)
	@ResponseBody
	public ErrorInfo handleTypeMismatchException(HttpServletRequest req, TypeMismatchException ex) {
		Locale locale = LocaleContextHolder.getLocale();
		String errorMessage = messageSource.getMessage("error.bad.smartphone.id", null, locale);

		errorMessage += ex.getValue();
		String errorURL = req.getRequestURL().toString();

		return new ErrorInfo(errorURL, errorMessage);
	}
...

Let’s consider the method. The @ExceptionHandler annotation has the argument – TypeMismatchException, this mean that the method will be triggered when the exception will occur. The @ResponseStatus annotation used for specifying of particular response status code.

You probably noticed that the method returns ErrorInfo. Here is nothing difficult it is a class for any kind of error which need to inform a client about error cause. So the class looks like:

public class ErrorInfo {

	private String url;
	private String message;

	public ErrorInfo(String url, String message) {
		this.url = url;
		this.message = message;
	}

//Getters and setters are omitted

}

Using of this class gives to us two main advantages: we can provide a URL which caused an exception and we can provide appropriate error message.

Now let’s try to see what we have in case when I try to access some URL with unacceptable id.

Spring-Exception-Handling-Controller

You can see on the screenshot that the URL with bad id was handled as I specified on the @Controller level. In the next article I will talk about some exceptions which we can place on @ControllerAdvice level.
 

Reference: Spring REST: Exception handling vol. 1 from our JCG partner Alexey Zvolinskiy at the Fruzenshtein’s notes blog.
Related Whitepaper:

Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions

Get ready to program in a whole new way!

Functional Programming in Java will help you quickly get on top of the new, essential Java 8 language features and the functional style that will change and improve your code. This short, targeted book will help you make the paradigm shift from the old imperative way to a less error-prone, more elegant, and concise coding style that’s also a breeze to parallelize. You’ll explore the syntax and semantics of lambda expressions, method and constructor references, and functional interfaces. You’ll design and write applications better using the new standards in Java 8 and the JDK.

Get it Now!  

Leave a Reply


7 × = twenty eight



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

20,709 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books