Introduction to J2CL
J2CL (Java to JavaScript Compiler) is a Google-backed compiler that enables Java source code to be transpiled into optimized JavaScript. Let us delve into understanding J2CL with our introduction to J2CL article.
1. What is J2CL?
J2CL (Java to Closure Compiler JavaScript) is a powerful transpiler developed by Google that converts Java source code into optimized JavaScript. It is specially designed to work seamlessly with the Closure Compiler, enabling advanced optimizations such as dead code elimination, aggressive minification, and tree-shaking.
J2CL is typically used in tandem with tools like gwt-java-lang (a subset of java.lang classes tailored for GWT and J2CL) and elemental2 (a modern wrapper around browser APIs) to build web applications where frontend logic is implemented in Java and then transpiled to high-performance JavaScript. This allows developers to benefit from strong static typing, code reuse, and the vast ecosystem of Java while still targeting the browser as the runtime environment.
- Java Compatibility: Supports Java 8 and partially supports newer Java language features.
- Code Reuse: Enables sharing of code between server-side and client-side components, promoting consistency and reducing duplication.
- Build Tool Integration: Fully integrated with modern build tools like
BazelandMaven, easing adoption in large projects. - Optimized Output: Produces minimal and efficient JavaScript code suitable for production environments through aggressive tree-shaking and dead code elimination.
- Debugging Support: Supports source maps, enabling developers to debug original Java code directly from the browser dev tools.
- Modularization: Works well with Java modules and provides isolation and encapsulation through strict dependency management.
J2CL is often used in large-scale applications at Google and is an essential part of projects like Clutz and Closure Compiler ecosystems. It is ideal for organizations looking to leverage the robustness of Java for front-end development without compromising on performance or code size.
2. Code Dependencies
This section covers the essential setup required to build a J2CL-based project using Maven. It includes the configuration of dependencies and plugins needed to compile Java code into optimized JavaScript using the J2CL toolchain.
2.1 Add Dependencies (pom.xml)
To begin with, you need to set up your Maven project by including the necessary dependencies for J2CL and Elemental2, as well as configuring the J2CL Maven plugin for transpilation. Below is a pom.xml that includes all required elements:
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>j2cl-task-manager</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.google.elemental2</groupId>
<artifactId>elemental2-dom</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.google.j2cl.tools</groupId>
<artifactId>j2cl-maven-plugin</artifactId>
<version>0.8</version>
<executions>
<execution>
<goals>
<goal>transpile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
2.2 Java Code
Once your project is configured, you can start writing Java code that will be transpiled into JavaScript. Below is an example of a TaskManager class that uses Elemental2 to manipulate the DOM and manage a list of tasks. This code will run in the browser after being compiled by J2CL.
package com.example.taskmanager;
import elemental2.dom.*;
import jsinterop.annotations.JsType;
import java.util.ArrayList;
import java.util.List;
@JsType
public class TaskManager {
private static final List tasks = new ArrayList();
public static void main(String[] args) {
// Get the root container in HTML
HTMLDivElement root = (HTMLDivElement) DomGlobal.document.getElementById("app");
// Create an input field for tasks
HTMLInputElement input = (HTMLInputElement) DomGlobal.document.createElement("input");
input.placeholder = "Enter a task";
// Create an add button
HTMLButtonElement button = (HTMLButtonElement) DomGlobal.document.createElement("button");
button.textContent = "Add Task";
// Create a list to display tasks
HTMLUListElement list = (HTMLUListElement) DomGlobal.document.createElement("ul");
// Add click event handler to add tasks
button.onclick = e -> {
String value = input.value.trim();
if (!value.isEmpty()) {
tasks.add(value);
renderList(list);
input.value = "";
}
return null;
};
// Append elements to root container
root.appendChild(input);
root.appendChild(button);
root.appendChild(list);
}
// Render the current tasks in the list
private static void renderList(HTMLUListElement list) {
list.innerHTML = ""; // Clear current list
for (String task : tasks) {
HTMLLIElement item = (HTMLLIElement) DomGlobal.document.createElement("li");
item.textContent = task;
list.appendChild(item);
}
}
}
2.2.1 Code Explanation
The provided Java code defines a simple browser-based task manager using J2CL and Elemental2 APIs. It uses the @JsType annotation to expose the TaskManager class to JavaScript. Within the main method, it dynamically creates an input field for entering tasks, a button to add tasks, and an unordered list to display them. When the “Add Task” button is clicked, it checks if the input is non-empty, then adds the task to a static list and refreshes the UI by calling the renderList method. The renderList method clears the current list and repopulates it with all task entries. All DOM manipulations are handled using Elemental2 types like HTMLInputElement, HTMLButtonElement, and HTMLUListElement, enabling seamless Java-to-JavaScript compilation for frontend interactivity.
2.3 HTML Wrapper
This section provides the HTML scaffolding needed to host and run the JavaScript code generated by the J2CL transpilation process. The HTML file acts as the entry point for the browser, loading the compiled JavaScript and rendering the application inside a designated DOM container. This wrapper is essential for binding the Java-based logic (transpiled into JavaScript) with the browser environment.
Below is a simple yet complete HTML wrapper that integrates with the TaskManager class described earlier:
<!DOCTYPE html> <html> <head> <title>Task Manager</title> </head> <body> <div id="app"></div> <script src="taskmanager.js"></script> <!-- The compiled JS output from J2CL --> </body> </html>
2.3.1 Code Explanation
The provided HTML wrapper serves as the foundation for running a J2CL-transpiled Java application in the browser. It starts with the <!DOCTYPE html> declaration to ensure standards-compliant rendering, and includes a simple <head> section that sets the page title to “Task Manager”. In the <body>, it defines a <div> with the ID “app”, which acts as a placeholder for dynamic content rendered by the JavaScript logic generated from the Java code. The key part of this HTML file is the <script src="taskmanager.js"> tag, which loads the JavaScript output produced by J2CL from the TaskManager Java class. This script dynamically creates and injects the task input field, add button, and task list into the “app” container, enabling user interaction entirely driven by Java logic that has been compiled into optimized JavaScript.
2.4 How to Build and Run the Code?
To build and run the application, place your TaskManager.java file under src/main/java/com/example/taskmanager/ and your pom.xml in the project root directory. Then, run mvn clean package to transpile the Java code into JavaScript and generate the taskmanager.js file. Open the index.html file in a browser. You will see an input box and an “Add Task” button. Add tasks using the input field, and they will appear as a list below.
For example, if you input “Buy groceries” and click “Add Task”, the list will display: Buy groceries. Then, if you input “Walk the dog” and click “Add Task”, the list will update to: Buy groceries, Walk the dog.
3. Conclusion
J2CL offers a powerful and high-performance way to reuse Java code in modern web applications. It enables developers to write client-side logic in Java, benefiting from type safety, existing tooling, and shared logic with server-side code. Although setting up the toolchain can be slightly complex, the result is a seamless and fast application. With support from Google and the integration of elemental2, it’s a great tool for Java developers looking to build frontend applications without switching to JavaScript.




