While most developers think of JavaScript/TypeScript for browser-based applications, the Bck2Brwsr project offers an intriguing alternative: running Java code directly in web browsers without plugins. This innovative approach compiles Java bytecode to JavaScript, enabling true write-once-run-anywhere capabilities for the client side.
This article explores Bck2Brwsr's architecture, use cases, and how to build browser-based Java applications with it.
What is Bck2Brwsr?
Bck2Brwsr (Back to Browser) is an open-source Java virtual machine implementation that compiles Java bytecode to JavaScript, allowing Java applications to run directly in web browsers. Unlike traditional approaches that rely on Java applets or WebStart, Bck2Brwsr uses modern web standards and requires no browser plugins.
Key Characteristics:
- Zero Plugin Requirement: Runs in any modern JavaScript-enabled browser
- Java 8+ Support: Implements significant portions of the Java standard library
- Ahead-of-Time Compilation: Converts JAR files to JavaScript during build
- Compact Runtime: Minimal footprint compared to full JVM
- DOM Integration: Provides Java APIs for browser DOM manipulation
How Bck2Brwsr Works
Bck2Brwsr operates through a sophisticated compilation pipeline:
Java Source → Java Bytecode (.class) → Bck2Brwsr Compiler → JavaScript (.js) → Browser Execution
Architecture Components:
- Bytecode Parser: Reads and analyzes Java .class files
- JavaScript Generator: Translates JVM instructions to equivalent JavaScript
- Runtime Library: Java core classes implemented in JavaScript
- DOM Bindings: Java interfaces for browser document object model
Setting Up a Bck2Brwsr Project
Maven Configuration
Bck2Brwsr projects are typically configured using Maven with specialized plugins:
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>bck2brwsr-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<bck2brwsr.version>0.9.0</bck2brwsr.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apidesign.bck2brwsr</groupId>
<artifactId>bck2brwsr-html</artifactId>
<version>${bck2brwsr.version}</version>
</dependency>
<dependency>
<groupId>org.apidesign.bck2brwsr</groupId>
<artifactId>bck2brwsr-vm</artifactId>
<version>${bck2brwsr.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apidesign.bck2brwsr</groupId>
<artifactId>bck2brwsr-maven-plugin</artifactId>
<version>${bck2brwsr.version}</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Building a Simple Browser Application
Basic HTML Page
Create index.html that loads the generated JavaScript:
<!DOCTYPE html> <html> <head> <title>Bck2Brwsr Java Application</title> <meta charset="utf-8"> </head> <body> <div id="content"></div> <!-- Load the compiled Java application --> <script src="bck2brwsr.js"></script> <script src="bck2brwsr/launcher.js"></script> </body> </html>
Java Application Entry Point
package com.example.browserapp;
import org.apidesign.bck2brwsr.html.Browser;
import org.apidesign.bck2brwsr.html.Html;
import org.apidesign.bck2brwsr.html.Page;
public class BrowserApp {
public static void main(String[] args) {
// Get the current page document
Page page = Browser.getPage();
Html document = page.getDocument();
// Create a heading element
Html heading = document.createElement("h1");
heading.setInnerHTML("Hello from Java!");
heading.setAttribute("style", "color: blue;");
// Create a button
Html button = document.createElement("button");
button.setInnerHTML("Click Me!");
button.setAttribute("style",
"padding: 10px 20px; font-size: 16px; margin: 10px;");
// Add click event handler
button.setOnclick((event) -> {
heading.setInnerHTML("Button clicked at: " +
new java.util.Date().toString());
return null;
});
// Create a container div
Html container = document.createElement("div");
container.appendChild(heading);
container.appendChild(button);
// Add to page body
Html body = document.getBody();
body.appendChild(container);
// Demonstrate Java collections and streams
demonstrateJavaFeatures(document);
}
private static void demonstrateJavaFeatures(Html document) {
// Show that standard Java libraries work
java.util.List<String> items = java.util.Arrays.asList(
"Java", "Bck2Brwsr", "Browser", "VM"
);
Html list = document.createElement("ul");
list.setAttribute("style", "margin-top: 20px;");
// Use Java 8 streams (if supported)
items.stream()
.map(item -> {
Html li = document.createElement("li");
li.setInnerHTML("Item: " + item);
return li;
})
.forEach(list::appendChild);
document.getBody().appendChild(list);
}
}
Advanced DOM Manipulation Example
package com.example.browserapp;
import org.apidesign.bck2brwsr.html.Browser;
import org.apidesign.bck2brwsr.html.Html;
import org.apidesign.bck2brwsr.html.Page;
import org.apidesign.bck2brwsr.html.Event;
public class AdvancedDOMApp {
public static void main(String[] args) {
Page page = Browser.getPage();
Html document = page.getDocument();
createCalculator(document);
createFormHandler(document);
}
private static void createCalculator(Html document) {
Html calculator = document.createElement("div");
calculator.setAttribute("style",
"border: 1px solid #ccc; padding: 20px; margin: 20px; max-width: 300px;");
// Display
Html display = document.createElement("input");
display.setAttribute("type", "text");
display.setAttribute("readonly", "true");
display.setAttribute("style",
"width: 100%; margin-bottom: 10px; padding: 5px; font-size: 18px;");
display.setAttribute("value", "0");
// Number buttons
Html buttonContainer = document.createElement("div");
for (int i = 1; i <= 9; i++) {
Html button = createNumberButton(document, String.valueOf(i), display);
buttonContainer.appendChild(button);
}
calculator.appendChild(display);
calculator.appendChild(buttonContainer);
document.getBody().appendChild(calculator);
}
private static Html createNumberButton(Html document, String number, Html display) {
Html button = document.createElement("button");
button.setInnerHTML(number);
button.setAttribute("style",
"width: 50px; height: 50px; margin: 5px; font-size: 16px;");
button.setOnclick((Event event) -> {
String current = display.getAttribute("value");
if ("0".equals(current)) {
display.setAttribute("value", number);
} else {
display.setAttribute("value", current + number);
}
return null;
});
return button;
}
private static void createFormHandler(Html document) {
Html form = document.createElement("div");
Html input = document.createElement("input");
input.setAttribute("type", "text");
input.setAttribute("placeholder", "Enter your name");
input.setAttribute("style", "padding: 8px; margin: 5px;");
Html button = document.createElement("button");
button.setInnerHTML("Greet");
button.setAttribute("style", "padding: 8px 15px; margin: 5px;");
Html output = document.createElement("div");
output.setAttribute("style", "margin: 10px; font-weight: bold;");
button.setOnclick((Event event) -> {
String name = input.getAttribute("value");
if (name == null || name.trim().isEmpty()) {
output.setInnerHTML("Please enter a name!");
} else {
output.setInnerHTML("Hello, " + name + "! Welcome from Java.");
}
return null;
});
form.appendChild(input);
form.appendChild(button);
form.appendChild(output);
document.getBody().appendChild(form);
}
}
Building and Deployment
Maven Build Process
mvn clean package
This generates:
target/classes/bck2brwsr.js- Main compiled JavaScripttarget/classes/bck2brwsr/- Supporting JavaScript filestarget/classes/*.jar- Your application classes
Project Structure
my-bck2brwsr-app/ ├── src/ │ └── main/ │ ├── java/ │ │ └── com/example/ │ │ └── BrowserApp.java │ └── resources/ │ └── index.html ├── pom.xml └── target/ └── classes/ ├── bck2brwsr.js ├── bck2brwsr/ └── *.jar
Integration with JavaScript Libraries
Bck2Brwsr can interact with existing JavaScript libraries:
package com.example.browserapp;
import org.apidesign.bck2brwsr.core.JavaScriptBody;
public class JSLibraryIntegration {
@JavaScriptBody(args = {}, body =
"alert('This alert comes from Java via JavaScript!');"
)
public static native void showAlert();
@JavaScriptBody(args = {"message"}, body =
"console.log('Java says: ' + message);"
)
public static native void logToConsole(String message);
@JavaScriptBody(args = {"a", "b"}, body =
"return Math.max(a, b);"
)
public static native int javascriptMax(int a, int b);
public static void demonstrateIntegration() {
showAlert();
logToConsole("Hello from Bck2Brwsr!");
int max = javascriptMax(10, 20);
logToConsole("Maximum value: " + max);
}
}
Limitations and Considerations
Supported Java Features
- Basic Java syntax and control structures
- Core collections (List, Map, Set)
- Limited I/O capabilities (browser security restrictions)
- DOM manipulation APIs
- Basic multi-threading (with browser constraints)
Current Limitations
- Reflection: Limited or no support for reflection APIs
- Native Methods: Cannot use JNI or native libraries
- File System: Restricted file access due to browser security
- Large Dependencies: Heavy Java libraries increase bundle size significantly
- Performance: JavaScript compilation may have performance overhead
Comparison with Alternatives
| Technology | Approach | Plugin Required | Size | Java Version |
|---|---|---|---|---|
| Bck2Brwsr | Java→JS compilation | No | Medium | Java 8+ |
| Java Applets | Browser plugin | Yes | Large | Java 1-8 |
| WebAssembly | Bytecode in browser | No | Small | Limited |
| TeaVM | Java→JS/WASM | No | Small | Java 8+ |
| CheerpJ | JVM in WASM | No | Large | Full JVM |
Use Cases and When to Choose Bck2Brwsr
Good Fit For:
- Java shops wanting browser deployment without rewriting in JavaScript
- Educational tools demonstrating Java concepts in browser
- Internal applications with controlled environments
- Prototyping and proof-of-concept applications
Poor Fit For:
- Performance-critical applications
- Applications requiring extensive JavaScript ecosystem integration
- Projects needing latest Java features beyond Java 8
- Public-facing websites requiring optimal load times
Conclusion
Bck2Brwsr represents an ambitious approach to bringing Java to the browser without plugins. While it faces competition from WebAssembly-based solutions and has some limitations, it offers:
- True Java Development: Write real Java code for client-side applications
- No Plugin Dependency: Runs in standard modern browsers
- JVM Ecosystem Access: Leverage existing Java libraries and skills
- Innovative Approach: Demonstrates Java's versatility beyond traditional environments
For teams deeply invested in Java who need browser deployment capabilities, Bck2Brwsr provides a viable pathway. However, for new projects, it's worth also evaluating TeaVM and WebAssembly-based solutions that may offer better performance and more modern feature support.
The project continues to be an important part of the Java-in-browser landscape, showing that Java's "write once, run anywhere" promise can extend to web browsers in the modern era.