Error Handling in a REST Service with Quartz
Java, Maven, Liquibase, Quartz, REST, Spring Boot
Spring MVC provides several complimentary approaches to exception handling.
Introduction
I welcome you all to this third post in the series of integrating Quartz with Spring. Througout the course of this tutorial on Quartz, you will notice we have not done any error handling. In this post I will show you how to configure a Spring REST application to handle errors.
This post builds upon the previous post and you can get the source/base for this post as zip|tar.gz. Extract the contents of the archive and let us begin.
Directory structure
The contents of the archive should be similar to the directory structure below:
.
|__src/
| |__main/
| | |__java/
| | | |__com/
| | | | |__juliuskrah/
| | | | | |__quartz/
| | | | | | |__Application.java
| | | | | | |__autoconfigure/
| | | | | | | |__QuartzProperties.java
| | | | | | |__job/
| | | | | | | |__EmailJob.java
| | | | | | |__mail/
| | | | | | | |__javamail/
| | | | | | | | |__AsyncMailSender.java
| | | | | | |__model/
| | | | | | | |__JobDescriptor.java
| | | | | | | |__TriggerDescriptor.java
| | | | | | |__service/
| | | | | | | |__EmailService.java
| | | | | | |__web/
| | | | | | | |__rest/
| | | | | | | | |__EmailResource.java
| | | | | | | | |__errors/
| | | | | | | | | |__ErrorVO.java
| | | | | | | | | |__ExceptionTranslator.java
| | | | | | | | | |__FieldErrorVO.java
| | | |__org/
| | | | |__springframework/
| | | | | |__boot/
| | | | | | |__autoconfigure/
| | | | | | | |__quartz/
| | | | | | | | |__AutowireCapableBeanJobFactory.java
| | | |__io/
| | | | |__github/
| | | | | |__jhipster/
| | | | | | |__async/
| | | | | | | |__ExceptionHandlingAsyncTaskExecutor.java
| | |__resources/
| | | |__db/
| | | | |__changelog/
| | | | | |__db.changelog-master.yaml
| | | |__application.yaml
| | | |__quartz.properties
|__pom.xml
Prerequisites
To follow along with this guide, you should have the following set up on your development machine:
Optional
Adding Validation
I will start with basic validation by annotating the *Descriptor
classes with Hibernate Validator annotations.
Hibernate Validator is the Reference Implementation of Bean Validation [JSR 349] (for those of you who like to know):
file:
src/main/java/com/juliuskrah/quartz/model/TriggerDescriptor.java
The trigger name
and group
may not be empty or null.
file:
src/main/java/com/juliuskrah/quartz/model/JobDescriptor.java
As you can see from the above, there is no validation on the group
. This is because the API consumers are not
required to specify a group name in the request payload but rather in the URL as a PathVariable
.
To activate the validation, annotate the JobDescriptor
parameter with @Valid
:
file:
src/main/java/com/juliuskrah/quartz/web/rest/EmailResource.java
You can test this out by making a POST
or PUT
request and leave the name
field blank.
Adding Exceptions
Let us start with throwing Unchecked
exceptions for a few known exception prone areas. When an API
consumer creates a job and specifies its trigger(s) and fails to add either cron
or fireTime
in the
trigger(s) we will throw an IllegalStateException
:
file:
src/main/java/com/juliuskrah/quartz/model/TriggerDescriptor.java
We can also validate the given cron
expression and throw IllegalArgumentException
if expression is invalid:
file:
src/main/java/com/juliuskrah/quartz/model/TriggerDescriptor.java
We need to ensure that consumers of our API do not register jobs with an existing name
and group
in the
scheduler:
file:
src/main/java/com/juliuskrah/quartz/service/EmailService.java
I will show you how to translate these exceptions into meaningful 4xx
status codes to the API consumer in the
next section.
Adding Exception Translators
We will create two immutable value objects (FieldErrorVO
and ErrorVO
) to transfer the errors to the API consumers.
To ease this creation we will use Immutables:
file:
pom.xml
Immutables is an annotation processor and if you are using an IDE you can activate it by following the instructions laid out in this link.
We will create a value object to map field validation errors:
file:
src/main/java/com/juliuskrah/quartz/web/rest/errors/FieldErrorVO.java
While
ImmutableFieldErrorVO
may not be generated yet, the above will compile properly
And another value object to map all other errors:
file:
src/main/java/com/juliuskrah/quartz/web/rest/errors/ErrorVO.java
While
ImmutableErrorVO
may not be generated yet, the above will compile properly
Now we create the ExceptionTranslator
class:
file:
src/main/java/com/juliuskrah/quartz/web/rest/errors/ExceptionTranslator.java
That’s all folks
Conclusion
In this post we learned how to validate and handle errors from the client and server. You can extend this to create powerful and robust exception handling for your APIs.
You can find the source to this guide in the github repository. Until the next post, keep doing cool things .