Unleashing Vaadin for GUI-Based Java Scripts with JBang
Making Java work for utility apps and scripts
Java has long been known for its robustness and scalability, but it has never been the go-to choice for small utility apps or quick scripts. While tools like Bash and Python are commonly used for scripting, they often come with their own set of frustrations—whether it's cryptic syntax, debugging struggles, or the lack of a solid IDE experience.
I’ve personally found myself battling with Bash scripts, able to get things done but never feeling truly productive compared to working in Java with a proper IDE. Java is often avoided for this kind of task due to the ceremonies related to building and execution (intermediate bytecode). While GraalVM native compilation provides one way to improve Java’s startup time and execution experience (native executable binary, without JVM overhead), it’s not ideal for scripts that require frequent modifications—native builds are simply too slow for fast iterations, and you still need that build script.
Enter JBang: Java for scripts, the right way
The real game-changer for using Java as a scripting language is JBang. JBang is a lightweight CLI tool that allows you to execute Java source files directly—just like a shell script. You’ll add a simple shebang-like line at the top of your .java
file, and you’re good to go. No compilation, no jar packaging, no builds scripts, simply execute the java file from CLI like this:
```java
./myscript.java
```
The first launch of this kind of JBang script can take a bit more time when e.g. some dependencies need to be downloaded, but subsequent runs with modern JVM are practically instant.
Some might argue that modern JDK versions (JEP 330) already allow running Java code directly, but JBang provides critical advantages over the raw JDK feature:
- (Arguably) better conventions, support for tooling, and user experience (e.g.,
.java
file extensions we have learned to use for our Java files) - Dependency management (support for Maven dependencies & resolving those automatically from the Maven Central repository)
- Convenience tools
- Quick commands for project scaffolding
- Shortcut to open the project in an IDE
- Automatic JDK installation for non-Java developers (or to servers executing scripts)
With JBang, you get the power of Java without the usual ceremony, making it a fantastic tool for anyone who wants to write robust, type-safe scripts.
But what about the UI?
Most JBang-based utilities either run headless or provide a minimal CLI-based UI. However, when one of my scripts started getting more complex, I realized something:
Not only were my Bash skills rusty, but my CLI UI design skills were just as bad. I could have settled on JavaFX, but as I mostly work on web apps, Vaadin APIs are much stronger in my “muscle memory.” So, I wondered—why not bring Vaadin into the mix and build a fully functional GUI for my script?
This led to the creation of a simple library that allows running a Vaadin Flow application with JBang, completely without requiring a front-end build or special plugins. This means you can now launch Vaadin-based GUIs directly from a script, just like any other JBang app.
Here’s what a basic Hello World GUI script looks like with Vaadin and JBang:
```java
///usr/bin/env jbang "$0" "$@" ; exit $?
//JAVA 17
//DEPS in.virit.ws:jbang-starter:24.6.1
package bang;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class hello {
public static void main(String... args) {
SpringApplication.run(hello.class, args);
}
@Route
public static class MainView extends VerticalLayout {
public MainView() {
add("Hello, world!");
}
}
}
```
And just like that, Java scripting isn't just for the terminal anymore—it’s now capable of instant GUI-based applications!
A truly seamless experience
One of the coolest aspects of this approach is how seamlessly it integrates with a local environment:
- Auto-opens in a browser when launched
- Uses a random port to avoid conflicts with other local servers
- Auto-shuts down when the browser window is closed (except in Firefox due to a known Vaadin bug)
This makes it a perfect fit for lightweight, single-use tools that don’t need a long-running server. No more manually killing processes—just close the tab, and the app is gone.
Example: A Simple Calculator
For a more practical example, here's a tiny calculator built using JBang and Vaadin:
```java
///usr/bin/env jbang "$0" "$@" ; exit $?
//JAVA 17+
//DEPS in.virit.ws:jbang-starter:24.6.2
package bang;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.html.Paragraph;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.select.Select;
import com.vaadin.flow.component.textfield.NumberField;
import com.vaadin.flow.router.Route;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.vaadin.firitin.components.button.DefaultButton;
@SpringBootApplication
public class calculator {
public static void main(String... args) {
SpringApplication.run(calculator.class, args);
}
enum Operation {
ADD, SUBTRACT, MULTIPLY, DIVIDE;
public String toString() {
return switch (this) {
case ADD -> "+";
case SUBTRACT -> "-";
case MULTIPLY -> "*";
case DIVIDE -> "/";
};
}
}
@Route
public static class MainView extends VerticalLayout {
public MainView() {
add(new H1("Hello, world!"));
add(new Paragraph("This is a small JBang & Spring Boot tool that opens locally on a workstation with a Vaadin based GUI."));
add(new Paragraph("Closing this window also shuts down the JBang application."));
var num1 = new NumberField() ;
var operation = new Select<Operation>() ;
var num2 = new NumberField();
var execute = new DefaultButton("=");
var result = new Div();
add(num1, operation, num2, execute, result);
execute.addClickListener(e -> {
double res = switch (operation.getValue()) {
case ADD -> num1.getValue() + num2.getValue();
case SUBTRACT -> num1.getValue() - num2.getValue();
case MULTIPLY -> num1.getValue() * num2.getValue();
case DIVIDE -> num1.getValue() / num2.getValue();
};
result.setText(num1.getValue() + " " + operation.getValue() + " " + num2.getValue() + " = " + res);
});
}
}
}
```
This runs as a full Vaadin app but launches instantly, providing a simple GUI utility without the usual complexity of Java web app deployment.
How this solved a real-world problem
This entire approach was inspired by my need for a vector tile processing tool, which isn’t quite ready for public release yet. However, I quickly found another very real problem where this tool proved incredibly useful:
When I recently migrated to a new laptop, I noticed that my Vaadin project directory contained millions of files, thanks to frontend builds and npm dependencies. This wasted gigabytes of space and slowed down file transfers significantly.
So, I built a simple GUI-based cleaner tool using Vaadin and JBang to:
- Scan a directory for Vaadin projects
- Identify & clean up auto-generated frontend files
- Free up disk space before migration
Having a visual GUI in this app, although quite trivial, helps you better understand what you are about to do and how the process goes (in my special case, it took several minutes). This saved gigabytes of storage and made copying my project directory significantly faster. 😎 The script is included in the examples directory—so feel free to take it and tune it for your own needs. One could, for example, tweak it for all your Maven projects as well.
Final thoughts
If you love Java but have always avoided it for quick scripts due to the build hassles and complexity, JBang is the missing piece of the puzzle. And now, with this Vaadin integration, you can take things one step further—turning quick Java scripts into fully interactive GUI applications.
Give it a try, and let me know what cool tools you end up building! 🚀
Source: View source