> ## Documentation Index
> Fetch the complete documentation index at: https://repost.sh/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Java Quickstart

> Install the Repost Maven plugin and BOM, generate a type-safe Java client from your schema, and publish your first event with idempotency and stable delivery outcomes.

export const RepostHighlight = () => {
  useEffect(() => {
    const colors = {
      comment: ['#116329', '#6A9955'],
      constant: ['#0550AE', '#9CDCFE'],
      keyword: ['#CF222E', '#569CD6'],
      name: ['#953800', '#4EC9B0'],
      string: ['#0A3069', '#CE9178'],
      type: ['#0550AE', '#4EC9B0'],
      variable: ['#1F2328', '#9CDCFE']
    };
    const tokenPattern = /"[^"\n]*"|@[A-Za-z_]\w*|\b(?:String|Int|Float|Boolean|DateTime|Json)\b|\b(?:true|false)\b|\b\d+(?:\.\d+)?\b|\b(?:now|uuid|cuid)(?=\s*\()|\b[A-Z]\w*\b|\b[A-Za-z_]\w*\b/g;
    const append = (line, text, color) => {
      if (!text) return;
      if (!color) {
        line.append(text);
        return;
      }
      const span = document.createElement('span');
      span.textContent = text;
      span.style.color = color[0];
      span.style.setProperty('--shiki-dark', color[1]);
      line.append(span);
    };
    const commentStart = text => {
      let quoted = false;
      for (let index = 0; index < text.length - 1; index += 1) {
        if (text[index] === '"' && text[index - 1] !== '\\') quoted = !quoted;
        if (!quoted && text[index] === '/' && text[index + 1] === '/') return index;
      }
      return -1;
    };
    const highlightCode = code => {
      if (code.dataset.repostHighlighted !== undefined || code.querySelector('span[style*="--shiki-dark"]')) {
        return;
      }
      code.dataset.repostHighlighted = '';
      const source = code.textContent ?? '';
      const fragment = document.createDocumentFragment();
      for (const text of source.split('\n')) {
        const line = document.createElement('span');
        line.className = 'line';
        const declaration = text.match(/^(\s*)(generator|model|enum|type|event)(\s+)([A-Za-z_]\w*)(.*)$/);
        if (declaration) {
          append(line, declaration[1]);
          append(line, declaration[2], colors.keyword);
          append(line, declaration[3]);
          append(line, declaration[4], colors.name);
          append(line, declaration[5]);
        } else {
          const start = commentStart(text);
          const codeText = start === -1 ? text : text.slice(0, start);
          const leading = codeText.match(/^(\s*)([A-Za-z_]\w*)(?=\s+(?:@|[A-Z]))/);
          const bare = codeText.match(/^(\s*)([A-Za-z_]\w*)(\s*)$/);
          let offset = 0;
          for (const match of codeText.matchAll(tokenPattern)) {
            append(line, codeText.slice(offset, match.index));
            const token = match[0];
            let color = colors.constant;
            if (token.startsWith('"')) color = colors.string; else if (token.startsWith('@') || (/^(now|uuid|cuid)$/).test(token)) color = colors.name; else if ((/^(String|Int|Float|Boolean|DateTime|Json)$/).test(token)) color = colors.type; else if (leading && match.index === leading[1].length) color = colors.variable; else if (bare && match.index === bare[1].length) color = colors.constant; else if ((/^[A-Z]/).test(token)) color = colors.name; else if ((/^[A-Za-z_]/).test(token)) color = colors.variable;
            append(line, token, color);
            offset = match.index + token.length;
          }
          append(line, codeText.slice(offset));
          if (start !== -1) append(line, text.slice(start), colors.comment);
        }
        fragment.append(line, '\n');
      }
      code.replaceChildren(fragment);
    };
    const highlightRepostBlocks = () => {
      for (const block of document.querySelectorAll('.code-block')) {
        const code = block.querySelector('pre code');
        const filename = block.querySelector('[data-component-part="code-block-header-filename"] [title$=".repost"]');
        const looksLikeRepost = (/^\s*(generator|model|enum|type|event)\s+[A-Za-z_]\w*\s*\{/m).test(code?.textContent ?? '');
        if (code && (filename || looksLikeRepost)) highlightCode(code);
      }
    };
    let frame;
    const schedule = () => {
      if (frame !== undefined) return;
      frame = requestAnimationFrame(() => {
        frame = undefined;
        highlightRepostBlocks();
      });
    };
    const observer = new MutationObserver(schedule);
    observer.observe(document.documentElement, {
      childList: true,
      subtree: true
    });
    schedule();
    return () => {
      observer.disconnect();
      if (frame !== undefined) cancelAnimationFrame(frame);
    };
  }, []);
  return null;
};

<RepostHighlight />

The Repost build plugin turns your `.repost` schema into a typed Java client: immutable models, a `webhooks.<catalog>.<member>()` method tree, synchronous and `CompletionStage` sends, and a shared runtime that handles retries, idempotency, and delivery reconciliation. The same schema and wire format back the [TypeScript](/docs/cli/schema), Go, Python, and [Kotlin](/docs/send/kotlin/quickstart) SDKs, pinned by a cross-language conformance suite.

The runtime is published to Maven Central under the `sh.repost` group and is **server-side only** — it holds a publish credential and must not ship in an Android app or any untrusted client.

<Note>
  The published runtime is version `1.0.18` and the schema engine is `0.9.0`. Every coordinate on this page resolves from Maven Central. Kotlin projects should follow the [Kotlin quickstart](/docs/send/kotlin/quickstart) instead.
</Note>

<Steps>
  <Step title="Install the plugin and BOM">
    Import the `repost-bom` to keep every Repost artifact on one version, depend on `repost-client`, and add the `repost-maven-plugin` to generate on every build. A complete working project lives in the repo under `examples/java`.

    ```xml pom.xml theme={"languages":{"custom":["/languages/repost.json"]}}
    <properties>
      <maven.compiler.release>11</maven.compiler.release>
      <repost.version>1.0.18</repost.version>
    </properties>

    <dependencyManagement>
      <dependencies>
        <dependency>
          <groupId>sh.repost</groupId>
          <artifactId>repost-bom</artifactId>
          <version>${repost.version}</version>
          <type>pom</type>
          <scope>import</scope>
        </dependency>
      </dependencies>
    </dependencyManagement>

    <dependencies>
      <dependency>
        <groupId>sh.repost</groupId>
        <artifactId>repost-client</artifactId>
      </dependency>
    </dependencies>

    <build>
      <plugins>
        <plugin>
          <groupId>sh.repost</groupId>
          <artifactId>repost-maven-plugin</artifactId>
          <version>${repost.version}</version>
          <configuration>
            <generators><generator>javaSdk</generator></generators>
          </configuration>
          <executions>
            <execution>
              <goals><goal>generate</goal></goals>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>
    ```

    The plugin resolves and runs a signed, platform-specific schema engine (`sh.repost:repost-schema-engine:0.9.0`) — nothing else to install. It adds no transitive HTTP, JSON, or logging libraries to your classpath — the transport is a source-verified, relocated Apache HttpClient baseline inside `repost-client`, so it cannot collide with your own Jackson, SLF4J, or OkHttp versions.
  </Step>

  <Step title="Define the schema">
    `repost schema init --language java --output ./src/main/java` scaffolds a `repost/` directory. Declare your events and a Java `generator` block:

    ```repost repost/schema.repost theme={"languages":{"custom":["/languages/repost.json"]}}
    generator javaSdk {
      language       = "java"
      output         = "../target/generated-sources/repost"
      resourceOutput = "../target/generated-resources/repost"
      packageName    = "com.example.repost"
      clientName     = "RepostClient"
    }

    model Order {
      id String
    }

    type Order {
      created
    }

    event OrderCreated {
      type      @type(Order.created)
      data      Order
      timestamp DateTime
    }
    ```

    The generator block sets four things the other languages don't need — [Code generation](/docs/send/java/generation) explains each field, the engine pinning, and multi-module builds.
  </Step>

  <Step title="Generate the client">
    The plugin binds to the `generate-sources` phase, so a normal compile already produces your client. To run generation on its own:

    ```bash theme={"languages":{"custom":["/languages/repost.json"]}}
    ./mvnw repost:generate
    ```
  </Step>
</Steps>

## Your first send

The client is `AutoCloseable`. Open it in a try-with-resources; `create()` reads the credential and endpoint from the environment. Send synchronously, or asynchronously with a `CompletionStage`, passing an idempotency key you control:

```java theme={"languages":{"custom":["/languages/repost.json"]}}
Order order = Order.builder().id("order-123").build();
try (RepostClient repost = RepostClient.create()) {
    SendResult sync = repost.webhooks().order().created("customer-123", order);
    System.out.println(sync.getId());

    SendResult async = repost.webhooks().order().createdAsync(
                    "customer-123",
                    order,
                    SendOptions.builder().idempotencyKey("order-123").build())
            .toCompletableFuture()
            .join();
    System.out.println(async.getId());
}
```

A successful send returns a `SendResult` whose `getDeliveryState()` is `ACCEPTED`; any failure throws a `RepostException` subclass — [Reliability](/docs/send/java/reliability) covers the full outcome model. `close()` returns every owned thread and connection to baseline — always close a client you created.

## Continue

<Columns cols={3} className="gap-y-4">
  <Card title="Code generation" icon="cog" href="/docs/send/java/generation" cta="Generation" arrow="true">
    The generator block, the `repost:check` CI gate, and multi-module builds.
  </Card>

  <Card title="Configuration" icon="sliders-horizontal" href="/docs/send/java/configuration" cta="Configure" arrow="true">
    Credentials, timeouts, retries, and transport options with production defaults.
  </Card>

  <Card title="Reliability" icon="shield-check" href="/docs/send/java/reliability" cta="Outcomes" arrow="true">
    Idempotency, the five delivery states, cancellation, and backpressure.
  </Card>
</Columns>
