JSweet is a project that aims at programming modern Web applications (i.e. HTML5+JavaScript) in plain Java, using our favorite Java IDEs. JSweet is fully open source, licensed under Apache License, Version 2.0.
For two reasons.
First, because with HTML5 and its new JavaScript API, modern Web browsers have become the most universal execution platform, efficient and plugable on most operating systems. For instance, the support of SVG and the canvas API allows the programmers to develop cutting edge UI, CSS transforms allows for animations that harmlessly take advantage of the GPU, CSS media queries supports adaptive design, debugging and profiling is natively supported by modern browsers, and so on.
Second, because Java remains the most efficient language for building complex applications, with its world-wide community support for various IDEs. Its simple syntax and strong typing (but not too strong), makes it a good compromise for most developer profiles. For instance, Eclipse’s Java incremental compiler and refactoring tools make Java the most comfortable language to handle the complexity of large scale projects.
In short, the idea behind JSweet it to take advantage of both worlds: Java for the coding, and JavaScript for the deployment and execution.
Any programmer who wants to build client-side HTML5 applications and who cares about advanced IDE support: incremental compilation, call graphs, inheritance graph, outlines, refactoring, completion, wizards, strong typing, etc.
In our opinion, the Java language offers the best IDE support, and will still remain ahead for a while, especially because the Java community actually do care about developing robust applications (more than developing good-looking ones).
JSweet relies on a Java transpiler built with Javac. The Java source code is transformed into TypeScript, which in turn is transformed into JavaScript. During the transformation process, the line mapping is preserved in a JavaScript map file so that you can debug your Java source code directly within your favorite browser’s debugger (or within your Java IDE with plugins such as SDBG).
JSweet provides a core API for dealing with specific JavaScript features such as arrays, global variables, etc. Also, it supports a large set of JavaScript APIs, which are directed transformed from existing TypeScript APIs (see DefinitelyTyped’s TSD) to well-packaged Maven artifacts, so-called JSweet candies. Thus, programmers have access to hundreds of JavaScript frameworks, components, and libraries directly from Java.
Java WebStart:
Besides the Java syntax, they have nothing in common. Java WebStart allows the browser to run native Java application within an embedded JRE. JSweet runs JavaScript code directly in the browser and the Java code does not use any of the Java SE API. Instead it uses the W3C standard WEB APIs. JSweet can provide support for Java APIs so that legacy Java applications running with WebStart can work directly in the browser. It is explained in this video.
GWT:
GWT takes Java code and translates part of it to JavaScript so that the client side application can run in a Web browser. GWT and JSweet are actually very different in their approaches, since GWT aims at providing a full Java emulation (following the Java Language Semantics). Also GWT is more of a framework than a language. It comes with a toolkit that binds the GWT programs to a specific API. It is very far from JSweet that simply intends to add a Java syntax layer to web programming. GWT approach of emulating Java is much more ambitious, but suffers from various drawbacks, the main problem being that the core GWT objects are an emulation of Java objects, which has direct impacts on:
More details on comparing JSweet to GWT can be found here.
In-browser Java VMs (Javapoly, doppiojvm, etc.):
Clearly, it is not JSweet purpose to emulate Java on top of JS. JSweet is a transpiler to generate and run pure JavaScript programs, not Java ones. Like for GWT, emulating Java is bad for performance and interoperability with JavaScript.
TypeScript:
JSweet can be seen as a syntax mapping to TypeScript. JSweet maps Java structures to TypeScript structures (modules, classes, interfaces, enums). It also support the same level of type safety by mapping to TypeScripts types (functional types, tuple types, object types, union types, etc.). So, using JSweet is very similar to using TypeScript to program JavaScript application. You can use the same tooling and, like with TypeScript, it is easy to bridge JavaScript APIs. The main difference besides the Java syntax is that with JSweet you can rely on the Java IDEs support and building tools such as Maven.
JSweet provides the following packages:
jsweet.lang
: defines the basic JavaScript APIs, plus core JSweet features (mostly annotations) for extending Javajsweet.dom
: defines the W3C APIs.jsweet.util
: contains Java API to map specific JavaScript language constructs (the Globals
class contains useful cast functions).jsweet.util.function
: complements the common functional interfaces (for basics, the program can use the java.util.function
package, and java.lang.Runnable
.jsweet.util.union
: defines union types.jsweet.util.tuple
: defines tuple types.def.<libname>
: the def
package is by convention used for external library definitions (i.e. JavaScript libraries APIs, a.k.a JSweet candies). For example: def.jquery
or def.angular
.Javadocs and candies are accessible at the candies page.
Also, JSweet allows the use of Java packages with some limitations:
java.lang
: by default, most basic functions on strings, objects, numbers, etc. It requires the J4TS candy for more extensive support.java.util
: requires the J4TS candy to support most collections and utility classes.java.io
: requires the J4TS candy to support some Java IO styles and a local-storage-based FS (beta).java.*
: generally speaking, most Java packages can be implemented in JSweet, following the way it is done in J4TS. Checkout this project and check if the Java feature you are looking for is already implemented in JSweet. If not, please request it or, even better, contribute to the project 😉The key point is that you have to remember that JSweet is *NOT* Java, it is Java syntax only. There is no deep Java emulation in JSweet and a running JSweet-generated program it actually a regular JavaScript program. There are many advantages to this approach, but it also means that there are small behavioral differences between JSweet and Java programs. For instance, JSweet cannot make a difference at runtime between a long and an int, which eventually impacts method overloading. Thankfully, JSweet makes sure that for most use cases, JSweet programs behave like Java programs, so that it is usually very straightforward to have the same code running in a JRE and in a JS container (if using APIs supported in both environments). JSweet provides some basic support to common Java APIs in the J4TS project, which is available as a candy (and more APIs should be supported in the future). Make sure to check the language specifications in order to fully understand the differences between Java and JSweet.
If your program only uses common Java APIs as implemented in J4TS, yes. Of course, most legacy programs will probably use plenty of Java libraries that are not supported yet. In that case, you need to provide a JSweet implementation of the libraries and publish them as JSweet candies (so that they can be used by other JSweet programs).
First go to the JSweet candy repository and check if your library is not already there (see https://www.jsweet.org/jsweet-candies). If not yet there, here is what you can do.
@Ambient
annotated classes and interfaces, so that you create a bridge to the existing library. By using @Ambient
, you can inline the external classes and interface declarations in your program.def.<yourlibname>
package. Consider creating your own candy within a Maven artifact, using this template, and don’t hesitate to contribute to the JSweet Candy organization. For details on how to define an API (definitions) with JSweet, please refer to the Language Specifications.First go to the J4TS organization and check if your library is not already there, maybe in the J4TS candy. If not yet there, you need to provide a JavaScript implementation of your Java library and publish it as a JSweet candy. This might be less complicated than it seems. First start from the following template. Then decide which strategy is best for you depending on your context.
Sure. You can stop maintaining your Java source code and use the generated TypeScript or JavaScript code as your new source base. JSweet can produce coder-friendly output by switching off the sourceMap
mode.
Yes you can. Since JSweet candies are generated from Definitely Typed definition files, you can share these files across your developer teams so that Java programmers and TypeScript programmers are ensured to use exactly the same libraries. Of course, you can also use JSweet to translate a Java model to TypeScript or JavaScript so that it can be used by the Web developers.
Yes, and yes. For instance: element.addEventListener("change", (event) -> { /* listener code here */ });
Yes, you can use native Java arrays and switch to JavaScript ones with array(myJavaArray)
(see the org.jsweet.util.Globals
class for all the cast methods).
JSweet generates source maps (thanks to the TypeScript compiler) and link them to the Java source code. Hence, one can debug Java files in the browser as if it was JavaScript ones. We recommend to use Chrome, because it supports Java syntax highlighting, but it is possible with all modern browsers. It is also possible to debug Java code in the IDE by using plugins such as SDBG.
Yes! JSweet relies on TypeScript that supports various JavaScript module management mechanisms. JSweet takes an option that allows the programmer to choose between the different module management kinds.
Sure. But at this point, it may require a little bit of work.
The first solution is to use one of the JavaScript Frameworks for unit testing. We are interested in any contribution that would explain how to use a JavaScript test framework under JSweet.
The second solution is to unit test JSweet programs from Java (with JUnit) by using the jsweet.util.Globals.$export
function, which makes values available to the caller Java program.
For instance, the following program makes available to the Java calling program the value “ok” in the variable “result”.
package test; import static jsweet.util.Globals.$export; public class MainExecution { public static void main(String[] args) { $export("result", "ok"); } }
Here is a typical JUnit test that uses the JSweet transpiler API to ensure that the main method is correctly executed:
@Test public void testMainExecution() { TestLogHandler logHandler = new TestLogHandler(); try { JSweetTranspiler transpiler = new JSweetTranspiler("outDir", null, System.getProperty("java.class.path")); transpiler.setModuleKind(ModuleKind.commonjs); // here, the transpiler uses node.js to evaluate the generated JavaScript EvaluationResult result = transpiler.eval(logHandler, "test.MainExecution.java"); Assert.assertEquals("There should be no errors", 0, logHandler.reportedProblems.size()); assertEquals("Main method was not executed", "ok", (String)result.get("result")); } catch (Exception e) { e.printStackTrace(); fail("Exception occured while running test"); } }
To get access to the JSweet API, add a dependency to the transpiler
artifact (group id: org.jsweet
), as shown in the following pom.xml
<project ...> ... <!-- repositories --> <repositories> <repository> <id>jsweet-central</id> <name>libs-release</name> <url>http://repository.jsweet.org/artifactory/libs-release-local</url> </repository> <repository> <snapshots /> <id>jsweet-snapshots</id> <name>libs-snapshot</name> <url>http://repository.jsweet.org/artifactory/libs-snapshot-local</url> </repository> </repositories> <!-- end repositories --> ... <!-- dependencies --> <dependencies> <dependency> <groupId>org.jsweet</groupId> <artifactId>jsweet</artifactId> <version>(current version)</version> </dependency> </dependencies> <!-- end dependencies --> ... </project>