Java Jersey Database with Jersey 2.26 and JDBI
In the previous blog we created an empty Jersey project to have a hello world service but it is quite useless as you expect. To make it more realistic I will add database connection and implement some methods with JDBI. You can use other options like MyBatis or Hibernate but I really don’t like giving all control to the ORM. If you haven’t used JDBI before it is the default JDBC Api on Dropwizard and actually it is quite similar to the Spring JDBC Template. Since we will be using simple stuff you will get the idea very quickly so don’t worry about that.
How does this really work? We don’t have a database connection at this stage and how do we start the db connection with application start and close it when the application is closed?
Answer is ServletContextListener
for the web app which enables us to have methods when context initialized and destroyed. It basically gives access to the start and end of your application. Also we could be using @PostConstruct
and @PreDestroy
for RestApplication
class and as expected it will run after app is initialized and before getting destroyed. Additionally if your app is not deployed as war but a jar then you can start your modules at start and close them on Shutdown Hook
properly.
When you try to implement ServletContextListener
you will notice it is not in our project scope yet. Add javax.servlet-api
to your pom to be able to use ContextListener
properly. Next will be defining a custom listener and adding it to our web.xml
file.
ServletContextListener
has two methods as contextInitialized and contextDestroyed. You can check the logs to see where these methods run. Also after defining the custom listener we need to add it to web.xml
.
Your web.xml file only had a simple webapp definition before and now it includes the context listener.
You can try running the app and see where these methods print out the messages we put for now temporarily.
We can’t use a single db connection for real user applications. It would require us to have a proper connection pool which will be done by HikariCP. Details for HikariCP can be found at https://github.com/brettwooldridge/HikariCP. It is also possible to use Tomcat Pool, c3p0, or dbcp2 but especially for production hikari has the best implementation with proper Thread safe methods. Also as I mentioned before, JDBI is the JDBC wrapper we will be using. Add both of these dependencies to your pom file.
Now I want to have a database manager class for just storing the HikariDataSource
and Jdbi
object for database access.
With this manager class, we will start the connection on contextInitialized
and close it with contextDestroyed
, and access to database connection with getJdbi()
method. The connection information will be stored in context xml or you can just set in start method with HikariConfig
object. Finally we can update context
methods to start and stop database connection pool.
As you might notice connection details are retrieved from the context lookup but haven’t done anything about it. First create a folder for the context.xml
just next to WEB-INF
as META-INF
and put the context.xml
in it.
These are specific HikariConfig details which you can update as you want but it should be enough for now to run our application. Also need to define this context in web.xml
. After adding it to web.xml
it should be something like below.
If you run without a proper database connection you will get the error Caused by: java.net.ConnectException: Connection refused (Connection refused)
.
I will run mysql on my local with docker. Also my default database name will be jersey
so make sure you created a schema as create database jersey;
.
docker run -d --name=jersey-mysql -e MYSQL_ROOT_PASSWORD=mypassword -v mysql:/var/lib/mysql mysql
Create a db package under com.blog.api
and have two classes in it as User
and UserDao
. User
is our resource model and make sure you implement empty constructor and getters-setters. Otherwise JDBI will fail to initialize the model while mapping it.
UserDao
is the JDBI interface where you define your database logic. You can read JDBI specific details from http://jdbi.org.
Last thing will be removing the Test resource we had created in previous post and create a UserResource
class in rest package.
I will implement two rest calls for User
as get all users and get a specific user. To make sure you have all the data required put the default models as below in the RestApp
class. It will keep inserting new users as we re-run again but doesn’t really matter. You access the JDBI calls jdbi.onDemand(Dao.class)
and have your method call on it. It will close the connection automatically and will use the pool properly with Hikari.
These should be all we need for a proper representation of user table as a resource. First try a specific user retrieval as /users/{userId}
and it should return a single user object.
http://localhost:8080/users/2
Next you can check all the users with /users/
call and see the list of users.
http://localhost:8080/users/
You can check the project from https://github.com/msdalp/jersey-jdbi-sample. Next I will convert Dao classes to annotation and inject it to resources automatically.