Skip to content

Developer Setup & Getting Started Guide

⚠️ Outdated — this page predates 0.3.0 and several of its commands and APIs are wrong. Use Quickstart instead, where every command has been executed against the current main.

Known errors on this page: the archetype version below is 1.0.0-SNAPSHOT but the project is at 0.3.0; java -jar …-server.jar cannot work because no shade or assembly plugin is configured; the UI imports are com.zeroz4j.ui.components.* but the real packages are com.zeroz4j.ui.component and com.zeroz4j.ui.layout; and Button has no onClick method — it is addClickListener.

The easiest way to scaffold a new zeroz4j project is to use the provided Maven Archetype. This will automatically generate a complete, multi-module project (client, shared, server) with all TeaVM, annotation processors, and Helidon dependencies correctly configured.

1. Generate the Project

Run the following Maven command to scaffold your project:

mvn archetype:generate \
  -DarchetypeGroupId=com.zeroz4j \
  -DarchetypeArtifactId=zerozstack-archetype \
  -DarchetypeVersion=1.0.0-SNAPSHOT \
  -DgroupId=com.mycompany \
  -DartifactId=myapp \
  -Dversion=1.0.0-SNAPSHOT

2. Project Structure

The generated project will contain: * myapp-shared: Contains your API interfaces and Domain Models. * myapp-client: Contains the Java UI code that compiles to WebAssembly. * myapp-server: Contains the Helidon-based backend that persists your data.

3. Build and Run

To build the entire project (including compiling the WASM client):

cd myapp
mvn clean install

To run the server:

java -jar myapp-server/target/myapp-server-1.0.0-SNAPSHOT.jar

Navigate to http://localhost:8080 to see your running ZeroZ Stack application!

4. Code Example

With ZeroZ Stack, you avoid boilerplate HTTP mapping, JSON translation, and ORM schemas. Here is how simple it is to build a full-stack feature.

1. The Domain Model (Shared)

Define your data structure. It automatically becomes serializable and persistable.

import com.zeroz4j.api.DataModel;

@DataModel
public class ChatMessage {
    private String author;
    private String text;

    public ChatMessage() {}

    public ChatMessage(String author, String text) {
        this.author = author;
        this.text = text;
    }
    // getters and setters...
}

2. The API (Shared)

Define the RPC interface.

import com.zeroz4j.api.RmiService;

@RmiService
public interface ChatService {
    void sendMessage(ChatMessage msg);
}

3. The Server Backend

Implement the service. The method receives the exact object sent from the client.

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import com.zeroz4j.db.net.ZeroZDbNode;

@ApplicationScoped
public class ChatServiceImpl implements ChatService {
    @Inject
    private ZeroZDbNode db;

    @Override
    public void sendMessage(ChatMessage msg) {
        // Automatically persist or broadcast!
        System.out.println("Received: " + msg.getText());

        // Example: save to your data root graph, atomically
        // db.localDb().write(ctx -> { ctx.edit(root.getMessages()); root.getMessages().add(msg); });
        // root.getMessages().add(msg);
        // storage.store(root.getMessages());
    }
}

4. The Client UI (Wasm)

Invoke the backend directly from a UI button click event. The UI never touches JSON or REST.

import com.zeroz4j.ui.components.Button;
import com.zeroz4j.ui.components.Div;

public class ChatView extends Div {
    public ChatView(ChatService chatService) {
        Button sendBtn = new Button("Send Hello");
        sendBtn.onClick(event -> {
            // Suspends cooperatively, calls backend over binary WebSocket
            chatService.sendMessage(new ChatMessage("Alice", "Hello World!"));
        });

        add(sendBtn);
    }
}