Expand description
§inline java
Embed Java directly in Rust — evaluated at program runtime (java!, java_fn!) or at
compile time (ct_java!).
§Prerequisites
Java 8+ with javac and java on PATH.
§Quick start
# Cargo.toml
[dependencies]
inline_java = "0.1.0"§java! — runtime, no parameters
Compiles and runs Java each time the surrounding Rust code executes. Expands
to Result<T, inline_java::JavaError>.
use inline_java::java;
// No type annotation needed — the macro infers `i32` from `static int run()`
let x = java! {
static int run() {
return 42;
}
}.unwrap();§java_fn! — runtime, with parameters
Like java!, but run(...) may declare parameters. Expands to a Rust
function value fn(P1, P2, …) -> Result<T, JavaError>. Parameters are
serialised by Rust and piped to the Java process over stdin.
use inline_java::java_fn;
// Single parameter — return type inferred from `static int run()`
let doubled = java_fn! {
static int run(int n) {
return n * 2;
}
}(21).unwrap();
// Multiple parameters
let msg: String = java_fn! {
static String run(String greeting, String target) {
return greeting + ", " + target + "!";
}
}("Hello", "World").unwrap();
// Optional parameter
let result: Option<i32> = java_fn! {
import java.util.Optional;
static Optional<Integer> run(Optional<Integer> val) {
return val.map(x -> x * 2);
}
}(Some(21)).unwrap();§ct_java! — compile time
Runs Java during rustc macro expansion and splices the result as a Rust
literal at the call site. No parameters are allowed (values must be
compile-time constants).
use inline_java::ct_java;
const PI: f64 = ct_java! {
static double run() {
return Math.PI;
}
};
// Arrays work too — result is a Rust array literal baked into the binary
const PRIMES: [i32; 5] = ct_java! {
static int[] run() {
return new int[]{2, 3, 5, 7, 11};
}
};§Supported parameter types (java_fn!)
Declare parameters in the Java run(...) signature; Rust receives them with
the mapped types below.
| Java parameter type | Rust parameter type |
|---|---|
byte | i8 |
short | i16 |
int | i32 |
long | i64 |
float | f32 |
double | f64 |
boolean | bool |
char | char |
String | &str |
T[] / List<BoxedT> | &[T] |
Optional<BoxedT> | Option<T> |
§Supported return types
| Java return type | Rust return type |
|---|---|
byte | i8 |
short | i16 |
int | i32 |
long | i64 |
float | f32 |
double | f64 |
boolean | bool |
char | char |
String | String |
T[] / List<BoxedT> | Vec<T> |
Optional<BoxedT> | Option<T> |
Types can be nested arbitrarily: Optional<List<Integer>> → Option<Vec<i32>>,
List<String[]> → Vec<Vec<String>>, etc.
§Options
The following optional key = "value" pairs may appear before the Java body, separated by
commas:
javac = "<args>"— extra arguments forjavac(shell-quoted).java = "<args>"— extra arguments forjava(shell-quoted).
use inline_java::java;
let result: String = java! {
javac = "-cp ./my.jar",
java = "-cp ./my.jar",
import com.example.MyClass;
static String run() {
return new MyClass().greet();
}
}.unwrap();§Cache directory
Compiled .class files are cached so that unchanged Java code is not
recompiled on every run. The cache root is resolved in this order:
| Priority | Location |
|---|---|
| 1 | INLINE_JAVA_CACHE_DIR environment variable (if set and non-empty) |
| 2 | Platform cache directory — ~/.cache/inline_java on Linux, ~/Library/Caches/inline_java on macOS, %LOCALAPPDATA%\inline_java on Windows |
| 3 | <system temp>/inline_java (fallback if the platform cache dir is unavailable) |
Each compiled class gets its own subdirectory named
<ClassName>_<hash>/, where the hash covers the Java source, the
expanded javac flags, the current working directory, and the raw java
flags. This means changing any of those inputs automatically triggers a
fresh compilation.
§Using project Java source files
Use import or package directives together with javac = "-sourcepath <path>"
(or -classpath) to call into your own Java code:
use inline_java::java;
// import style
let s: String = java! {
javac = "-sourcepath .",
import com.example.demo.*;
static String run() {
return new HelloWorld().greet();
}
}.unwrap();
// package style — the generated class becomes part of the named package
let s: String = java! {
javac = "-sourcepath .",
package com.example.demo;
static String run() {
return new HelloWorld().greet();
}
}.unwrap();§Refactoring use case
inline_java is particularly well-suited for incremental Java → Rust
migrations. The typical workflow is:
- Keep the original Java logic intact.
- Write the replacement in Rust.
- Use
java_fn!to call the original Java with the same inputs and assert that both implementations produce identical outputs.
use inline_java::java_fn;
fn my_rust_impl(n: i32) -> i32 {
// … new Rust code …
n * 2
}
fn parity_with_java() {
let java_impl = java_fn! {
static int run(int n) {
// original Java logic, verbatim
return n * 2;
}
};
for n in [0, 1, -1, 42, i32::MAX / 2] {
let expected = java_impl(n).unwrap();
assert_eq!(my_rust_impl(n), expected, "diverged for n={n}");
}
}
parity_with_java();§Crate layout
| Crate | Purpose |
|---|---|
inline_java | Public API — re-exports macros and core types |
inline_java_macros | Proc-macro implementation (java!, java_fn!, ct_java!) |
inline_java_core | Runtime helpers (run_java, JavaError) |
inline_java_demo | Demo binary |
Macros§
- ct_java
- Re-export the proc macros so users only need to depend on this crate. Run Java at compile time and splice its return value as a Rust literal.
- java
- Re-export the proc macros so users only need to depend on this crate. Compile and run zero-argument Java code at program runtime.
- java_fn
- Re-export the proc macros so users only need to depend on this crate. Return a typed Rust function that compiles and runs Java at program runtime.
Enums§
- Java
Error - Re-export the core error type and runtime helpers.
All errors that
java!andjava_fn!can return at runtime (and thatct_java!maps tocompile_error!diagnostics at build time).
Functions§
- expand_
java_ args - Re-export the core error type and runtime helpers.
Shell-expand
raw(expanding env vars and~), then split into individual arguments (respecting quotes). Returns an empty vec ifrawis empty. - run_
java - Re-export the core error type and runtime helpers. Compile (if needed) and run a generated Java class, returning raw stdout bytes.