Obsidian gives your Spark Java app a solid foundation — annotation routing, fluent migrations, LiveComponents, authentication, and more.
Get started in seconds
git clone https://github.com/obsidian-framework/skeleton
cd obsidian-skeleton
./build.bat
App running on localhost:8888
Code that speaks for itself
Annotation routing
Declare routes directly on your methods. No manual wiring.
@Controller
public class PostController extends BaseController
{
@GET("/posts")
private Object index(PostRepository repo) {
return render("posts.html",
Map.of("posts", repo.findAll()));
}
}
Fluent migrations
Laravel-inspired schema builder. No raw SQL.
public class CreatePostTable extends Migration
{
@Override
public void up() {
createTable("posts", table -> {
table.id();
table.string("title").notNull();
table.timestamps();
});
}
}
Authentication & roles
Protect routes with a single annotation.
@HasRole("ADMIN")
@GET("/admin/dashboard")
private Object dashboard() {
return render("dashboard.html");
}
@CsrfProtect
@POST("/login")
private Object login(Request req, Response res) {
login(username, password, session);
}
Form validation
Simple, readable validation rules.
ValidationResult result =
RequestValidator.validateSafe(req,
Map.of(
"title", "required|min:20",
"body", "required|min:100"
));
if (result.fails()) {
return render("form.html",
Map.of("errors", result.getErrors()));
}
One backend, every frontend
Obsidian doesn't force your frontend choices. Ship reactive UIs with LiveComponents, classic server-rendered pages with Pebble, or a pure JSON API consumed by any external stack.
@LiveComponentImpl
public class Counter extends LiveComponent
{
@State
private int count = 0;
public void increment() { count++; }
public void decrement() { count--; }
public int getCount() { return count; }
public String template() {
return "components/counter.html";
}
}
<div live:id="">
<h2>Count: </h2>
<button live:click="increment">+</button>
<button live:click="decrement">-</button>
</div>
Everything you need
LiveComponents
Reactive server-side UI without writing a single line of JavaScript. Inspired by Laravel Livewire.
Middleware system
@Before / @After with built-in CORS, rate limiting, logging, and API key middlewares.
Repository injection
Annotate a class with @Repository and it's automatically injected into your controller methods.
CSRF protection
One annotation on your POST routes. Token generation and validation handled automatically.
Flash messages
redirectWithFlash() for temporary success and error notifications without external dependencies.
Server-Sent Events
Real-time streaming from server to client. No WebSocket complexity when you don't need it.