One really cool thing about using the Spring Boot framework is how easy it is to setup entities for database operations. Hibernate is the ‘persistence layer’ that Spring uses to achieve this and this framework comes with something called ‘HQL‘.

Hibernate uses a powerful query language (HQL) that is similar in appearance to SQL. Compared with SQL, however, HQL is fully object-oriented and understands notions like inheritance, polymorphism and association

With HQL, you can construct queries using your database entities instead of SQL. It certainly feels more declarative than constructing SQL queries. For example, here’s an ER diagram of a personal project (cleaning up some things before I make the repo public).

To fetch all Restaurant records which had critical violations (severity of 3), I constructed the following HQL query.

Another cool thing you can do with Hibernate is creating a virtual column. This virtual column can then be used in any HQL queries you need. derived properties. Here’s an example of my use case (creating a derived property):

Postgresql – I was previously on version 9.0-801.jdbc4 and I switched to the latest to resolve the following error ‘ PSQLException: Method org.postgresql.jdbc4.Jdbc4Connection.isValid(int) is not yet implemented.’

Testing:

Mockito – *.runners.MockitoJUnitRunner is now in *.junit.MockitoJUnitRunner

After my first post, a lot happened. First, the moment I moved my Dockerfile from my $projectDir root into a folder (docker/myapp/Dockerfile to declutter things), “everything” stopped working. A lot of tutorials and even the Transmode gradle docker plugin assume that your Dockerfile is in a standard location ($projectDir/Dockerfile) and if you step outside that, you’ll learn an awful lot about Docker build contexts and working directories.

To set some context, my application is a Spring Boot Java application (version 1.5.12-RELEASE). This became pertinent for me as a lot of the official Spring guides have defaulted to 2.x.x versions which have significant differences (notably the use of bootRepackage going away in favor of bootJar or bootWar).

So. I took a step back and yanked out the Transmode gradle plugin from my repository & embarked on learning how to do it all manually. A lot of the tasks listed below are very nicely handled by docker-compose but I figured that I needed to know the essentials first in order to troubleshoot when things go sideways. Here are the manual tasks:

For the postgres image, I did not need to build one from scratch since there is an official image published on Dockerhub). You can read more about configuring the official image according to your needs.

manually tagging and pushing both images to a remote registry (I practiced with both Dockerhub and the Heroku registry),

manually setting up the network (this is a nice-to-have since apps in the same network are implicitly able to communicate with each other. Of course, the server needs to talk to the database so this was the first step)

manually running the postgres application (since the database needs to be up before the server)

manually running the server application

Once I verified that I could repeatedly perform steps 1 – 5, I decided to investigate the Palantir Gradle Docker plugin since I’d like to eventually get away from the lengthy Docker commands and move to gradle tasks for the entire process. The Palantir plugin is more robust than the Transmode plugin and in my opinion, it’s a little clearer to understand what is happening.

For the rest of this post, my focus will be on the image generation step and I’ll share my commands from the perspective of one whose Dockerfile is not in the typical location i.e. $projectDir/Dockerfile. Instead, my Dockerfile is located at $projectDir/docker/myapp/Dockerfile. I’ll outline the manual steps and the corresponding gradle task configuration (using the Palantir Gradle Docker plugin).

Building your Docker image for a 1.5.x Spring boot app

The basics of the Dockerfile (what is it, etc) are on the Docker docs. The biggest issue I ran into was getting the COPY task to work the same whether the step was manual or via the gradle task. The recommendation I can share is to use a placeholder argument for the location of the jar file to be copied. When manually generating your image, you will then pass in the value of the ARG. Here’s the full command which was run at the root of my project. Compare with the Spring guide configuration:

The -t flag sets the friendly name of the image you intend to build. -f sets the location of the Dockerfile and the last argument is a dot (this is important to set the working directory for Docker. Update this accordingly). Here's what my Dockerfile looks like.

In the official Spring guide to dockerizing your Spring app, you can also see how the ARG is declared and referenced in the COPY task later. Note: the official Spring guide is written with the Palantir Gradle Docker plugin and Spring 2.x.x in mind. So, I had to do things a little differently mainly:

When setting up the Palantir Gradle Docker plugin, you need to specify the maven url (it's not in mavenCentral) so that bit me. I also opted to use the 'traditional' way of applying the plugin since the newer and more expressive way seems to have some kinks. As an aside, I've created a PR to include this bit of information to the guide.

The gradle configuration in the guide could do with a bit more explanation i.e. the why. Nevertheless, with a lot of trial/error and reading various docs (Spring, Docker, Stackoverflow, etc), I was able to come up with a configuration that works for my Spring Boot application. Here are my settings

What the docker task depends on. In my case, I depend on the bootRepackage task since within my file config setting, I'm fetching the generated jar file from my $libsDir to be copied into the Docker build context along with the Dockerfile from its original location.

Another difference is the use of bootJar task which, for those of us still on 1.5.x, is absent.

In the Palantir readme, you'll observe how the output of a task is fetched like so

files tasks.distTar.outputs, 'file1.txt', 'file2.txt'

. You may be tempted to do something like tasks.jar.outputs but your Spring application won't be packaged correctly although image generation will succeed (running a jar generated this way will result in an error message about the missing main class). My solution was to depend on the bootRepackage task in order to retrieve the full jar file from the expected location.

I've attempted to comment the code in my docker task configuration but I welcome improvements for clarity/correction. A lot of the information I've gleaned is largely from trial/error. Finally, to run the gradle tasks, here's a verbose command I use which comes in handy when troubleshooting gradle tasks failures. gradlew clean docker --console=plain --stacktrace

Running your Docker app

Okay, we've got the image generation out of the way. It is important to validate that you can run the application before calling it a day. For my purposes, I need to validate that my image was generated correctly and that I could run it with all the needed environment variables (which includes api keys, secrets, and the like). To avoid leaking my secrets, I created a .env file in a location outside of my repository. I was able to run & validate my app two ways: manually and via docker-compose. Note: the Palantir plugin also has a way to programmatically setup your docker-compose file but that's a work in progress.

If all is right with your image, you should see the normal Spring startup messages. If you run into issues like the missing main class, verify you didn't fat-finger the commands like someone I know (mainly when using CMD in the Dockerfile, each argument has to be its own entry to the array) and verify your jar is a valid jar. You should be able to run your jar like any normal java app e.g. java -jar -Dfoo=bar myapp.jar.

At work, we make heavy use of Docker containers for local development and I figured I should apply those learnings into my personal projects. I will say that this would be slightly harder if I didn’t have a reference project (i.e. work project setup) to reference.

My project is a Spring Boot Java application and requires a Postgresql database. Here’s how I built it up piece by piece:

I started out learning to ‘dockerize’ the Java web service which is pretty straightforward (my sample Dockerfile which has links to sites that I referenced). With your Dockerfile, you can generate the image using the standard docker commands (docker build -t org/yourapp:latest .). However, I wanted to get more comfortable with gradle so I used the Transmode gradle plugin. This allows me to generate my image using a simple gradle task (my sample gradlew $dockerImageBuildTaskName).

Once I was able to individually build each image, I saw the need for ‘orchestrating’ the setup of the server + db which led me to docker-compose (my sample docker-compose file). Using this configuration-based approach takes the headache out of I’m also making use of env files since my application takes in api secrets and the like (aside, do NOT commit items like these to git. I have these env files located outside of my application folder and I use relative paths to access them)

Dockerhub allows you to create a free repository to hold images and pushing your image is a straightforward two-step process: docker tag local-image:tagname reponame:tagname and docker push reponame:tagname. You can create your docker-compose file in a way that your image gets built every time you do ‘docker-compose up’ but I opted to separate out the build process from the startup.

Overall, I’m pretty pleased with my progress so far. I’m certain I haven’t followed all the best practices regarding Docker container configurations but that’s on my Trello to-do list!

Source code showing a signed POST request: https://s3.amazonaws.com/aws-java-sdk/samples/AWSS3SigV4JavaSamples.jar. ‘Unzip’ this jar file if you have 7-zip. Otherwise, use the “jar xvf $file.jar” command

The classes in the ‘auth’ & ‘util’ folders contain the classes of interest so copy them over to your project.

A ‘runnable’ class you can inspect is PutS3ObjectSample.java which shows how it’s all put together.

If you’re collecting any sort of user sign up information, Google requires your form to be behind an SSL backed site. I’ve been getting warning emails from Google due to some relatively ancient personal projects I’ve done and I decided to bite the bullet and go through the process. So far, I’ve gone as far as simply ordering the free SSL cert via Dreamhost. Once I’ve properly setup my domains, the next step would be using .htacess to get all pages to load with https. *crossing fingers*

In my next post, I’d like to muse about passion projects and when to put things to pasture. 🙂