Bck2Brwsr
From APIDesign
During my duties at JavaOne2012 my feeling (primed by observing various RSS feeds full of posts about something which ends .js) that Java is no longer as cool as it used to be straightened. It always starts by loosing interest of newcomers, targeting just a piece of the technology segment and soon once Good Technology becomes new COBOL. Can that happen to Java? Just read Is JavaScript the Future of Programming? and (if you like Java), you'll get scared. I decided to do something about that. I'd like to return my favorite programming language Bck2Brwsr.
Contents |
Goals
Create small Java (check the Bck2BrwsrJavadoc) capable to boot fast and run in 100% of modern browsers including those that have no special support for Java.
Demonstrate that Java has benefits over JavaScript when creating larger HTML5 applications.
Unlike other similar efforts, the goal of this project is not to execute any existing Java library. It is expected that libraries for the new, limited environment need to be specially designed.
Demo
The current flagship demo is MineSweeper running in the browser: http://xelfi.cz/minesweeper/bck2brwsr/
As a memento it makes sense to keep in mind the little calculator demo showing the first application that I managed to get running in the browser. The application is packaged in a JAR file and the Bck2Brwsr VM loads necessary classes and transforms them into JavaScript on the fly.
There is/was (relatively) enhanced Twitter demo showing various technologies including JSONP communication with the server. However as Twitter abandoned its authorization free API in May 2013, the communication with the server is broken.
For JavaOne2013 I developed a chess application showing use of knockout.js from a Java code. See Knockout4Java.
To demonstrate my geolocation API, I created another Where are you? demo.
We also managed to port JavaFX to Bck2Brwsr and here is a proof of that. There is an overhead to load JavaFX scene graph API, so excuse slight delay when downloading and booting the app. When finally running, the performance should be OK.
Try It Yourself!
It is simple to try Bck2Brwsr! The project skeleton is provided as Maven archetype. The use of the most recent one is described in Knockout4Java page. There is another one (with more experimental features) described at Bck2BrwsrViaCLI.
What is in New Releases?
In Progress Release 0.11
The new version fixes problems with obfuscation mode (a regression in Bck2Brwsr 0.10). Now the final application can be FULLy obfuscated and the sample org.apidesign.html:knockout4j-archetype:1.0 seems to work with version 0.11. System has nanoTime method (per requests of Toni Epple). Iterating through JavaScript or Java array
var array = [1, 3, 5] for (var i in array) { console.log(i); }
shows only 0, 1, 2. All additional Bck2Brwsr functions are added as non-enumerable.
Release 0.10
The ahead-of-time mode has support for JDK8's Lambdas (thanks to RetroLambda project). Following example properly returns "XXXXXXXXXX" in Bck2Brwsr 0.10 when compound methods is called:
private static void fewTimes(Runnable r, int cnt) { while (cnt-- > 0) { r.run(); } } public static String compound() { StringBuilder sb = new StringBuilder(); fewTimes(() -> sb.append('X'), 10); return sb.toString(); }
My experience from implementing lambdas in Bck2Brwsr VM was so horrible that I had to express my hate of invokeDynamic in a dedicated essay. Such instruction should have never be added into the JVM specification! See the Lambdas Go Bck2Brwsr video:
Support for JDK8 defender and interface static methods. In the following example the method defaultValue properly returns 42 in Bck2Brwsr 0.10:
public interface Value { public static int staticValue(Value v) { return v.value(); } public default int value() { return 42; } public static int defaultValue() { return staticValue(new Value() {}); } }
The support for lamdas does not mean Bck2Brwsr 0.10 supports JDK8 APIs. It does not. The libraries are still subset of JDK7 - one can use lamdas only in own code so far. Technically it should not be a problem to backport JDK8, libraries - it just has not been done yet.
Using Object.defineProperty to make sure the JavaScript Object has all the methods of Object, while those methods do not show up during iteration
for (var p in anObject) { console.log('A prop found ' + p); }
Release 0.9
Version 0.9 eliminates useless stack assignments. Instead of doing
var stI0 = lcI0; var stI1 = lcI1; var stI0 = stI0 + stI1; return stI0;
the now generated code is
return lcI0 + lcI1;
which is shorter and more human readable. However I doubt the V8 virtual machine sees any benefits - I think the final native code remains the same. But at least the debugging of the generated JavaScript code is now easier - there is less Step Over invocations and it mimics more closely the original Java source.
Optimized the ahead-of-time compilation, so now the
http://xelfi.cz/minesweeper/bck2brwsr/
demo starts up instantly. I had to do it, because it was so embarrassing to see TeaVM to boot the same application so quickly: The initial delay is gone, and moreover it downloads necessary libraries in parallel and on background. Now we are ready for next step: share the libraries between different applications.
Can ObfuscatePerLibrary - e.g. each JAR gets compiled ahead-of-time into its own JavaScript file, which can be shared between many applications.
Release 0.8.1
- Supports latest Html4Java revision 0.7.5
- Now we can run JavaC in the browser.
- Many new JDK classes implemented - see at github
Release 0.8
- this is the JavaOne2013 version
- comes with nice NetBeans IDE integration, see plugin portal page.
- sound API
- geolocation API
- Support for smooth communication over WebSocket protocol
Release 0.7.2
- Donated our JSON4Jersey mappings to Jersey project (pull request has been accepted) for Jersey 2.1
- Support for different HTTP methods (like PUT, PULL, etc.)
- Knockout4Java Archetype for dual profile project (FXBrwsr as well as Bck2Brwsr)
- Better support for Boolean mapping in Bck2Brwsr VM
- FXBrwsr launcher stops the HTTP server when the FXBrwsr window is closed
Release 0.7
- FXBrwsr with full debugging support and a demo
- Dual Twitter demo - single source code, dual deployment (watch the same demo)
- Lightweight, generic JSON <-> Java mapping: javadoc
- ProviderAPI and a TCK to bind to other technologies than Bck2Brwsr, Knockout.js and FXBrwsr: javadoc
- Follow naming convention -- now bck2brwsr-maven-plugin -- thanks to Miloš Kleint
Release 0.6
- Full featured demo Twttr demo
- Bck2Brwsr provides better binding of complex classes (defined by a special @Model) annotation
- The @Model classes can be obtained from a server via JSON and JSONP. Use @OnReceive annotation
- Browser testing harness has nicer output with UL and expandable LI
Release 0.5
- Bck2Brwsr 0.5 has better support for MVVC via Knockout.js - see the calculator demo version 0.5
- Binds String and primitive types
- Bind array types (exposed as List
- Basic binding of complex classes
- Separate module for Maven archetype called org.apidesign.bck2brwsr:bck2brwsr-archetype-html-sample (and thus instructions for getting Bck2BrwsrViaCLI has changed)
- Improved speed of Bck2Brwsr virtual machine via better control flow
- Can use Closure compiler to generate more compact code
- One incompatible change: AnnotationProcessor for the @Page annotation no longer capitalizes field names found in the HTML page. This was meaningful when the fields were static constants. Now (when they are plain instance fields) it makes little sense.
Release 0.4
0.4 is the first release we managed to upload to java.net Maven repository. Heuréka! See Bck2BrwsrViaCLI for simple three steps towards using this version of Bck2Brwsr.
What you can expect? It works. It is sometimes not fast. It is sometimes broken (what would you expect after four months of development?). Errata:
- When you create new project and want to use it in NetBeans, you need to update nbactions.xml file to refer to 0.4 version, rather than 0.3-SNAPSHOT.
Here is list of achievements for the 0.4 version:
- Throwing and catching exceptions by Tomáš Z., finally block by me.
- Support for converting ByteCode in the browser
- Speed via register based system - Ľubomír finished first version of his register based rewrite on Dec 14, 2012.
- Speed benchmark and infrastructure to measure it in various environments - Martin Š.
- Run with -Dvmtest.brwsrs=firefox,chromium-browser (or any other browsers you want to test)
- Maven archetype for creating the calculator like demos
- Int32, Int16, Int8 arithmetics done by Martin Š.
- API for drawing on the canvas: Thanks Toni! Read about his experience using Bck2Brwsr.
- More precise int64 support - Martin Š. working on
- Convertor from GWT's native code to Bck2Brwsr's @JavaScriptBody - is sort of there, but not really functional.
- Fields of same name in subclasses. Thanks to Bck2BrwsrMangling.
- Compatibility tests can be written with help of @Compare annotation
- Basic reflection support (e.g. Bck2Brwsr throws SecurityException when allowed),
- Done: Class.newInstance() works.
- Done: Class.getMethods() works (returns only public methods)
- Done: Annotations of classes and methods
- Support for MVVC like Knockout.js that binds String and primitive types
- Packages into a static website via JAR files (which then take long time to inflate)
- Implements java.util.zip APIs
Done, not yet released
Version 0.9 eliminates useless stack assignments. Instead of doing
var stI0 = lcI0; var stI1 = lcI1; var stI0 = stI0 + stI1; return stI0;
the now generated code is
return lcI0 + lcI1;
which is shorter and more human readable. However I doubt the V8 virtual machine sees any benefits - I think the final native code remains the same. But at least the debugging of the generated JavaScript code is now easier - there is less Step Over invocations and it mimics more closely the original Java source.
Optimized the ahead-of-time compilation, so now the
http://xelfi.cz/minesweeper/bck2brwsr/
demo starts up instantly. I had to do it, because it was so embarrassing to see TeaVM to boot the same application so quickly: The initial delay is gone, and moreover it downloads necessary libraries in parallel and on background. Now we are ready for next step: share the libraries between different applications.
Can ObfuscatePerLibrary - e.g. each JAR gets compiled ahead-of-time into its own JavaScript file, which can be shared between many applications.
TODO
Although the system is capable to run and execute trivial applications, there remains tons of things to improve and fix. Any help is welcomed. Just let me know if something interests you:
- Access to multipage via sammy.js or crossroads.js
- Method and field overriding with various modifiers
- More reflection support (e.g. don't throw SecurityException when allowed),
- No private method/field/constructor/class access
- Probably no field access
- May need constructor access
- Debugger of Java (and not JavaScript would be good)
- Performance benchmark Sci2000
- Investigate generating asm.js friendly code
- Generate Java wrappers for all HTML5 elements dynamically (Honza)
Resources
- Project page at html.java.net
- Mailing list and its archive
- Source code
- Hudson jobs
- Maven Repository at java.net
- Javadoc
- Bugs are in java.net's bugzilla