GWT

Java to Javascript Conversion for Framework Developers

The Javascript engine is designed to allow you to flexibly expose Java apis for Javascript libraries, and run Java code in the browser. For most developers, you use the StrataCode command to compile and run your application and do not have to be aware of the details of how Java is converted to Javascript. This section describes the details for framework developers who want to add new libraries or who want to know more about the conversion process.

Framework developers that want to add new Javascript libraries write Java class stubs to wrap them. Instead of a complex native interface, you replace Java types with a Javascript implementation using the simple API mapping rules. To use JQuery in StrataCode for example, you would extend a JQuery layer which pulls in the necessary JS library files and exposes Java types which give you access to JQuery's features. At runtime, your generated JS classes will directly call the JQuery APIs in a more reliable way using Java's type system. If you need to write JS code for some reason, it can mix calls to the generated apis with calls to JQuery.

Packaging into JS Files

After Java files have been converted to JS, each type's JS code is stored into a temporary file. Those temporary files are then assembled into one or more JS files loaded by the browser. There are two mechanisms you can use for controlling how this packaging is performed.

One option is to use the jsModuleFile annotation on your classes. When you do this, all Java types using the same module are put into the same file. That file must have an ordered list of dependencies against all other types in how they are packaged in JS files.

By default, StrataCode figures out all of the entry points required for a given HTML file, and puts all unassigned Java types that are used by those entry points into that file. With this approach, types which are not referenced are not included in the resulting JS file making it smaller, but the resulting JS file is not reused and not cached in the browser.

Java Runtime

A subset of Java's utility libraries (ArrayList, HashMap, etc.) have been added to the framework. Those were all just copied from the apache Java project into the js/sys layer. When there are native dependencies in types you must simulate that code in native JS. The native Java types are hand-written in the file js/javasys.js.

Using the JS System

To use the JS library, include js.core for basic Java to Javascript functionality. Mark your type with @MainInit or just have a main method and it will be called by default after all of the types have been loaded.

Include the js.template layer if you want to use schtml files as well that are compiled to .java files, then to .js files for loading along with the default runtime.

There are two base layers which configure how template pages are assembled. In the js.allInOne layer, all of the code in the application is put into a single index page. This is great for test programs or those cases where an entire app is contained in a single page. The other mode, js.appPerPage, is included by js.template by defualt and generates separate javascript and HTML files for each template which defines the tag.

Controlling Compilation

The JSSettings annotation controls how your type is processed by the Javascript conversion engine.

The JSMethodSettings annotation is usually used for a type which set JSSettings.jsLibFiles. There are times when the name of the Javascript method conflicts with a field that already exists. For example, String.length is a field in Javascript but a method in Java. So an annotation layer for java.lang.String sets JSMethodSettings on the length method to _length(). That method is added to javasys.js for the prototype of the built-in String class.

Naming Conventions, and Runtime Rules

Most types use the prefixAlias feature to map a java package tree (e.g. java.*) into a prefix jv_String. The thinking is basically that two letters is all of the uniqueness that an application really needs for a package prefix, especially when it's configurable to work around the odd case. The global name space in Javascript is untenable without some unique prefix to avoid name conflicts, and even organize names.

Though a lot of Java code can be converted to Javascript unchanged, given the constraints of the Javascript runtime some changes in the type system will require changes in your code to get it to work. The main differences in the type systems are:

StrataCode initializes all fields with null before accessing them. If you hit "undefined" when accessing a field that should be there, that's a bug. Because of that assumption, it uses fieldName !== null instead of fieldName !== undefined in all comparisons.

Dependencies

At compile time, StrataCode computes the dependencies between each javascript file it processes, both those files specified as the jsFile annotation, those specified with jsModuleFile, and any default types. Default types may be included in more than one base file (for the appPerPage runtime) or they may be put into a default javascript file named: js/sc.js.

Within each file, the list of types is sorted so that super-types come before sub-types. Any javascript files which extend types in another javascript file will introduce a dependency between those two files. If you use jsModuleFile incorrectly, you can introduce cyclic dependencies between modules which is not allowed. Note that the dependency only exists when one type extends types in another file.

Future Optimizations

It would not be difficult to omit unused methods from the generated Javascript for a given compilation. This would thwart the sharing of js file modules between applications however.