Contents

Java development for Linux on Mac OS

Written by: David Vlijmincx

Introduction

I am working on JUring, and to do that I need a Linux environment. JUring uses some C libraries like IO_uring that are only found on Linux. This works fine on my Linux Desktop, but I also wanted to work on it while I was on the go with a MacBook.

If you want to do something similar you basically have three options:

  • A virtual machine
  • Multipass (Ubuntu VM)
  • Docker

Most of my development I do in either IntelliJ or Visual Studio Code and I want it to feel as if I am working on a Linux machine. So my requirements were as follows:

  • I want it to be power efficient while on the go.
  • Feel as if I am working on a Linux machine
  • Work with my tools and libraries

I decided to go with Dev containers on Docker. I made that decision based on that a VM used too much power, and gives me another machine to maintain. Multipass was also a good candidate, but IntelliJ and VS Code both support dev containers making the experience a bit smoother.

The dev container

For my dev containers I use a Dockerfile because it gives me some more freedom than the standard templates and I don't need a compose file yet. My devcontainer.json file looks as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "name": "JUring",
  "build": {
    "dockerfile": "Dockerfile"
  },
  "mounts": [
    "source=${localEnv:HOME}${localEnv:USERPROFILE}/data,target=/mnt/data,type=bind,consistency=cached"
  ],
  // Configure tool-specific properties.
  "customizations": {
    "jetbrains": {
      "backend": "IntelliJ"
    }
  },
}

There are three things to notice in the json:

  • build: This is the dockerfile that it will use. In my case it is located next to the devcontainer.json file.
  • mounts: I needed access to my local file system, to do that you need to mount them. Using localEnv you can use local environment variables.
  • customizations: This makes it play nice with IntelliJ.

The next thing is the Docker file. This will determine how my development environment actually looks like.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# Base image - Dockerfile.base
FROM arm64v8/ubuntu:25.04

ARG JDK_VERSION=24

# Install prerequisites
RUN apt-get update && apt-get install -y \
    wget \
    git \
    liburing-dev \
    maven \
    && rm -rf /var/lib/apt/lists/*

# Specific Java EA version
RUN wget "https://download.java.net/java/early_access/jdk24/33/GPL/openjdk-24-ea+33_linux-aarch64_bin.tar.gz" -O jdk.tar.gz && \
    mkdir -p /usr/lib/jvm && \
    tar -xzf jdk.tar.gz -C /usr/lib/jvm && \
    rm jdk.tar.gz

ENV JAVA_HOME=/usr/lib/jvm/jdk-${JDK_VERSION} \
    PATH=$JAVA_HOME/bin:$PATH

The MacBook has an M chip inside of it, so I have to use arm64v8/ubuntu to get some better performance. Next you can install and do the same things you would normally do with a Dockerfile. In my case, I need to install liburing-dev and Java. There are easier ways to install Java, but I wanted to use an early access version.

Next thing you need to do is create a Dev container in IntelliJ. You can do this by going to tools -> services -> Dev containers or at the starting screen.

Pros and Cons of Dev containers

Pros:

  • Lightweight native feeling
  • Container for each project
  • Power usage compared to VM's
  • Easy to experiment with versions of libraries.

Cons:

  • Doesn't work flawlessly all the time wth IntelliJ
  • Having to manage multiple Docker files (still better than VM's)
  • A bit more of a learning curve than simply starting a machine.

Conclusion

The best part of this setup is that each project can have its own dev container. The IDE's also gives it a native feeling while I am working on my projects. It doesn't work flawlessly as IntelliJ sometimes does not start the container, but that is rare. Overall I am pleased with this setup.