Java in the Browser Reimagined: Bck2Brwsr for Client-Side Java

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:

  1. Bytecode Parser: Reads and analyzes Java .class files
  2. JavaScript Generator: Translates JVM instructions to equivalent JavaScript
  3. Runtime Library: Java core classes implemented in JavaScript
  4. 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 JavaScript
  • target/classes/bck2brwsr/ - Supporting JavaScript files
  • target/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

TechnologyApproachPlugin RequiredSizeJava Version
Bck2BrwsrJava→JS compilationNoMediumJava 8+
Java AppletsBrowser pluginYesLargeJava 1-8
WebAssemblyBytecode in browserNoSmallLimited
TeaVMJava→JS/WASMNoSmallJava 8+
CheerpJJVM in WASMNoLargeFull 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:

  1. True Java Development: Write real Java code for client-side applications
  2. No Plugin Dependency: Runs in standard modern browsers
  3. JVM Ecosystem Access: Leverage existing Java libraries and skills
  4. 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.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper