Older versions: FAQ for version 1.x
JSweet is a Java to TypeScript/JavaScript transpiler that aims at programming modern Web and Mobile applications (i.e. HTML5+JavaScript) in plain Java, using our favorite Java IDEs. JSweet is fully open source (license details).
With JSweet, you can use JavaScript APIs and Java APIs together in the same Java program. JavaScript and Java objects are directly interchangeable and interoperable.
JSweet is an Open Tranpiler, which means that the generated intermediate TypeScript code can be tuned and adapted declaratively and/or programmatically.
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.
JSweet also provides support for Java APIs, with some limitations. This default support can be extended since JSweet is an Open Transpiler.
Here are JSweet (v2) main differentiation points:
In general, an Open Compiler denotes a compiler that provides an API to tune the way it works. This API can be used declaratively (often through program annotations), but can also provide a more in-depth tuning API through a compile-time reflection API. Having an Open Compiler can be really useful, for many use cases such as:
JSweet provides both declarative and programmatic tuning. Read the documentation on how to extend the transpiler.
JSweet provides the following packages:
jsweet.lang
: defines JSweet features (mostly annotations) for extending Java.jsweet.util
: contains the Lang
class that defines JSweet macros to map specific JavaScript syntactic language constructs (and also cast functions to map Java to corresponding JavaScript types).jsweet.util.function
: complements the common functional interfaces.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
.def.js
: defines the core JavaScript language APIs.def.dom
: defines the W3C APIs.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 core Java functions are supported, however, some variations/limitations may appear on numbers, especially when dealing with floating point precisions (Java doubles and floats cannot be mapped to JavaScript numbers). Also, all multithreading/synchronisation primitives are not supported. Finally, some work is still required for hashCode()
emulation, which is so far not fully supported.java.lang.reflect
: some very partial support is available, for introspecting methods and fields. Expect only basic operations to work.java.util
: in this package, collections and maps are almost entirely implemented by default, except for some utility methods (which can be easily added). Some variations have to be expected because of the hashCode()
limitation. Typically using objects as keys in map may behave wrong compared to Java (and should thus be avoided). On the other hand, dates and locales have a limited basic support, which needs to be extended if you want more extensive support.java.io
: some very partial support is available, by replacing streams with string or byte arrays (to be completed).java.math
: by default, big numbers are not supported, but JSweet comes with an optional adapter that can be activated to automatically map Java BigDecimal
to the Big.js JavaScript library.By default, JSweet will generate the needed JavaScript code without having to rely on a Java runtime/emulation. If you feel that your use case requires a JRE emulation, you can use the J4TS runtime, which is a fork from GWT’s JRE emulation. In that case, all you need to do it so add the J4TS candy/jar in your classpath and JSweet will automatically tune its generation strategy to use it.
Support for other JDK and external Java API is possible. You will find JSweet-supported Java APIs in the J4TS organization. For instance, the java.awt.geom package is fully supported, as well as javax.swing.undo. Both can be useful even for JavaScript and/or TypeScript applications.
Since JSweet wants to ensure a close interoperability between Java and JavaScript, JSweet does not fully emulate Java. Although close-enough to Java for many use cases, you have to be aware that JSweet’s goal is not to execute existing Java applications as is in the browser. Some rewriting will most probably be necessary, especially for the UI part if uses Java-specific APIs such as Swing. The good news is that JSweet is an Open Transpiler, and you can automate Java rewriting by implementing so-called adapters as explained in the documentation.
See the previous question first.
Most legacy programs will probably use Java libraries that are not supported yet. You can either support them by writing an adapter, or by providing a JSweet implementation in the J4TS organization.
First go to the JSweet candy repository and check if your library is not already available (see https://www.jsweet.org/jsweet-candies). If not yet there, here is what you can do.
def.myJsApi
package. Definitions are empty classes and declarations that act as headers. If your definitions map the target JavaScript API, your program will compile in a type-safe way and execute as expected. You can then contribute your definitions in the JSweet Candies organization.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. However, you have to take into account that if you have used many Java APIs, it may be harder to switch back to JavaScript (so prefer JavaScript APIs if you expect to switch back to JavaScript at some point).
Yes you can. JSweet generates TypeScript definition files, so that you can share these files across your Java programmers and TypeScript programmers and ensure that they share the same APIs.
Yes! JSweet automatically translates JavaDoc comments to JSDoc comments so that the generated TypeScript/JavaScript APIs are consistently documented and easily accessible to JavaScript developers and tools.
Yes.
By default Java lambdas are transpiled to arrow functions. So element.addEventListener("change", (event) -> { /* listener code here */ });
will transpile to element.addEventListener("change", (event) => { /* listener code here */ });
.
You can force the transpilation to a plain JS function by using the Lang.$noarrow(...)
JSweet macro. Typically, element.addEventListener("change", $noarrow((event) -> { /* listener code here */ }));
will transpile to element.addEventListener("change", function(event) { /* listener code here */ });
.
Yes, in general you can switch from plain Java object to JavaScript ones and conversely with so-called jsweet.util.Lang
. So, you can use native Java arrays and switch to JavaScript ones with array(...)
: def.js.Array
(see the jsweet.util.Lang
class for all the cast methods).
JSweet generates source maps. Hence, one can debug Java files in the browser as if it was JavaScript ones. 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 transpiler’s eval function and assertions. 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 { private static int a = 0; public static void main(String[] args) { assert a + 1 == 1; } }
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() throws Exception { TestLogHandler logHandler = new TestLogHandler(); 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 transpiler.eval(logHandler, SourceFile.getSourceFiles(new File("test/MainExecution.java")); logHandler.assertNoProblems(); }
Note that the eval
method also returns an evaluation result that contains data that is made available through the jsweet.util.Lang.$export
macro. For more details on how to write JSweet tests, please refer also to the contribution page.