How to Install Java OpenJDK 14 on macOS Catalina

In this article, I will demonstrate how to install Java OpenJDK 14 on macOS Catalina in 2020.

Download and Install OpenJDK 14

Download the .tar.gz version of OpenJDK 14 from

sudo mv openjdk-14.0.1_osx-x64_bin.tar.gz /Library/Java/JavaVirtualMachines/
cd /Library/Java/JavaVirtualMachines/
sudo tar -xzf openjdk-14.0.1_osx-x64_bin.tar.gz
sudo rm openjdk-14.0.1_osx-x64_bin.tar.gz

Next, execute the following command to find out where JDK 14 is located:

$ /usr/libexec/java_home -v14

and append the resulting path as an export into your .bash_profile:

echo -n "\nexport JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-14.0.1.jdk/Contents/Home" >> ~/.bash_profile

and make sure to apply the changes:

source ~/.bash_profile

Test Java

You should now be able to run java:

java -version

Depending on your security settings, the following warning needs to be accepted by clicking “Open”:

You should then see an output similar to the following:

openjdk version "14.0.1" 2020-04-14
OpenJDK Runtime Environment (build 14.0.1+7)
OpenJDK 64-Bit Server VM (build 14.0.1+7, mixed mode, sharing)

Congratulations! You have installed OpenJDK 14.

One more thing:

I’m currently working on a cool side project named – it allows you to monitor the execution of regular background tasks such as backups and notifies you when they are not executed on time. Please check it out and use the invitation code BLOG20 to create an account for free:

Pitfalls when Integrating Spring Sessions with Spring Security

Spring Sessions allows you to persist user sessions into a database. Combined with Spring Security, it is easy to create a setup where each logged in user is represented by a row in a SPRING_SESSION table. Externalising sessions into a database is also a prerequisite for a zero-downtime deployment strategy where users can stay logged in while a new application version is deployed.

On paper, the integration of those two Spring components is very easy. Assuming you have a working Spring Security setup, just add this dependency:


and add this line to your

and you should be good to go!

Value too long for column PRINCIPAL_NAME

In my case, the setup was unfortunately not working out of the box. After login, I noticed the following exception:

org.h2.jdbc.JdbcSQLDataException: Value too long for column """PRINCIPAL_NAME"" VARCHAR(100)": "STRINGDECODE('Customer{id=123, email='''', firstName=''Jane'', lastName=''Doe'', company='... (179)"; SQL statement:

As stated in the exception, the data format of one of the newly created database tables did not expect a PRINCIPAL_NAME to exceed 100 characters. The principal in Spring Security is your user object (e.g., a class named “User” or something similar that is used in the login process). Therefore, this error means that there is some problem when Spring Security tries to create the user session in the database.

Continue reading

Environment-Dependent Code Execution with Spring Boot and Docker

Different deployment environments (e.g., development, testing, staging and production) often require that different pieces of code are switched on and off. For example, you only want to send real emails in production and write to an email log in all other environments instead. Or your code to initialise the database should only run in the staging environment.

A simple but hard to maintain way for such conditional code executions is to define a globally available variable such as isProductionSystem and write code such as this:

if (isProductionSystem) {
} else {

This is hard to maintain because you end up with large if statements if you have multiple environments. Also, the only way you can adapt in your environment is to change the isProductionSystem variable, which means you either have all of the “production-only” features or none of them.

The @ConditionalOnProperty Annotation

Spring offers a much better way to handle conditional code execution. You can annotate the beans that should only execute depending on an environment flag with the ConditionalOnProperty annotation:

@ConditionalOnProperty(value = "emails.enabled")
public EmailJob emailJob() {
    return new EmailJob();

In the above example, the email job is only started when the property-value emails.enabled is set to true.

Profile-dependent execution

The code execution can also be dependent on the application profile:

public emailJob emailJob() {
    return new EmailJob();

As already mentioned, this removes some level of flexibility because you can no longer decide to activate or deactivate individual features at configuration time on the respective environment.

Overriding Configuration Flags in Docker

When using Docker, you can override the default values for the properties by using environment variables with the -e flag of the docker run command:

docker run -it -e SPRING_JPA_DATABASE_PLATFORM=org.hibernate.dialect.PostgreSQLDialect myimage:latest

Spring translates environment variables into the dot-syntax for property-names by substituting dots with underscores and capitalising everything. If you want to override the value of, you need to set the environment variable MY_PROPERTY.

In the above example, you can control whether to actually send emails with the following command:

docker -it -e EMAILS_ENABLED=1 myapp:latest

Conditional Execution on Application Startup

There is another interesting use case for an overridable configuration switch: code that is executed on application startup. For example, a method that creates test instances in an empty database in the staging system but is skipped in production.

This is more verbose but is still readable. Simply extract the configuration value with the @Value annotation (with the default false) into a private variable and check it in a method annotated with the @EventListener annotation listening to the ApplicationReadyEvent:

public class PostStartService {

    private boolean initEmptyDb;

    public void createTestData() {
        if (!initEmptyDb) {

        // execute your code here

In the above code snippet, you can control whether the body of createTestData is executed via setting the following environment variable in Docker:

docker -it -e INIT_EMPTY_DB=1 myapp:latest


In this article, I presented several techniques to run code depending on the deployment environment. Let me know how what works best for you or if you have different ways of achieving the correct environment configuration.

Thymeleaf: Output Size of List

Question: In my Thymeleaf template, I want to output the size of a list of objects. For example, for the list

List<String> list = Arrays.asList("Go", "Python", "Scala");

the result should be 3. How is this possible using just Thymeleaf syntax?

You can use the following expression:

<span th:text="${#lists.size(myList)}">[Number of Elements]</span>

And just in case you want to check if the list is empty, there is also an easy method for that:

<span th:if="${#lists.isEmpty(myList)}">This list is empty</span>

Send JSON objects via POST to Spring Boot Controllers

Creating and persisting business objects using Spring Boot is amazingly easy. Assume you create an API for simple CRUD methods and want to create an entity based on data entered by your frontend users. In the old times, you would probably populate several POST fields in a key-value style and create your business object manually from those fields.

Spring Boot offers an easier solution. As long as your internal data model equals the frontend’s data model, you can use the @Valid On @RequestBody Controller Method Arguments to automatically create the object from a JSON-serialized request and execute the necessary validation logic.

Continue reading

Creating a VirtualBox-Based Spring Boot Development Environment

In this article, I’ll show how to set up a simple development environment for working with Spring Boot inside a VirtualBox Ubuntu Server. You will learn how to

  • configure port forwarding for interacting with the development server
  • set up shared folders for using an IDE on your client to edit code on the server
  • build and execute the application using maven

Let’s get started!


You need:

Continue reading