Javelin is a lightweight Java framework inspired by MarwaPHP-style service providers while staying explicit, modular, and close to the JDK.
This repository is the first production-oriented MVP phase. It includes the boot flow, service container, provider loading, JDK HTTP runtime with virtual threads, routing, middleware, YAML and .env config, SLF4J logging, Pebble views, JDBC/Hikari database access, Picocli commands, security middleware, in-memory cache, a demo app, and unit tests.
modules/javelin-core- application, container, providers, router, request/response, facades, kernel contractsmodules/javelin-config-.envand YAML config loadingmodules/javelin-http-jdk- JDKHttpServeradapter using virtual threadsmodules/javelin-db-jdbc- HikariCP-backed JDBC database, query builder, and YAML migration runnermodules/javelin-log-slf4j- SLF4J/Logback logger adaptermodules/javelin-view-pebble- Pebble template renderermodules/javelin-console- Picocli command kernel and generatorsmodules/javelin-security- secure headers, request limits, rate limiting, password hashingmodules/javelin-support- short Laravel-style helper facades for strings, dates, arrays, files, images, HTTP client, AI client, objects, validation, HTML, and securitymodules/javelin-cache- simple in-memory cache contract and implementationmodules/javelin-starter- batteries-included bootstrapdemo-app- runnable demo application
Module-by-module API and usage examples live under docs/.
Javelin is designed as two cooperating pieces:
javelin-coreand its adapter modules are the reusable framework library.javelin-starteris the default runtime composition for application code.javelin-consoleis the developer workspace toolchain that provides thejavelincommand.
For a library or application that wants to consume Javelin from Maven, depend on the framework artifacts directly:
<dependency>
<groupId>io.javelin</groupId>
<artifactId>javelin-starter</artifactId>
<version>${javelin.version}</version>
</dependency>Then keep your actual workspace as a normal Maven application project. That workspace can add Javelin plus any other libraries it needs, and the javelin command can be used for scaffolding, serving, code generation, migrations, diagnostics, and AI-assisted workflows.
The generated workspace template already follows that shape: the project POM depends on javelin-starter, while the workspace remains free to add its own application dependencies.
It also includes a workspace-local README.md, install.ps1, and install.sh that explain the app setup, verify Java and Maven, then run mvn test from inside the generated app.
The starter validation example is customizable too: javelin new crm-app --validation-rule TeenAge will generate app/validation/TeenAgeRule.java.
- Java 25
- Maven 3.9+
From the repository root, install the local javelin command with one line.
Windows PowerShell:
powershell -ExecutionPolicy Bypass -File .\install.ps1Linux/macOS:
sh ./install.shThe installer builds modules/javelin-console, creates a launcher in ~/.javelin/bin, and adds that folder to your user PATH. Open a new terminal after installation.
Verify:
javelin --helpAfter changing CLI source, rebuild the CLI jar:
mvn -pl :javelin-console -am package -DskipTestsWhen you generate a new workspace with javelin new <name>, use the workspace-local installer inside that app directory:
cd <name>
./install.shOn Windows:
cd <name>
.\install.ps1- Load
.env - Load
config/app.yaml - Create
Application - Create
Container - Register core bindings
- Load configured service providers
- Run
provider.register(app) - Run
provider.boot(app) - Start JDK
HttpServerwith virtual threads - Serve requests
app.router()
.get("/", home::index)
.get("/health", home::health)
.get("/users/{id}", users::show);return Json.ok(Map.of("status", "ok"));
return View.render("users/index", Map.of("name", "Javelin"));Pebble settings live in config/view.yml. Applications can register custom Pebble filters, functions, tests, globals, or full extensions from a service provider:
app.make(PebbleViewExtensions.class)
.extension(new JavelinViewExtension())
.global("javelinRuntime", "JDK 25");See demo-app/app/views/JavelinViewExtension.java for a custom filter and function example.
The javelin-support module provides small, stateless helper facades for common library and application tasks:
import java.nio.file.Path;
import java.util.List;
import io.javelin.support.Arr;
import io.javelin.support.Date;
import io.javelin.support.File;
import io.javelin.support.Html;
import io.javelin.support.Obj;
import io.javelin.support.Security;
import io.javelin.support.Str;
import io.javelin.support.Validator;
String slug = Str.toSlug("Javelin Framework");
List<String> tags = Arr.compact(new String[] {"core", null, "support"});
Path path = File.safeResolve(Path.of("storage"), "logs", "app.log");
String today = Date.format(Date.today());
String escaped = Html.escape("<strong>safe</strong>");
String fallback = Obj.coalesce(null, "default");
String name = Validator.requireNonBlank("User", "name is required");
String token = Security.randomToken(16);These helpers are intentionally strict and predictable:
- no hidden global state
- no annotation scanning
- no framework magic
- JDK-only behavior where practical
Use them when you want concise utility methods without pulling in a heavy framework abstraction.
Database db = app.make(Database.class);
db.table("users").where("id", 1).first();The query builder uses prepared statements for values. Keep table and column names framework-controlled or validated before passing dynamic identifiers.
YAML migration files live under database/migrations, and javelin migrate / javelin migrate:rollback execute them through the JDBC migration runner.
The repository includes local launcher scripts for the global-style javelin command:
- Windows:
javelin.cmd - Linux/macOS:
./javelin
Build the CLI launcher after cloning or after changing CLI source:
mvn -pl :javelin-console -am package -DskipTestsIf you installed with install.ps1 or install.sh, use javelin directly instead of the repo-local launcher.
Build the demo application once:
javelin --project demo-app buildWithout installing, use the repo-local launcher:
.\javelin.cmd --project demo-app buildStart the HTTP server:
javelin --project demo-app serveWithout installing:
.\javelin.cmd --project demo-app serveThen open:
http://127.0.0.1:8080
From the repository root, app runtime commands default to demo-app, so this also works after the app has been built:
javelin serveWithout installing:
.\javelin.cmd serveUse --project <path> to target an application folder:
javelin --project demo-app routes:list
javelin --project demo-app make:controller UserController
javelin --project demo-app make:model User
javelin --project demo-app migratejavelin build is explicit. Other project commands, including serve, do not rebuild automatically; they run the existing application jar from target/.
javelin make:migration now generates YAML files under database/migrations, and javelin migrate / javelin migrate:rollback execute those files through the JDBC migration runner.
Use --type create-table, --type add-column, or --type seed to scaffold the common migration shapes quickly.
If the jar does not exist yet, run:
javelin --project demo-app buildRun all tests:
mvn testBuild the full reactor:
mvn package -DskipTestsBuild only the demo app and required modules:
mvn -pl demo-app -am package -DskipTestsNext phases should add validation, file uploads, trusted proxy parsing, static assets, CSRF/session support, Redis, queues, scheduler, WebSocket, OAuth, metrics, and deploy tooling.