Spring Boot Bootcamp – Workbooks and Challenges

Workbook 8.2

In workbook 8.1, we handled bad requests by throwing and catching checked exceptions. This method is annoying because it forces you to modify the service methods.

In this workbook, you will handle bad requests using a ControllerAdvice class.

Launch the starter project

Screen Shot 2022-07-13 at 9.46.09 PM.png

Task 1

Create a new folder called exception. Inside the folder, create a ContactNotFoundException class.

Use the following code to create a custom unchecked exception:

public class ContactNotFoundException extends RuntimeException { public ContactNotFoundException(String id) { //constructor gets called when exception is thrown super("The id '" + id + "' does not exist in our records"); //passing an error message into the parent constructor allows us to access it later... } }

Task 2

Modify the findIndexById function to throw the ContactNotFoundException.

private int findIndexById(String id) { return IntStream.range(0, contactRepository.getContacts().size()) .filter(index -> contactRepository.getContacts().get(index).getId().equals(id)) .findFirst() .orElseThrow(() -> new ContactNotFoundException(id)); }

Because it's an unchecked RuntimeException, there is no need to catch it. It will just be thrown as the application runs.

Task 3

Run the application and make a GET request from Postman. There is no data in the ArrayList, so pass in any id.

  • GET: localhost:8080/contact/123

Because your application threw an exception in the middle of a request, it sends back a 5xx error code.

Screen Shot 2022-07-13 at 10.09.05 PM.png

5xx means there was a failure from the server (our application).

Screen Shot 2022-07-13 at 10.12.52 PM.png

But really, the failure results from the client's bad request. So our application should not fail, it should send back a 4xx error code instead.

New Concept: @ControllerAdvice

class-level annotation that allows you to define global exception handlers.

New Concept: @ExceptionHandler

method-level annotation that defines an exception handler.

Screen Shot 2022-07-13 at 11.58.50 PM.png

  1. Defines the exception that you want the method to handle.
  2. The thrown exception can be accessed from the list of arguments.

Task 4

Create a class called ApplicationExceptionHandler. Then apply the @ControllerAdvice annotation. By doing so, your class will serve as the global exception handler.

Task 5

Inside your global exception handler:

  • Create a method called handleContactNotFoundException, and mark it as an @ExceptionHandler.
  • Your exception handler must pick up exceptions of type ContactNotFoundException.
  • Your exception handler's return type will be ResponseEntity<Object>. This is common practice because Object allows us to pass anything into the ResponseEntity.
  • For now, your method will return a ResponseEntity that contains a status code of 404.

Test Case: GET: localhost:8080/contact/123

Screen Shot 2022-07-14 at 12.08.04 AM.png

The exception handler handles the exception by responding to the consumer with a 404 status code.

Task 6

It would be nice to send the user an error response. Inside the exception folder, create a class called ErrorResponse.

public class ErrorResponse { }

Create the following field and generate a complete constructor, getters and setters.

private String message;

Task 7

Inside handleContactNotFoundException, create a new ErrorResponse object, and pass the exception's message into the constructor.

ErrorResponse errorResponse = new ErrorResponse(ex.getMessage());

Return the errorResponse object along with the status code.

return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);

Spring Boot will automatically serialize the errorResponse object inside the ResponseEntity into JSON.

Test Case: GET: localhost:8080/contact/123

Screen Shot 2022-07-14 at 12.25.38 AM.png

Task 8

It would be nice to also send back a timestamp. Add another field inside ErrorResponse, and generate the usual getters and setters.

private LocalDateTime timestamp;

Inside the constructor, set the timestamp equal to the current time.

public ErrorResponse(String message) { this.timestamp = LocalDateTime.now(); this.message = message; }

Test Case: GET: localhost:8080/contact/123

Screen Shot 2022-07-14 at 12.29.53 AM.png The timestamp is barely readable.

Task 9

You can configure how each property gets serialized into JSON.

Screen Shot 2022-07-14 at 12.35.31 AM.png

  1. Defines the structure to use when serializing into JSON .
  2. Defines the pattern to use when serializing into JSON.

We wish to configure how the timestamp property will be serialized into JSON. The structure we will serialize to will remain JSON STRING type. The pattern will be dd-MM-yyyy hh:mm:ss

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss")

Test Case: GET: localhost:8080/contact/123

Screen Shot 2022-07-14 at 12.41.07 AM.png

Good Luck!

Feedback Summary
4 students





Written Reviews
There are no written reviews yet.