# Call Java from Node.js

You are a Node.js Moleculer developer. You want to add some Java functionality to your system — a Spring Boot service, a JVM library you can only reach from Java, a CPU-heavy job — and call it from your existing JavaScript code, without replacing your architecture.

You do not rewrite anything. You start a Java node, point it at the same message bus (see Setup), and call its actions exactly like any other Moleculer service. This page is the Node.js developer's view; the reverse direction is Call Node.js from Java.

# 1. See the Java node join the cluster

Once the Java node is up, it appears in the built-in $node introspection service like any other node. From your Node.js code:

// $node.list returns every node in the cluster (local + remote).
const nodes = await broker.call("$node.list");
const java = nodes.find(n => n.id === "java-node");

console.log(java.available);    // true
console.log(java.client.type);  // "java"  — the remote is a moleculer-java node

// $node.services aggregates the services advertised by every node.
const services = await broker.call("$node.services");
const names = services.map(s => s.name);
console.log(names.includes("mathJava")); // true — the Java service is visible

No registration step is needed on your side: discovery is automatic over the transporter.

# 2. Call a Java action

Say the Java side exposes a mathJava service. From Node.js you call mathJava.add and mathJava.greet just like a local action — the framework handles discovery, routing, serialization and deserialization across the language boundary.

    The request body you pass as the second argument becomes ctx.params on the Java side (an io.datatree.Tree), and whatever the Java action returns comes back to you as a plain JavaScript value.

    # 3. Send an event to Java

    Java services can subscribe to your events. Broadcast (or emit) an event from Node.js and a Java listener receives the payload:

      The difference between emit (load-balanced to one listener per group) and broadcast (delivered to every listener) works across languages too — see the Events section of the data-types reference.

      # 4. Errors and timeouts

      If a Java action throws, the failure crosses back as a rejected promise, so a normal try/catch handles it. Add a per-call timeout through the call options:

        You can also pin a call to a specific node with { nodeID: "java-node" } (in Java, CallOptions.nodeID("java-node"), chainable with .timeout(5000)) when more than one node offers the same service.

        # Next

        Every snippet here is trimmed from a runnable, test-verified integration demo where a Node.js node and a Java node prove these calls and events in both directions.