Skip to content

18 · Modules

Java with extern

Java 8 and later, live objects and Maven libraries through the JVM provider.

On this page

Import java from the jvm plugin. Function signatures use Zolo types, while the bodies use Java. Call the functions directly, with the same syntax as other Zolo functions. These examples run with the CLI and an installed JVM plugin; the browser Playground cannot host a JVM.

Use a leading Java import, return an exact integer and await a CompletableFuture.

39-extern-java.zolo
use plugin jvm::{java}

extern java fn upper(value: str) -> str {
    import java.util.Locale;
    return value.toUpperCase(Locale.ROOT);
}

extern java fn exact(value: int) -> int {
    return value;
}

extern java async fn later(value: int) -> int {
    import java.util.concurrent.CompletableFuture;
    return CompletableFuture.supplyAsync(() -> value + 1L);
}

print(upper("hello Java"))
print(exact(9007199254740993))
print(await later(41))

Requires the Zolo CLI/host — open in the playground or run locally.

HELLO JAVA
9007199254740993
42

int and i64 map to Java long, preserving signed 64-bit integers, including values above 2^53. i32 maps to Java int; narrower primitives keep their native types. Use 1L for a Java long literal. Overloads follow the declared types, and conversions that overflow or lose precision report an error.

extern java async fn adapts a Java CompletionStage<T> to a Zolo Future. Await it normally. Java functional interfaces can receive Zolo callbacks; callbacks from Java threads return to the owning Zolo runtime. Cancelling a Future requests cancellation, but Java work that ignores interruption can continue running.

Files, JARs and objects

Import the public Person class from a Java file through a provider alias. Construct it with .new, call methods, update a field and pass the same live instance to a separate inline function.

40-extern-java-objects.zolo
use plugin jvm::{java as j}

extern j from "./java_fixtures/Person.java" use {Person}

extern j fn same(person: Person) -> Person { return person; }

let person = Person.new(name: "João", age: 30)
print(person.getName())
print(person.getAge())
person.age = 31
print(person.age)
print(Person.twice(21))
print(person == same(person))

Requires the Zolo CLI/host — open in the playground or run locally.

João
30
31
42
true

Paths follow the importing Zolo file. The companion java_fixtures/Person.java exposes public constructors and methods, plus a writable public age field. Objects keep their native identity and state; passing an object between these bindings does not copy its fields.

A local JAR uses the same import form: extern java from "./Person.jar" use {Person}. With a JAR exposing the same public API, let person = Person.new("João", 30) followed by print(person.getName()) prints João. Use positional arguments for JAR bindings when parameter names are unavailable. Source imports expose parameter names for named calls. JARs containing the MethodParameters attribute, normally produced by javac -parameters, also retain those names: the same class accepts Person.new(name: "João", age: 30).

Use public Java APIs across independently compiled modules. Package-private access requires sources compiled together. For varargs, open generics or an unsupported native shape, expose a small Java wrapper with a concrete signature. Static fields also need a wrapper in this version.

Maven libraries

Declare each dependency once at file scope. Java functions keep their normal imports, and Maven resolves the transitive JAR graph before compilation.

Pin Guava with its Maven group:artifact coordinate and use Joiner from Java.

41-extern-java-maven.zolo
// Prepare with `zolo install` or opt into `zolo run ... --install=auto`.
use plugin jvm::{java}

extern java deps {
    "com.google.guava:guava" = "33.4.0-jre"
}

extern java fn join(values: [str]) -> str {
    import com.google.common.base.Joiner;
    return Joiner.on(", ").join(values);
}

print(join(["Java", "Maven", "Zolo"]))

Requires the Zolo CLI/host — open in the playground or run locally.

Java, Maven, Zolo

For a standalone script named analysis.zolo, allow preparation on the first run with zolo run analysis.zolo --install=auto. To install explicitly:

zolo install analysis.zolo
zolo run analysis.zolo --install=manual
zolo run analysis.zolo --offline --frozen

Standalone scripts default to auto; projects default to manual. The script lock is analysis.zolo.lock. --offline uses local caches only, while --frozen requires a matching lock and prevents changes to it. Opening a file in the editor does not download dependencies or execute authored Java code.

For a project, move the dependency declaration to zolo.toml and keep the Java function and its import in main.zolo:

[package]
name = "java-demo"
version = "0.1.0"

[packages]
schema = 2

[foreign]
install = "manual"

[foreign.jvm.dependencies]
"com.google.guava:guava" = "33.4.0-jre"

Run zolo install main.zolo, then zolo run main.zolo --offline --frozen. The project uses zolo.lock. Identical source and manifest declarations merge; conflicting requirements report their origins. Direct Maven declarations accept exact versions or native version intervals. Direct BOM, classifier, scope and exclusion fields are not exposed yet.

Choose Java and deploy

Source compilation and semantic editor features require a JDK 8 or later. Set ZOLO_JAVA_HOME before the first Java call; JAVA_HOME is a fallback. The JVM architecture must match Zolo. Java runtimes are installed separately. Authored source targets Java 8 by default, even with a newer JDK. Set ZOLO_JAVA_RELEASE, for example to 17, to use a newer language/API target; the selected compiler must support that target.

VM, native and LLVM execute the same provider. Compiled artifacts retain class files, dependency JARs, resources and source maps. Dynamic, embedded and static plugin packaging can run without the original sources or a Java compiler. Deployment still needs a JRE compatible with the selected target and every dependency; packaging the plugin does not bundle Java. Libraries using native binaries retain their platform requirements. Hosted JVM execution is unavailable on wasm-aot.

Java exceptions work with ordinary try/catch and point to authored source. For libraries that use an existing common pool or another executor, propagate the session context class loader or pass it explicitly to resource/service lookups. See the JVM plugin guide for these integration details. Acceptance currently covers Windows x64 with JDK 8, 11 and 23, plus compiler-free JRE 8 deployment; Linux and macOS still need runtime validation.

Global index

Find your way through Zolo

Try an idea

Start here

9 results

9 results

enpt-br