# JAR assembly

> Create, list and extract JARs with `elide jar`, and build JARs, sources and Javadoc JARs and runnable application distributions in an Elide project.

Elide creates and reads JAR files directly with `elide jar`, and builds them as project artifacts.

## Create, list and extract

`jar` options go after `--`:

```bash
elide jar -- --create --file app.jar -C out .                              # create
elide jar -- --list --file app.jar                                         # list
elide jar -- --extract --file app.jar --dir extracted                      # extract
elide jar -- --create --file app.jar --main-class com.example.Main -C out . # executable JAR
elide jar -- -help
```

## Compile and create a JAR

```bash
elide javac --jar target/app.jar -- src/Main.java src/Util.java
elide javac --jar target/app.jar --manifest src/MANIFEST.MF -- src/Main.java
```

## Project artifacts

```pkl
amends "elide:project.pkl"
import "elide:Jvm.pkl" as Jvm

artifacts {
  ["app"] = new Jvm.Jar {
    name = "app"
    options {
      entrypoint = "com.example.Main"
    }
  }
}
```

`elide build` writes `.dev/artifacts/jar/<name>/`. The JAR holds every non-test source set's classes and resources.

### `Jvm.Jar`

| Property | Meaning | Default |
| --- | --- | --- |
| `name` | File name; `"app"` and `"app.jar"` both give `app.jar`. | the artifact key |
| `sources` | Source sets to package; empty means every non-test set. | none |
| `from` | Other workspace members' JARs to unpack into this one, each built first: `from { project("x") }`. Their manifests are dropped; their dependencies join this project's exported and published POM. | none |
| `resources` | Extra files: paths or `new { from = …; into = … }`. | none |
| `manifest` | Extra `META-INF/MANIFEST.MF` attributes. | none |
| `manifestFile` | Manifest file to use instead of a generated one. | — |
| `excludes` | Entries to omit: a pattern with `/ * ? [ ]` is a path glob; a dotted name is a package prefix. | none |
| `options.entrypoint` | `Main-Class`. | `jvm.main` |
| `options.compress` | Compress entries. | `true` |
| `options.defaultManifestProperties` | Add `Implementation-*` attributes. | `true` |
| `main` | Not read when packaging; use `options.entrypoint`. | — |
| `dependsOn` | Artifacts to build first. | none |

```pkl
artifacts {
  ["app"] = new Jvm.Jar {
    sources { "main" }
    excludes {
      "com.example.internal"   // a package and its subpackages
      "**/*.proto"             // a path glob
    }
    manifest {
      ["Implementation-Vendor"] = "Example"
    }
    resources {
      "LICENSE.txt"
      new { from = "config"; into = "META-INF/config" }
    }
  }
}
```

### Sources and Javadoc JARs

```pkl
artifacts {
  ["sources"] = new Jvm.SourceJar {
    classifier = "sources"
    excludes { "**/internal/**" }
  }
  ["javadoc"] = new Jvm.JavadocJar {
    windowTitle = "Example API"
    links { "https://docs.oracle.com/en/java/javase/25/docs/api/" }
    groups {
      ["Core"] { "com.example.core" }
    }
  }
}
```

| `Jvm.SourceJar` | Meaning |
| --- | --- |
| `sources` | Source sets to package; empty means every non-test set. |
| `classifier` | Inserted before the extension (`app-sources.jar`). |
| `includes`, `excludes` | Path globs over the sources. |

| `Jvm.JavadocJar` | Meaning |
| --- | --- |
| `sources` | Source sets to document; empty means every non-test set. |
| `groups` | Package groups: title to package list. |
| `links` | External documentation URLs. |
| `excludes` | Patterns to leave undocumented. |
| `windowTitle`, `docTitle` | Window and document titles. |
| `generator` | `"auto"` (default): Dokka when the sources include Kotlin, `javadoc` otherwise. `"javadoc"` or `"dokka"` picks one. |

Sources that include Kotlin are documented with [Dokka](https://kotlinlang.org/docs/dokka-introduction.html) instead of
`javadoc`, covering the Java beside them too; `generator = "javadoc"` documents only the Java files. Dokka runs as a
separate JVM process. Elide resolves its jars from Maven the first time a Kotlin javadoc JAR is built and caches them in
the local Maven repository, so that first build needs network access. On every build, Dokka also fetches the package
lists behind its links to the JDK, the standard library and `links`; `--offline` skips those lookups. Dokka reads
`sources`, `links` and `excludes` (an excluded package and its subpackages are left out); `groups` and the titles apply
to `javadoc` only, and Elide warns when titles are set for Dokka.

## Runnable application distributions

A `Jvm.JvmApplication` is a runnable tree, like Gradle's `application` plugin: runtime JARs in `lib/`, start scripts
in `bin/`, and optional archives.

```pkl
artifacts {
  ["dist"] = new Jvm.JvmApplication {
    from { "app" }
    entrypoint = "com.example.Main"
    defaultJvmArgs { "-Xmx512m" }
    contents {
      new { from = "config"; into = "etc" }
    }
    options {
      archives { "zip"; "tar" }
    }
  }
}
```

| Property | Meaning | Default |
| --- | --- | --- |
| `from` | JAR artifacts with the app's code; empty means every declared JAR, or a JAR of the project's classes. | none |
| `name` | Directory and start-script name. | the artifact key |
| `entrypoint` | Main class. | `jvm.main` |
| `defaultJvmArgs` | JVM options in the scripts, after `jvm.flags`. | none |
| `executableDir` | Directory for the scripts. | `"bin"` |
| `contents` | Extra files in the root, in the same form as source-set resources. | none |
| `options.unixStartScript`, `options.windowsStartScript` | Generate each script. | `true` |
| `options.archives` | `"zip"` and/or `"tar"` (gzip). | none |
| `dependsOn` | Artifacts to build first. | none |

| Output | Path |
| --- | --- |
| Install tree | `.dev/artifacts/install/<name>/` |
| Archives | `.dev/artifacts/distributions/` |

- `elide run` launches the installed tree with the scripts' JVM options.
- Scripts also read `JAVA_OPTS` and `<NAME>_OPTS` (`sample-app` → `SAMPLE_APP_OPTS`).
- The POSIX script follows symlinks to itself; on Windows, run the script directly or via `PATH`.
- `name`, `version` (when archiving) and each `into` must be valid file names on every platform: no `/`, `\`,
  `:*?"<>|`, control characters, trailing dot or space, or Windows device names such as `NUL`. Invalid names fail the
  build before it writes.

Workspace members use a sibling's `Jvm.Jar` with `project("core")`; see
[Workspaces](https://elide.help/docs/elide-pkl-reference#workspaces).
