DEV Community

カイノヴァイイ
カイノヴァイイ

Posted on

I was tired of Spring Boot, so I built a Laravel-inspired Java framework

I'm a self-taught developer. I'm 25 and I just want to build things — Minecraft server websites, dashboards, portfolios — without spending half my time fighting my own stack.

That's how Obsidian was born.


The problem

I tried Spring Boot with Thymeleaf. It felt horrible. Too much configuration, too many annotations before writing a single line of business logic. I knew Laravel and Symfony from PHP — and the contrast was brutal.

In Laravel, you clone a repo, run one command, and you're building. In Spring Boot, you're still configuring beans.

I wanted that Laravel feeling, but in Java. I couldn't find it. So I built it.


What is Obsidian?

Obsidian is a web framework built on top of Spark Java that brings Laravel-style conventions to the JVM.

git clone https://github.com/obsidian-framework/obsidian my-app
cd my-app
mvn clean package exec:java
Enter fullscreen mode Exit fullscreen mode

That's it. App running on localhost:8888.


How it feels in practice

Annotation routing

No manual wiring. You declare routes directly on your methods.

@Controller
public class PostController extends BaseController {

    @GET("/posts")
    private Object index(PostRepository repo) {
        return render("posts/index.html",
            Map.of("posts", repo.findAll()));
    }

    @POST("/posts")
    private Object store(Request req, Response res) {
        // handle form submission
    }
}
Enter fullscreen mode Exit fullscreen mode

Dependency injection — two ways

Field injection when you need it across multiple methods:

@Controller
public class ArticleController extends BaseController {

    @Inject
    private ArticleRepository articleRepo;

    @GET("/articles")
    private Object index(Request req, Response res) {
        return render("articles/index.html", Map.of("articles", articleRepo.findAll()));
    }

    @DELETE("/articles/:id")
    private Object delete(Request req, Response res) {
        articleRepo.delete(req.params(":id"));
        res.redirect("/articles");
        return null;
    }
}
Enter fullscreen mode Exit fullscreen mode

Method parameter injection when only one route needs it:

@GET("/articles")
private Object index(Request req, Response res, ArticleRepository repo) {
    return render("articles/index.html", Map.of("articles", repo.findAll()));
}
Enter fullscreen mode Exit fullscreen mode

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.text("body");
            table.timestamps();
        });
    }
}
Enter fullscreen mode Exit fullscreen mode

LiveComponents

This is the part I'm most proud of. Reactive server-side UI without writing JavaScript — the runtime is included automatically via {{ livecomponents_scripts | raw }}, inspired by Laravel Livewire.

@LiveComponentImpl
public class Counter extends LiveComponent {

    @State
    private int count = 0;

    @Action
    public void increment() { count++; }

    @Action
    public void decrement() { count--; }

    public int getCount() { return count; }

    public String template() {
        return "components/counter.html";
    }
}
Enter fullscreen mode Exit fullscreen mode
{{ component('Counter') | raw }}
Enter fullscreen mode Exit fullscreen mode
<div live:id="{{ _id }}">
    <h2>Count: {{ count }}</h2>
    <button live:click="increment">+</button>
    <button live:click="decrement">-</button>
    <div live:loading>Updating...</div>
</div>
Enter fullscreen mode Exit fullscreen mode

I use this in production on a Minecraft server website. It works.


How it compares to Spring Boot

Spring Boot Obsidian
Time to first route 10+ minutes 30 seconds
Annotations to start 3–5 1
Config files Multiple .env
Learning curve Steep Minimal
Production-ready Yes Side projects & small apps

What it's built on

  • Spark Java — lightweight HTTP server
  • ActiveJDBC — ActiveRecord-style ORM
  • Pebble — Jinja2-inspired template engine
  • Reflections — classpath scanning for auto-discovery
  • Jedis — Redis support via the cache system

Who is it for?

Honestly? Not for enterprise teams that need Spring Boot's ecosystem. Obsidian is for:

  • PHP developers forced to write Java who miss Laravel
  • Developers who want to ship a small Java app without the ceremony
  • Anyone who thinks Java web dev should feel less like paperwork

What's next

The framework is MIT licensed, the code is open, and I'm building in public. There will be bugs. I'll fix them.

If this sounds interesting — the repo is at github.com/obsidian-framework and the docs are at obsidian-java.com.

Star it if you want to follow along. Open an issue if something breaks. That's how open source works.

Top comments (0)