JUno /ˈxu.no/ is an ahead-of-time compiler for running a practical subset of Java for Microcontrollers. It keeps javac as the Java frontend, performs
closed-world linking on the development machine, and emits Assembly.
Traditionally, Java programs require a JVM to run. However, in memory-constrained environments, running Java programs inside a JVM can be difficult. Juno enables developers to create small Java programs for microcontrollers such as Arduino.
Arduino UNO Q
|
Arduino UNO R4 WiFi
|
Arduino UNO R3 WiFi Rev2
|
Arduino UNO R3
|
Arduino Nano ESP32
|
| Accessory | Image | Supported features |
|---|---|---|
| Arduino Nano Connector Carrier | ![]() |
Passive carrier for the Arduino Nano ESP32: microSD card slot on SPI, four Grove sockets, and one Qwiic connector. |
M5Stack Cardputer Adv
|
Requirements: Arduino CLI, JDK 27+, Maven 3.10+.
On macOS, install Arduino CLI with Homebrew and verify that it is on your PATH:
brew update
brew install arduino-cli
arduino-cli versionSee Arduino's installation guide for direct downloads and other options.
sdk env install
./mvnw clean installBlink runs unmodified on every
supported board. Its built-in LED alternates on and off every 500 ms (one full cycle per second).
package io.github.jabrena.juno.api.hardware.gpio;
import io.github.jabrena.juno.hardware.ArduinoUno;
import io.github.jabrena.juno.hardware.gpio.DigitalOutput;
import io.github.jabrena.juno.util.Delay;
public final class Blink {
public static void main(String[] args) {
DigitalOutput led = DigitalOutput.of(ArduinoUno.getGpio().getBuiltinLed());
while (true) {
led.high();
Delay.millis(500);
led.low();
Delay.millis(500);
}
}
}The project provides a Maven plugin to help the user with the common operations. juno:upload generates the sketch, verifies it with arduino-cli, and flashes it in one step.
Blink has no board restriction, so pick a target with -Djuno.board:
./mvnw -f juno-examples/pom.xml compile juno:upload \
-Djuno.main=io.github.jabrena.juno.api.hardware.gpio.Blink \
-Djuno.board=arduino-uno-q
# -Djuno.board=arduino-uno-r4-wifi
# -Djuno.board=arduino-uno-r3-wifi-rev2
# -Djuno.board=arduino-uno-r3
# -Djuno.board=arduino-nano-esp32Select another supported board with -Djuno.board. The plugin auto-detects the port when exactly one matching board is
connected; otherwise, specify it with -Djuno.port=<PORT>.
After uploading the program, you could monitor what happen in the board using the following command:
./mvnw -f juno-examples/pom.xml juno:monitor \
-Djuno.board=arduino-uno-qThe juno Maven plugin provides these goals. The commands below run them from the examples module;
add -Djuno.main=<fully-qualified-class-name> and -Djuno.board=<id> when the entry point has no single-board
@Board declaration.
| Goal | Purpose | Command |
|---|---|---|
juno:boards |
Lists the boards and serial ports detected by Arduino CLI without touching a board. | ./mvnw -f juno-examples/pom.xml juno:boards |
juno:install-deps |
Installs the Arduino core and optional libraries required by the examples. | ./mvnw -f juno-examples/pom.xml juno:install-deps |
juno:compile |
Generates the assembly, C++ runtime shim, and Arduino sketch wrapper. | ./mvnw -f juno-examples/pom.xml compile juno:compile -Djuno.main=io.github.jabrena.juno.api.hardware.gpio.Blink -Djuno.board=arduino-uno-r4-wifi |
juno:verify |
Generates the sketch and compiles it with Arduino CLI without using physical hardware. | ./mvnw -f juno-examples/pom.xml compile juno:verify -Djuno.main=io.github.jabrena.juno.api.hardware.gpio.Blink -Djuno.board=arduino-uno-r4-wifi |
juno:upload |
Generates, verifies, and uploads the sketch to the selected or detected board. | ./mvnw -f juno-examples/pom.xml compile juno:upload -Djuno.main=io.github.jabrena.juno.api.hardware.gpio.Blink -Djuno.board=arduino-uno-r4-wifi |
juno:monitor |
Opens the serial monitor for the selected or detected board. | ./mvnw -f juno-examples/pom.xml juno:monitor -Djuno.board=arduino-uno-r4-wifi |
For example, verify the Grove Temperature and Humidity Sensor Pro monitor for a UNO WiFi Rev2 without uploading it:
./mvnw -f juno-examples/pom.xml compile juno:verify \
-Djuno.main=io.github.jabrena.juno.api.hardware.device.grove.sensors.GroveDht22Monitor \
-Djuno.board=arduino-uno-r3-wifi-rev2Juno is an ahead-of-time compiler, not a JVM. It links a program closed-world from main, validates every reachable
bytecode, and stops with a diagnostic (method, bytecode offset, unsupported operation) rather than emit code whose
behavior it cannot guarantee. Valid Java is therefore not automatically valid Juno input.
| Area | Supported |
|---|---|
| Language core | main() / main(String[]), static and instance methods, all eight primitive types, control flow and switch, fixed-size (also multidimensional) arrays, constant lookup tables kept in flash |
| Objects | classes, inheritance, interfaces, enums, records, lambdas and method references |
| Exceptions | throw, try/catch/finally, multi-catch, propagation between methods, try-with-resources |
| Library | String and StringBuilder, Math, BigInteger/BigDecimal, LocalDateTime (SNTP), UUID, random numbers |
| Concurrency | virtual threads and the JDK 27 preview StructuredTaskScope on one preemptive scheduler (up to four threads including main), monitors, ReentrantLock, atomics, ScopedValue |
| Board services | GPIO, serial, clocks, LED matrix, mouse, Wi-Fi, HTTP/HTTPS, UDP/TCP, SD card, and stacked shields (pin conflicts are rejected at compile time) |
Platform threads (new Thread) and Thread.ofVirtual() builders are rejected. Objects live in one fixed arena
(8 KiB, 1 KiB on AVR), so the AVR boards fit smaller programs. The details are on the
Java subset page, and runnable examples of each feature are under
juno-examples.
This is a multi-module Maven build:
juno-api/— the programming model: the Java-facing hardware API the compiler recognizes as intrinsics (api/) and the@Boardannotations used to select a compilation target (annotations/). This is the only artifact programs compile against.juno-compiler/— the compiler (classfile,bytecode,linker,backend, …), which depends onjuno-api. Builds the executablejuno-compiler/target/juno-compiler-<version>.jar.juno-maven-plugin/— Maven goals for generating a sketch (juno:compile), compiling it with Arduino CLI (juno:verify), uploading it (juno:upload), and opening the serial monitor (juno:monitor).juno-examples/— example Java programs written againstjuno-api, built like any other Maven module so they're checked for compile errors on every build.juno-site/— the Roq/Quarkus static site generator behind the documentation site.docs/is entirely generated from Markdown underjuno-site/src/main/resources/content/— see Documentation site below to regenerate it.juno-third-parties/— integrations maintained outside the core compiler, currently including the independent H8/300 firmware generator for the LEGO RCX, its S-record, and the generated Java representation consumed byjuno-examples.
Juno is an ahead-of-time compiler, not a virtual machine. An Arduino board has no JVM, so nothing is
interpreted at run time: the Java program is compiled with javac as usual, and Juno then translates the
resulting JVM bytecode into native ARM assembly that the Arduino toolchain builds into the sketch's firmware.
The compiler is closed-world: it only sees the classes reachable from main, so it can resolve every call
at build time, drop everything unused, and reject anything outside the supported subset before generating a
single instruction. That is also why there is no dynamic class loading, reflection, or general heap.
Hello.java ──javac──▶ Hello.class ──▶ Juno ──▶ Hello.S + HelloShim.cpp + HelloAsm.ino ──arduino-cli──▶ board
│
classfile → bytecode → linker → lowering → optimize → backend
- Write and compile Java. Programs use the Juno hardware API and optionally select a board with
@Board. Maven runsjavac; Juno consumes the resulting.classfiles. - Link and validate. Juno starts at
main, keeps only reachable code, converts hardware calls into intrinsics, and rejects unsupported bytecode with a precise diagnostic. - Lower and optimize. Reachable methods become Juno IR, where compiler passes simplify the program and report risks such as excessive arena use, recursion, or unsafe array access.
- Generate the sketch. The backend emits native assembly and a small C++ runtime shim. The Maven plugin
packages them with a minimal
.inoundertarget/juno/<Main>Asm/. - Build and run. Arduino CLI compiles the generated sketch for the selected board. Use
juno:verifyto compile it,juno:uploadto flash it, andjuno:monitorto read its serial output.
- https://dev.java/
- https://docs.oracle.com/javase/specs/jls/se25/html/index.html
- https://docs.oracle.com/en/java/javase/27/docs/api/index.html
- https://github.com/openjdk/jcstress/tree/master/jcstress-samples
- https://openjdk.org/
- https://openjdk.org/groups/conformance/JckAccess/
- https://github.com/openjdk
- https://docs.arduino.cc/hardware/uno-q/
- https://docs.arduino.cc/hardware/uno-r4-wifi/
- https://docs.arduino.cc/hardware/uno-wifi-rev2/
- https://docs.arduino.cc/hardware/uno-rev3/
- https://docs.arduino.cc/hardware/nano-esp32/
- https://docs.m5stack.com/en/core/Cardputer-Adv
- https://lejos.sourceforge.io/
- https://lejos.sourceforge.io/ev3/docs/index.html
- https://lejos.sourceforge.io/nxt/nxj/api/index.html
- https://lejos.sourceforge.io/rcx/api/index.html
- https://sourceforge.net/p/lejos/wiki/Sensor%20Framework/
- https://pbrick.info/index.html-p=74.html
- https://tinyvm.sourceforge.net/
- https://sunspotdev.org/
- https://sunspotdev.org/docs/index.html
- https://bearssl.org/














