DEV Community

JADEx
JADEx

Posted on

Why I Built JADEx Instead of Switching to Kotlin

Every Java team eventually has that conversation.

Someone opens a PR, there's a NullPointerException in production, and someone says: "We should just migrate to Kotlin."

I've had that conversation. And I get it — Kotlin is genuinely good. But every time I looked at a migration seriously, the same problems came up: existing codebase, team familiarity, Spring Boot annotation processing quirks, and Lombok everywhere. The cost wasn't just technical. It was organizational.

So I asked a different question: What if Java just had null-safety syntax?

Not annotations. Not a linter. Actual syntax — String?, ?., ?: — that gets checked at compile time and disappears into plain Java before the JVM ever sees it.

That's how JADEx started.


The "Obvious" Solutions Weren't Enough

I looked at NullAway and JSpecify first. They're solid tools, but they work through annotations — you end up writing @Nullable String name everywhere, and it still doesn't give you the concise chained access that makes null-safe code actually readable. You're still writing null checks by hand in most cases.

Kotlin solves this elegantly. But Kotlin solves it by being a different language. That's the tradeoff I wasn't willing to make.

And honestly, null-safety wasn't the only problem.

Every Java developer has felt it at some point — wanting to mark something final but having to do it manually every single time. Immutability should be the default, but in Java, mutability is the default and final is the opt-in. Kotlin flipped this. val is the default, var is the exception.

JADEx goes the same direction. Just without a new language, and without forcing anything. Declare apply readonly at the top of a file, and every field, local variable, and parameter in that file is automatically treated as final. Only mark something mutable when you explicitly need it to change. No need to rewrite the entire codebase at once — apply it file by file, at whatever pace works for your team.


So What Is JADEx, Exactly?

One sentence: Keep your Java code as-is, and change the language-level defaults for writing safe code.

Non-null and final are the defaults in the type system. If you want to allow null, you declare it explicitly. If you need mutability, you choose it intentionally. Everything else is plain Java — same JVM, same ecosystem, same build pipeline. .jadex files are transformed into .java files at compile time, and javac takes it from there. No runtime overhead, no new language to learn.

If Kotlin solved these problems by creating a new language, JADEx solves them while keeping Java exactly as Java.


Why Not Just Use Kotlin?

Not because Kotlin is bad. Quite the opposite — Kotlin solved these problems beautifully. Null-safety, val/var, data classes. Everything Java ignored for decades, Kotlin addressed at the language design level.

But migrating to Kotlin isn't just changing syntax.

Right now, countless companies are running hundreds of thousands of lines of Java legacy code. Lombok annotations are scattered everywhere. Spring Boot configurations are built around Java. Real services are running on top of all of it. Migrating to Kotlin isn't just a matter of time and money — it means taking on risk against systems that are stable and in production. That's not a decision most teams can make lightly.

The cost of migration isn't just in the code. It's in the team's time, focus, and risk tolerance.

So in practice, Kotlin migration discussions usually end the same way: "Good idea, but not right now." And that conversation gets forgotten until the next NPE hits production.

JADEx is for the teams stuck at "not right now." Unlike a Kotlin migration, there's no new language for the whole team to learn, no need to flip the entire codebase at once. .jadex files coexist alongside existing .java files. You can start with a single new file today. Migration happens at the source file level, incrementally, at whatever pace the team is ready for.

No migration. Existing codebase intact. Safer code starting today.


How It Works

JADEx is a source-to-source compiler. It reads .jadex files, parses the new syntax, and transforms them into plain .java files. Then javac takes over. The JVM has no idea JADEx exists.

The grammar extension is built on ANTLR4. Starting from the official Java grammar, JADEx adds ? type annotations, ?. safe calls, ?: Elvis operator, the mutable keyword, and apply readonly declarations. The parser converts .jadex files into an AST, and a visitor walks the tree, replacing new nodes with equivalent Java code.

But syntax transformation alone wasn't enough.

Replacing String? with @Nullable String is straightforward. The hard part is verifying that the nullable type flows correctly throughout the entire codebase. Passing a String? to a method that expects String should be a compile error. The result of a ?. access should automatically become nullable. This isn't a text substitution problem — it's a type system problem.

So I built a static analyzer from scratch.

JADEx's NullabilityChecker walks the AST and tracks the nullability of each expression. Variable declarations, method return types, parameters — all type information is recorded in a symbol table, and every assignment and call site is checked to ensure nullable/non-null flow is correct. Null safety is guaranteed at the JADEx level, before javac ever runs.

Lombok makes this more complicated. Lombok annotations generate code at compile time, which means the generated code doesn't exist yet at static analysis time. JADEx runs Delombok as a separate JVM process to obtain the expanded code first, maps the offsets back to the original source, and then proceeds with analysis. This ensures null-safety works correctly even in codebases heavy with Lombok.


I Want to Build This Together

JADEx is still early. But it works — null-safety syntax, apply readonly, Lombok integration, a Gradle plugin published to Maven Central, and an IntelliJ plugin.

I want to make JADEx a polished, production-ready tool and give it to Java developers for free. This isn't about commercialization. It's about giving teams that can't migrate to Kotlin, won't migrate to Kotlin, or simply love Java — a real choice for writing safer code.

But I'll be honest. I'm currently unemployed. I'm putting everything into this project without any income. Working alone, every day, at a public library. Continuing to build JADEx requires financial support. That's not a preference — it's a reality.

If you think this project matters, and if you think the Java ecosystem needs tools like this — please consider supporting development through GitHub Sponsors. As long as the support continues, so does JADEx.

If you'd like to contribute with code:

  • Browse the repo and open an issue on GitHub

  • Try it out and share your feedback

  • Or just leave a star

Any form of support is welcome. I want to build the day when Java developers are finally free from NullPointerExceptions.

JADEx GitHub

JADEx GitHub Sponsors

Top comments (0)