Fork me on GitHub

Older versions: FAQ for version 1.x

What is JSweet?

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.

Why JSweet?

  • To write JavaScript applications with Java, using the JavaScript libraries.
  • To port legacy Java code, applications and libraries to the Web, with some limitations.
  • To make client-side JavaScript/TypeScript applications interoperate with server-side Java applications with shared and well-typed APIs and DTOs.
  • To generate JavaScript code that depends on the target (for instance, to optimize the code for mobile and embedded software running on a specific JavaScript VM).

How does JSweet work?

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.

How does JSweet compare to related tools?

Here are JSweet (v2) main differentiation points:

  • JSweet generates intermediate TypeScript code (including TypeScript definitions).
  • JSweet is a transpiler, not an emulator, and no runtime is required. It is possible to use the generated code as a new source base and drop Java completely.
  • It maps directly to JavaScript API, thus preserving interoperability with existing JavaScript libraries.
  • It is an Open Transpiler, easy to extend in order to tune the generated code and support new use cases (including Generative Programming).

What is an Open Transpiler and why is JSweet an Open Transpiler?

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:

  • extending the built-in support of existing APIs (for instance to add compile-time support to a new Java library, without requiring JavaScript runtime),
  • modifying the way the transpiler generates the code for targeting different execution environments (for compatibility and/or performance purposes),
  • add constraints, typing, checks, restrictions at compile-time in order to enhance code quality for your own specific use cases,
  • automate the generation of code from an existing code base (for instance, generating JavaScript JAX-RS client code from Java services).

JSweet provides both declarative and programmatic tuning. Read the documentation on how to extend the transpiler.

What are JSweet API packages?

JSweet provides the following packages:

  • Package jsweet.lang: defines JSweet features (mostly annotations) for extending Java.
  • Package 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).
  • Package jsweet.util.function: complements the common functional interfaces.
  • Package jsweet.util.union: defines union types.
  • Package jsweet.util.tuple: defines tuple types.
  • Package 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.
    • Package def.js: defines the core JavaScript language APIs.
    • Package 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:

  • Package 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.
  • Package java.lang.reflect: some very partial support is available, for introspecting methods and fields. Expect only basic operations to work.
  • Package 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.
  • Package java.io: some very partial support is available, by replacing streams with string or byte arrays (to be completed).
  • Package 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.

What are the known limitations to JSweet?

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.

Can I run existing Java programs with JSweet?

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.

What should I do to use a *JavaScript* library that is not currently supported by JSweet?

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.

  • The simplest way: define the JavaScript API in Java within your program in a 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.
  • The TypeScript way: if the library you need to access is quite big, you probably don’t want to write the definitions all by yourself. What you can do is find the TypeScript definition on the Web and use it to generate the JSweet definitions thanks to JSweet’s candy generator.

What should I do to use a *Java* library that is not currently supported by JSweet?

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.

  • Case one — compile the library with JSweet: if the library is open source or if you own the source code, you might be able to compile it with JSweet with no or little code modification. What you will get is a TypeScript/JavaScript version of your library (usable from any TypeScript or JavaScript program). Then, you just need to package it as a candy, similarly to what is done in the J4TS project.
  • Case two — wrap an existing JavaScript library: there are plenty of JavaScript libraries out there for doing almost everything. There is a big chance that the Java library you are trying to access to already has a JavaScript counterpart, and that this library is available as a JSweet candy. There is also a big chance that the API core functions only differ slightly from the Java version. In that case, all you need to do it to write a wrapper to the JavaScript library that conforms to the targeted Java API. Then publish this wrapper as a candy that depends on the wrapped JavaScript library.
  • Case three: when none of the above cases is possible, then you need to rewrite the library from scratch. This is of course a bad solution, unless the library is quite simple.

Can I get rid of JSweet and go back to classical Web languages in the middle of a project?

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).

Can I mix JSweet, TypeScript, and JavaScript code within the same project?

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.

Does JSweet support JSDoc?

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.

Can I use Java 8 lambda expressions in my JSweet programs and are they similar to JavaScript functions?

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 */ });.

Can I use Java arrays in my JSweet programs?

Yes, in general you can switch from plain Java object to JavaScript ones and conversely with so-called cast methods defined in jsweet.util.Lang. So, you can use native Java arrays and switch to JavaScript ones with array(...): def.js.Array arr = array(new String[] { "a", "b" }) (see the jsweet.util.Lang class for all the cast methods).

Can I debug my Java files directly in the browser or in Eclipse?

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.

Does JSweet support AMD, CommonJS, or UMD modules?

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.

Can write JUnit test for unit testing JSweet programs?

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.

JSweet is looking for a new maintainer/owner! If interested, please contact us at info@cincheo.com.More details...