<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ControllerAdvice Archives - Codersee blog- Kotlin on the backend</title>
	<atom:link href="https://blog.codersee.com/tag/controlleradvice/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>Kotlin &#38; Backend Tutorials - Learn Through Practice.</description>
	<lastBuildDate>Wed, 16 Apr 2025 04:50:21 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://blog.codersee.com/wp-content/uploads/2025/04/cropped-codersee_logo_circle_2-32x32.png</url>
	<title>ControllerAdvice Archives - Codersee blog- Kotlin on the backend</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>@ControllerAdvice vs @RestControllerAdvice</title>
		<link>https://blog.codersee.com/controlleradvice-vs-restcontrolleradvice/</link>
					<comments>https://blog.codersee.com/controlleradvice-vs-restcontrolleradvice/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Tue, 01 Feb 2022 07:00:23 +0000</pubDate>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[ControllerAdvice]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=1001997</guid>

					<description><![CDATA[<p>In this post, I would like to walk you through the differences between @ControllerAdvice and @RestControllerAdvice.</p>
<p>The post <a href="https://blog.codersee.com/controlleradvice-vs-restcontrolleradvice/">@ControllerAdvice vs @RestControllerAdvice</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="article-heading-introduction">1. Introduction</h2>
<p>In this blog post I would like to explain the differences between <strong>@ControllerAdvice </strong>and<strong> @RestControllerAdvice</strong>, because oftentimes, these two lead to confusion.</p>
<p>On the other hand, if you are not sure what are these two used for, then I recommend you to check out my <a href="https://blog.codersee.com/exception-handling-with-restcontrolleradvice-and-exceptionhandler/" target="_blank" rel="noopener">previous article</a>, where you can learn how to handle exceptions efficiently when creating Spring Boot REST API with <strong>@RestControllerAdvice</strong> and <strong>@ExceptionHandler</strong>.</p>
<h2 class="article-heading-introduction">2. What Is @ControllerAdvice?</h2>
<p>Let&#8217;s start by describing what exactly the <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html" target="_blank" rel="noopener"><strong>@ControllerAdvice </strong></a>is?</p>
<p>Basically, it&#8217;s been introduced in Spring 3.2 and is a specialized @Component that allows us to declare @ExceptionHandler, @InitBinder, or @ModelAttribute methods to be shared among @Controller classes.</p>
<p>To put it another way, we can treat it as an annotation driven interceptor, whose methods will apply to the whole application (not just to an individual controller).</p>
<h2 class="article-heading-introduction">3. What Is @RestControllerAdvice?</h2>
<p>On the other hand, the <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestControllerAdvice.html" target="_blank" rel="noopener"><strong>@RestControllerAdvice </strong></a>is a syntactic sugar for <strong>@ControllerAdvice</strong> and <strong>@ResponseBody </strong>annotations.</p>
<p>To illustrate, let&#8217;s see it&#8217;s definition:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ControllerAdvice
@ResponseBody
public @interface RestControllerAdvice</pre>
<p>Basically, the<strong> @ResponseBody</strong> indicates a method return value should be bound to the web response body. To put it simply, it allows us to implement methods without wrapping them with <em>ResponseEntity&lt;T&gt; (or HttpEntity&lt;T&gt;)</em>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">fun withResponseEntity(): ResponseEntity&lt;SomeClass&gt; =
  ResponseEntity.ok(
    SomeClass()
  )

@ResponseBody
fun withResponseBody(): SomeClass =
  SomeClass()</pre>
<p>Additionally, since Spring 4.0, it can be used on the type level, so <strong>it will be inherited by all methods of an annotated class</strong>.</p>
<h2 class="article-heading-introduction">4. @ControllerAdvice vs @RestControllerAdvice in Practice</h2>
<p>With all of that being said, let&#8217;s analyze a few examples to better understand these differences.</p>
<p>Firstly, let&#8217;s create the <strong>Exceptions.kt</strong> file with a few custom exceptions:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">class CustomExceptionOne : RuntimeException()
class CustomExceptionTwo : RuntimeException()
class CustomExceptionThree : RuntimeException()
class CustomExceptionFour : RuntimeException()
class CustomExceptionFive : RuntimeException()</pre>
<p>Nextly, let&#8217;s add the <strong>ExampleResponse</strong> class carrying messages for API consumers:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">data class ExampleResponse(val message: String)</pre>
<p>Finally, let&#8217;s implement the <strong>ExampleController </strong>class:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">@RestController
class ExampleController {

  @GetMapping("/one")
  fun endpointOne(): ExampleResponse {
    throw CustomExceptionOne()
    return ExampleResponse("Message")
  }

  @GetMapping("/two")
  fun endpointTwo(): ExampleResponse {
    throw CustomExceptionTwo()
    return ExampleResponse("Message")
  }

  @GetMapping("/three")
  fun endpointThree(): ExampleResponse {
    throw CustomExceptionThree()
    return ExampleResponse("Message")
  }

  @GetMapping("/four")
  fun endpointFour(): ExampleResponse {
    throw CustomExceptionFour()
    return ExampleResponse("Message")
  }

  @GetMapping("/five")
  fun endpointFive(): ExampleResponse {
    throw CustomExceptionFive()
    return ExampleResponse("Message")
  }

}</pre>
<p>These are just a few test endpoints, which will be helpful to better understand @ControllerAdvice and @RestControllerAdvice in our examples.  Whatsoever, we can clearly see that each method throws its own, custom exception before returning ExampleResponse instance.</p>
<p>Without a doubt, querying any of these endpoints at this point <strong>will result in <em>500 Internal Server Error</em></strong>.</p>
<h2 class="article-heading-introduction">5. @ControllerAdvice Examples</h2>
<h3 class="article-heading-sub">5.1. Plain @ControllerAdvice</h3>
<p>Undoubtedly, we don&#8217;t want our clients to see this type of responses and we should handle such cases in our code.</p>
<p>As the first step, let&#8217;s create the <strong>ErrorResponse</strong><em>,</em> which will be used to return information for properly handled exceptions:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">data class ErrorResponse(val message: String)</pre>
<p>Following, let&#8217;s create the <strong>ExampleControllerAdvice</strong>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">@ControllerAdvice
class ExampleControllerAdvice {

  @ExceptionHandler(CustomExceptionOne::class)
  fun handleExceptionOne(): ErrorResponse =
    ErrorResponse("Handled exception one!")

}</pre>
<p>As we can see, the class is marked as a <strong>@ControllerAdvice. </strong>Moreover, the method annotated with <strong>@ExceptionHandler</strong> should be invoked each time a <strong>CustomExceptionOne</strong> is thrown returning <strong>ErrorResponse</strong> instance.</p>
<p>Let&#8217;s check this assumption with cURL command:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">curl localhost:8080/one

# Console Output:
javax.servlet.ServletException: Circular view path [one]...

# Response Body: 
{
  "timestamp": "2022-01-01T01:01:01.839+00:00",
  "status": 500,
  "error": "Internal Server Error",
  "path": "/one"
}</pre>
<p>Well, this is not the response we were expecting. We can clearly see, that the exception was not caught properly leading to the <strong>ServletException</strong>.</p>
<h3 class="article-heading-sub">5.2. @ControllerAdvice with ResponseEntity</h3>
<p>But how can we solve this issue?</p>
<p>We&#8217;ve got a few possibilities, so let&#8217;s see the first one:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">@ExceptionHandler(CustomExceptionTwo::class)
fun handleExceptionTwo(): ResponseEntity&lt;ErrorResponse&gt; =
  ResponseEntity.ok(
    ErrorResponse("Handled exception two!")
  )</pre>
<p>This time, instead of returning <strong>ErrorResponse</strong> instance, we wrap it with the <strong>ResponseEntity&lt;T&gt;</strong>.</p>
<p>Let&#8217;s test our dedicated endpoint then:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">curl localhost:8080/two

# Console Output:
empty

# Response Body: 
{
  "message": "Handled exception two!"
}</pre>
<p>Obviously, this time handler works as expected returning the desired message. Whatsoever, empty console output indicates that no exception remain unhandled in this case.</p>
<h3 class="article-heading-sub">5.3. @ResponseBody On Method Level</h3>
<p>On the other hand, if we don&#8217;t want to return ResponseEntity, we can simply put <strong>@ResponseBody</strong> annotation to work:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">@ExceptionHandler(CustomExceptionThree::class)
@ResponseBody
fun handleExceptionThree(): ErrorResponse =
  ErrorResponse("Handled exception three!")</pre>
<p>Similarly, let&#8217;s check this handler:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">curl localhost:8080/three

# Console Output:
empty

# Response Body: 
{
  "message": "Handled exception three!"
}</pre>
<p>Again, the exception is handled perfectly.</p>
<h3 class="article-heading-sub">5.4. @ResponseBody On Class Level</h3>
<p>Although annotating methods with <strong>@ResponseBody</strong> is necessary in some cases, this approach would be better oftentimes.</p>
<p>To avoid unnecessary redundancy, we can simply put this annotation at the class level and it will be applied to all methods:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">@ControllerAdvice
@ResponseBody
class ExampleControllerAdviceAnnotated {

  @ExceptionHandler(CustomExceptionFour::class)
  fun handleExceptionFour(): ErrorResponse =
    ErrorResponse("Handled exception four!")
}</pre>
<p>Let&#8217;s check again:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">curl localhost:8080/four

# Console Output:
empty

# Response Body: 
{
  "message": "Handled exception four!"
}</pre>
<p>Similarly, we can see desired message in the response body.</p>
<h2 class="article-heading-introduction">6. @RestControllerAdvice Example</h2>
<p>And finally we come to the point,that <strong>@RestControllerAdvice is a @ControllerAdvice with @ResponseBody</strong> (just like above).</p>
<p>Let&#8217;s implement our last example:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">@RestControllerAdvice
class ExampleRestControllerAdvice {

  @ExceptionHandler(CustomExceptionFive::class)
  fun handleExceptionFive(): ErrorResponse =
    ErrorResponse("Handled exception five!")
}</pre>
<p>Following, let&#8217;s query the necessary endpoint:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">curl localhost:8080/five

# Console Output:
empty

# Response Body: 
{
  "message": "Handled exception five!"
}</pre>
<p>Identically, the exception has been caught successfully by the dedicated handler.</p>
<h2 class="article-heading-introduction">7. <strong>@ControllerAdvice vs @RestControllerAdvice</strong> Summary</h2>
<p>And that would be all for this comparison article on <strong>@ControllerAdvice vs @RestControllerAdvice</strong>. I believe, that after reading it you will have no more doubts about the differences between these two.</p>
<p>As always, if you would like to see the source code for this post, please check out <a href="https://github.com/codersee-blog/controlleradvice-vs-restcontrolleradvice" target="_blank" rel="noopener">this GitHub repository</a>.</p>
<p>Finally, if you enjoy this type of content, please let me know in the comments section below, or by the <a href="https://codersee.com/contact/">contact form</a>.</p>
<p>&nbsp;</p>
<h4 class="article-heading-sub">Previous articles, you might be interested in:</h4>
<ul>
<li><a href="https://blog.codersee.com/rest-api-ktor-ktorm-postgresql/" target="_blank" rel="noopener">REST API With Ktor, Ktorm and PostgreSQL</a></li>
<li><a href="https://blog.codersee.com/exception-handling-with-restcontrolleradvice-and-exceptionhandler/" target="_blank" rel="noopener">Exception Handling with @RestControllerAdvice and @ExceptionHandler</a></li>
<li><a href="https://blog.codersee.com/16-intellij-shortcuts-that-will-boost-your-productivity/" target="_blank" rel="noopener">16 IntelliJ Shortcuts That Will Boost Your Productivity</a></li>
</ul>
<p>The post <a href="https://blog.codersee.com/controlleradvice-vs-restcontrolleradvice/">@ControllerAdvice vs @RestControllerAdvice</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/controlleradvice-vs-restcontrolleradvice/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Exception Handling with @RestControllerAdvice and @ExceptionHandler</title>
		<link>https://blog.codersee.com/exception-handling-with-restcontrolleradvice-and-exceptionhandler/</link>
					<comments>https://blog.codersee.com/exception-handling-with-restcontrolleradvice-and-exceptionhandler/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Tue, 18 Jan 2022 07:00:57 +0000</pubDate>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[ControllerAdvice]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=1973</guid>

					<description><![CDATA[<p>In this article, we'll learn what exactly @RestControllerAdvice and @ExceptionHandler are, and how to use them in a Spring Boot REST API.</p>
<p>The post <a href="https://blog.codersee.com/exception-handling-with-restcontrolleradvice-and-exceptionhandler/">Exception Handling with @RestControllerAdvice and @ExceptionHandler</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading" id="h-1-introduction">1. Introduction</h2>



<p>In this article, I would like to show you several ways we can handle exceptions with <strong>@RestControllerAdvice</strong> and <strong>@ExceptionHandler</strong> in a <strong>Spring Boot REST API</strong>.</p>



<p>Exceptions are nothing else than exceptional events indicating the standard program flow has been affected in any way. Sooner or later, some of them will appear in our applications and it&#8217;s our job to handle them in the best possible way.</p>



<p>When creating <strong>REST APIs with Spring Boot</strong>, a huge amount of work is done by the framework to prevent the application from stopping. Nevertheless, returning 500 Internal Server Error responses to clients is not the best practice and in this tutorial we will see how can we fix that.</p>



<h2 class="wp-block-heading" id="h-2-restcontrolleradvice-and-exceptionhandler">2. @RestControllerAdvice and @ExceptionHandler</h2>



<p>Let&#8217;s start by describing what exactly <strong>@RestControllerAdvice</strong> and <strong>@ExceptionHandler</strong> are.</p>



<p><strong>@RestControllerAdvice</strong> is a syntactic sugar for <strong>@ControllerAdvice</strong> and <strong>@ResponseBody</strong> annotations. The first one, <strong>@ControllerAdvice</strong>, has been introduced in Spring 3.2 and allows us to write a code, which will be applied globally to all controllers. It can be used to add model enhancements methods, binder initialization methods, and what&#8217;s important for us today- to handle exceptions. In simple words, it allows us to implement some logic only once, instead of duplicating it across the app. Additionally, classes annotated with it do not have to be injected or declared explicitly in controllers, improving the decoupling of our logic.</p>



<p>On the other hand, the <strong>@ResponseBody</strong> indicates that our methods&#8217; return values should be bound to the web response body. To put it simply- our handler methods returning some <em><strong>ExampleClass</strong></em> will be treated as <strong>ResponseEntity&lt;ExampleClass></strong> out of the box. As I have said, the <strong>@RestControllerAdvice</strong> combines it with the <strong>@ControllerAdvice</strong>, so that we do not have to annotate our methods explicitly.</p>



<p>Finally, the <strong>@ExceptionHandler </strong>is an annotation used to mark that the given method should be invoked when a specific exception is thrown.</p>


<p>[elementor-template id=&#8221;9007393&#8243;]</p>



<h2 class="wp-block-heading" id="h-3-simple-exceptionhandler">3. Simple @ExceptionHandler</h2>



<p>With all of that being said, let&#8217;s create the <em>Exceptions.kt</em> file and add exceptions classes:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class FirstCustomException(message: String) : RuntimeException(message)
class SecondCustomException(message: String) : RuntimeException(message)

@ResponseStatus(HttpStatus.BAD_REQUEST)
class ThirdCustomException(message: String) : RuntimeException(message)

class FourthCustomException(message: String) : RuntimeException(message)
</pre>



<p>As we can see, they are pretty much the same, except the <em>ThirdCustomException</em>, which is marked as <em>400 Bad Request</em>.</p>



<p>As the next step, let&#8217;s create a controller class with the first method:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@RestController
class ExampleController {

  @GetMapping("/example-exception-one")
  fun getExampleExceptionOne(): ExampleResponseBody {
    throw FirstCustomException("First exception message")
    return ExampleResponseBody(message = "ok")
  }
  
  data class ExampleResponseBody(val message: String)
}
</pre>



<p>We can clearly see, that the exception is thrown and the <em>ExampleResponseBody</em> instance will be never returned.</p>



<p>Whatsoever, if we run the application and perform a GET request, we will see the<em> Internal Server Error</em>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{
  "timestamp": "2022-01-14T07:08:10.061+00:00",
  "status": 500,
  "error": "Internal Server Error",
  "path": "/example-exception-one"
}
</pre>



<p>As the next step, let&#8217;s add the <em>ExampleAdvice</em> class:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@RestControllerAdvice
class ExampleAdvice {

  @ExceptionHandler(FirstCustomException::class)
  fun handleFirstCustomException() {
    println("FirstCustomException handler")
  }
}
</pre>



<p>This time, the class is annotated with the <em><strong>@RestControllerAdvice</strong></em> and it contains a method which will print some text to the output. The most important thing is that the function is annotated with the <em><strong>@ExceptionHandler</strong></em> indicating, <strong>which exception should be handled by it</strong>. Moreover, it allows us to specify multiple exceptions, for example:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@ExceptionHandler(value = [ExceptionOne::class, ExceptionTwo::class])</pre>



<p>But let&#8217;s get back to our example, rerun the application and test the endpoint once again. This time, the <em>200 OK</em> response has been returned along with the desired message printed to the console:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Console:
FirstCustomException handler
# Response:
Status: 200 OK
Body: empty</pre>



<p>Unfortunately, the response body is empty, which may cause problems (and we will see better approaches in the next examples). Besides that, we can clearly see that the handler is working, as expected.</p>



<h2 class="wp-block-heading" id="h-4-map-status-code-with-responsestatus">4. Map Status Code With @ResponseStatus</h2>



<p>As the next example, let&#8217;s see how can we map the status code returned by our handler. Let&#8217;s add a new method within the controller:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@GetMapping("/example-exception-two")
fun getExampleExceptionTwo(): ExampleResponseBody {
  throw SecondCustomException("Second exception message")
  return ExampleResponseBody(message = "ok")
}
</pre>



<p>It&#8217;s almost exactly the same as the previous one.</p>



<p>Nextly, let&#8217;s implement a new exception handler:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@ResponseStatus(HttpStatus.FAILED_DEPENDENCY)
@ExceptionHandler(SecondCustomException::class)
fun handleSecondCustomException() {
  println("SecondCustomException handler")
}
</pre>



<p>This time, we&#8217;ve additionally marked it with the <em><strong>@ResponseStatus</strong></em> annotation and the desired HTTP status.</p>



<p>Similarly, let&#8217;s test our new endpoint:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Console:
SecondCustomException handler
# Response:
Status: 200 OK
Body: empty</pre>



<p>We can clearly see that the new handler has been triggered and the <strong><span class="response-meta-status-code">424 </span></strong><span class="response-meta-status-code-desc"><strong>Failed Dependency</strong> has been returned. Not an ideal solution, but still better, then the previous one.</span></p>



<h2 class="wp-block-heading" id="h-5-read-exception-message-and-re-throw-exception">5. Read Exception Message and Re-throw Exception</h2>



<p>For the record, in the beginning, we&#8217;ve annotated the <em>ThirdCustomException</em> with <strong>@ResponseStatus</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@ResponseStatus(HttpStatus.BAD_REQUEST)
class ThirdCustomException(message: String) : RuntimeException(message)</pre>



<p>It means, that it will be translated to <em>400 Bad Request</em> each time it is thrown (so that we won&#8217;t have to mark our handler method).</p>



<p>Nevertheless, let&#8217;s focus on the another approach, which resolves the issue with empty response body. Just like previously, let&#8217;s start by adding the necessary controller:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@GetMapping("/example-exception-three")
fun getExampleExceptionThree(): ExampleResponseBody {
  throw ThirdCustomException("Third exception message")
  return ExampleResponseBody(message = "ok")
}
</pre>



<p>As the next step, let&#8217;s implement a new exception handler:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@ExceptionHandler(ThirdCustomException::class)
fun handleThirdCustomException(ex: ThirdCustomException) {
  println("ThirdCustomException handler. Exception message: ${ex.message}")
  throw ex
}</pre>



<p>As we can see, except marking our methods with annotation, we additionally inject the exception instance. This approach might be really helpful when we would like to <strong>log the exception details</strong>. It&#8217;s worth mentioning, that handler methods allow us to inject plenty of information, so I highly recommend you to check out the <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/ExceptionHandler.html" target="_blank" rel="noopener">documentation</a> (we&#8217;ll cover one more in the next example).</p>



<p>Finally, let&#8217;s test the endpoint:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Console:
ThirdCustomException handler. Exception message: Third exception message

# Response:
Status: 400 Bad Request
Body:
{
  "timestamp": "2022-01-18T01:01:01.111+00:00",
  "status": 400,
  "error": "Bad Request",
  "path": "/example-exception-three"
}</pre>



<p>As we can see, the console output contains the<strong> exception message</strong>, which might be really helpful in the real-life scenarios. Additionally, <strong>the response body is not empty anymore</strong> providing more information to the API client.</p>



<h2 class="wp-block-heading" id="h-6-return-custom-object">6. Return Custom Object</h2>



<p>I&#8217;ve mentioned in the beginning that <em><strong>@RestControllerAdvice</strong></em> is a <em><strong>@ControllerAdvice</strong> </em>enhanced with the <em><strong>@ResponseBody</strong></em> annotation.</p>



<p>Let&#8217;s add the below code:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@GetMapping("/example-exception-four")
fun getExampleExceptionFour(): ExampleResponseBody {
  throw FourthCustomException("Fourth exception message")
  return ExampleResponseBody(message = "ok")
}
</pre>



<p>As the next step, let&#8217;s implement a new handler along with a custom data class:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@ExceptionHandler(FourthCustomException::class)
fun handleFourthCustomException(
  req: HttpServletRequest,
  ex: FourthCustomException
): ExceptionResponseBody {
  println("FourthCustomException handler. Request details: [${req.getHeader("custom-header")}]")
  return ExceptionResponseBody(errorMessage = ex.message)
}

data class ExceptionResponseBody(val errorMessage: String?)</pre>



<p>If we query this endpoint passing &#8216;<em>passed value&#8217;</em> as a value of &#8216;<em>custom-header&#8217; </em>header, we should see the following result:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Console:
FourthCustomException handler. Request details: [passed value]

# Response:
Status: 200 OK
Body:
{
  "errorMessage": "Fourth exception message"
}</pre>



<p>Unquestionably, the desired value has been obtained correctly. Moreover, the instance of <em>ExceptionResponseBody</em> has been<strong> serialized to JSON</strong> and sent as a request body with <em>200 OK</em> status.</p>



<p>This strategy might be really useful, if we would like to extract some custom format for our errors.</p>



<h2 class="wp-block-heading" id="h-7-restcontrolleradvice-and-exceptionhandler-summary">7. @RestControllerAdvice and @ExceptionHandler Summary</h2>



<p>And that would be all for this tutorial covering <strong>@RestControllerAdvice and @ExceptionHandler</strong>. We went through a few practical examples describing how to use these two can help you when working with<strong> Spring Boot</strong>.</p>



<p>If you would like to see the source code for this article, please refer to <a href="https://github.com/codersee-blog/kotlin-spring-boot-restcontrolleradvice" target="_blank" rel="noopener">this GitHub repository</a>. Also, I&#8217;ve created one more article related to @RestControllerAdvice, which you can find <a href="https://blog.codersee.com/controlleradvice-vs-restcontrolleradvice/">right here</a>.</p>



<p>Finally, if you find this kind of articles useful, or have any suggestions, please let me know in the comments section, or through the <a href="https://codersee.com/contact/" target="_blank" rel="noopener">contact form</a>.</p>



<h4 class="wp-block-heading" id="h-">&nbsp;</h4>



<h4 class="wp-block-heading" id="h-previous-articles-you-might-be-interested-in">Previous articles, you might be interested in:</h4>



<ul class="wp-block-list">
<li><a href="https://blog.codersee.com/16-intellij-shortcuts-that-will-boost-your-productivity/" target="_blank" rel="noopener">16 IntelliJ Shortcuts That Will Boost Your Productivity</a></li>



<li><a href="https://blog.codersee.com/solid-principles-with-kotlin-examples/" target="_blank" rel="noopener">SOLID Principles with Kotlin Examples</a></li>



<li><a href="https://blog.codersee.com/sring-boot-kotlin-apache-pdfbox/">How to Generate a PDF in a Spring Boot REST API with Apache PDFBox and Kotlin</a></li>
</ul>
<p>The post <a href="https://blog.codersee.com/exception-handling-with-restcontrolleradvice-and-exceptionhandler/">Exception Handling with @RestControllerAdvice and @ExceptionHandler</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/exception-handling-with-restcontrolleradvice-and-exceptionhandler/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 

Served from: blog.codersee.com @ 2026-04-19 17:42:00 by W3 Total Cache
-->