It's been a long time, well long in Internet-years, since my last blog on JavaFX. Now I'm approaching JavaFX 2.0 by porting the JavaFX 1.x programs that I had written and blogged about here. These new ports will allow me to evaluate the evolution of the platform. Has the wait been worth it?

Porting from JavaFX 1

For my first port I’ve picked JavaFX Balls. (But this blog is not about benchmarking; I’ll do that in a follow-up.) The port cost me a couple hours of tedious, but easy massaging of the original code. JavaFX Script is sufficiently close to Java that you can rename a .fx file to .java and edit it until it becomes Java. Heavy editing, but better than a rewrite from scratch. The core APIs are 99% identical. There’s no much legacy out there, but this is nice evidence of JavaFX’s maturity: the team didn’t need to use the opportunity of the breaking-change v2 release for heavy API redesign. The major changes are all in features tied to special support from JavaFX Script’s syntax. But even in these cases, the new version is very familiar.

Functions

Java does not have an equivalent to JavaFX Script’s functions, but JDK 8 will have that, and its lambdas are tied to Single Abstract Method types. The JavaFX 2 API is carefully designed around SAM types; current application code will use loads of inner classes in the same places where JavaFX 1 code would use functions, but when JDK 8 comes we’ll be able to replace all those inner classes with lambdas – so losing JavaFX Script’s functions is a temporary setback.

             
JavaFX 1JavaFX 2



onKeyPressed: function (ke: KeyEvent): Void { … }

With JDK 8:

.onKeyPressed(#{ KeyEvent ke -> … });

With JDK 6..7:

.onKeyPressed(new EventHandler<KeyEvent>() {
  public void handle (KeyEvent ke) { … }
});

Initialization Blocks

I loved JavaFX Script’s syntax to initialize complex trees of objects, but that’s also gone, so I feared that my code would double in size. Not so much:

             
JavaFX 1JavaFX 2

public def fpsTimer = Timeline {
repeatCount: Timeline.INDEFINITE
  keyFrames: KeyFrame {
    time: 1s
    action: function () {…}
}}

private Timeline fpsTimer = new TimelineBuilder()
  .cycleCount(Timeline.INDEFINITE)
  .keyFrames(new KeyFrame(
    new Duration(1000L),
    new EventHandler<ActionEvent>() {…}
})).build();

The trick is obvious: the Builder pattern. This keeps code almost as tight as in JavaFX Script. The javafx.builders package offers 257 builders, covering all the APIs. I’m not fond of the Builder pattern; I loathe the extra allocations and calls with the single purpose of making code a little more compact. But UI-tree initialization is a best-case application for that pattern. As a minimal rule, avoid builders in performance-critical code, and in any reusable library. I hope visual designers will have an option to choose between readable/compact style (builders), and optimized style (constructors and setters).

You can mix styles – there is a KeyFrameBuilder, but I didn’t use above because KeyFrame contains several constructors, including one with all properties that I wanted to set. Avoiding the TimelineBuilder though, would require setter calls, because Timeline doesn’t offer constructor initialization for all fields or even the most important ones. This is a trait of JavaFX 2’s API design: most classes offer constructor initialization only for properties that can only be set at construction time – a convention that replaces JavaFX Script’s public-init visibility. But there are exceptions for struct-like classes, such as those in thejavafx.geometry package, that offer constructor initialization even for mutable properties.

Properties and Binding

Properties and binding are definitely the big loss, in syntax, from abandoning JavaFX Script. Compare:

             
JavaFX 1JavaFX 2

view = ImageView { image: image
   translateX: bind x + (view.scaleX - 1) * 25
  translateY: bind y + (view.scaleY - 1) * 25
};

view = new ImageView(image);
view.translateXProperty().bind(x.add((view.getScaleX() - 1) * 25));
view.translateYProperty().bind(y.add((view.getScaleY() - 1) * 25));

Not all Java fields can be binding targets, only those with special types like DoubleProperty. These are similar to the classic Java wrappers like java.lang.Double, except they are observable, and optionally mutable. The bind()methods’ single argument must be some observable type. Whenever the observable value changes, the property bound to it will also change. Properties can be bound directly to a observable value (bind(x) – “identity binding”), or to a more complex observable expression like the example: methods like DoubleProperty.add() don’t perform the actual named operation like addition, they build expression trees that can be evaluated later. In both cases,DoubleProperty.bind()’s parameter should be aObservableNumberValue<?>; this is a supertype of both my DoubleProperty x (so I can do identity binding), and of the expression tree produced by add(). To make this clear, this is the full hierarchy forDoubleProperty:

DoubleProperty

The support for properties and binding is extensive, spreading over three main packages (javafx.beans,javafx.binding and javafx.collections). The API has specialized classes, interfaces and methods for all base Java types, so you won’t pay the cost of extra boxing that exists with total reliance on generics. But don’t be scared by the size of the API; you’ll usually only need the *Property classes. All other types are there just for reuse, or static-typing for the binding and expression tree building APIs. The hierarchy is extensible (no final classes), so it’s useful to know it in more detail to create your own property, observable, or expression types. You don’t need to use*Property types all the time; instead oftranslateXProperty().get(), just callgetTranslateX(). See Mike Heinrichs’ introductionsto properties. The full power of JavaFX Script’s binding lives… except the convenient syntax.

Notice also that in my JavaFX 2 code above I didn’t use anImageViewBuilder, that’s because the builders’ chained setters only allow you to initialize properties with standard values, not with observable values. This would bloat the builder APIs, because Java’s base types are not extensible soObservableDoubleValue cannot be a subtype ofdouble or even Double – higher-level languages for the JVM may not have this problem. Implicit sharing of observable values, over repeated uses of the same builder object (a nice optimization especially inside loops), might also be confusing. You can still create the object with a builder, only the bound properties must be initialized after construction.

             
JavaFX 1JavaFX 2


public var nBalls:Integer on replace {
  N = nBalls;
  fpsTarget = 0;
}

With override:

IntegerProperty nBalls = new IntegerProperty(0) {
protected void invalidated () {
  Config.this.N = value.getValue();
  fpsTarget = 0;
}};

With explicit listener:

IntegerProperty nBalls = new IntegerProperty(0);
nBalls.addListener(new InvalidationListener<Integer>() {
  public void invalidated (ObservableValue<? extends Integer> value) {
    Config.this.N = value.getValue();
    fpsTarget = 0;
}});

Triggers are replaced by invalidation events. Besides declaring the *Property field, you must handle this event in one of two ways: either register an InvalidationListener, or define a subclass of the property overridinginvalidated(). The latter is much more concise, closer to JavaFX 1’s triggers; and lighter-weight, because the property’s internal listeners list won’t be allocated if no listener is installed. The event dispatch itself is basically just as fast in either case: different from most event listeners,InvalidationListener.invalidated()‘s parameter is not a special event object, it’s simply the “self” reference to the invalidated property (here,nBalls). There’s no per-event allocation.

One important advantage over JavaFX 1 is the higher level of control. Explicit invalidation listeners are a bit bulkier even with lambdas, but they allow extra flexibility – register and deregister listeners at any time; multiple listeners for a single property, single listener for multiple properties (that’s why the “self” parameter), capturing variables from a different scope than the property initialization scope, etc.

Properties: –verbose?

Some people have complained that JavaFX 2’s properties are too verbose. Overall, it’s true that the property / binding system adds more weight to the already-bulky Java Beans; Java really needs property syntax. Maybe JDK 8 will bring that. You don’t have to wait though; DSLs like Visage, or JavaFX bindings created with any language that offers either meta-programmingor operator overloading, should be able to eliminate the boilerplate, even in complex binding expressions.

But it’s worth notice that JavaFX properties can be programmed in several styles, from the more heavyweight to more lightweight:

  1. A full-blown, “API-quality” scheme with two private attributes, allowing lazy allocation of the *Propertyobject (at least for properties that are often not set by the user), like described by Mike Heinrich. Definitely significant extra code compared with the traditional Java Beans convention.
  2. The “standard” approach: the private*Property attribute, and getX(),setX(…) and xProperty() accessors. That’s just one method more than Java Beans.
  3. Only the private attribute and the xProperty() method – I’d rather name it just x(). Users will have to invoke x().get() and x().set(…) to access the value. That’s one method less than Java Beans.
  4. Only a public attribute. Just make it final, so users can’t reassign the property object itself. That’s two methods less than JavaBeans!

There are also other possible variations, remarkably using theReadOnly*Property and ReadOnly*Wrapper APIs – these come to replace JavaFX Script’spublic-read visibility. But considering the list of options above for simplicity, the amount of boilerplate code is proportional to functionality and design choices. Not all application beans have to be as thoroughly optimized, either for programmer convenience or performance, as the JavaFX APIs. Even the option of public attributes is not an absurd proposal – not even if you strictly adhere to Object-Oriented encapsulation dogma. Guess what, the *Property types allow you to keep encapsulation! Check:


public final DoubleProperty x = new DoubleProperty(){
    public double get () { return super.get(); }
    public void set (double v) { super.set(v); }
};

In the example (similar in structure to C# properties), I can add any code to the overriddenget() and set() methods, just like in Java Beans accessors. Of course, for the common need of reacting to value changes in the setter, JavaFX’s properties have a specialized notification mechanism. This style just won’t go well with inheritance, but this doesn’t matter: I always declare all my Java Beans accessors final; both because overriding these is not good OO in my book, and because polymorphic self-calls are dangerous in constructors – but constructors should initialize attributes with setters, to not risk skipping or duplicating setter’s logic like validation of illegal arguments.

The remaining issue is reflection or other dynamic mechanisms to discover and handle properties; supporting multiple possible coding styles would be harder than a single style, but not that much. The whole thing needs more radical improvements. Java Beans was already an afterthought; the API part (java.beans) was never a great design: partially obsolete, not a good foundation for higher-level features like validation, conversion or binding.

Whither Compiled Bind?

We lose JavaFX 1.2+’s compiled bind, still a work in progress but already quite good in v1.3.1 (JavaFX Balls was a benchmark of binding among other things!). But compiled bind had a cost; javafxc had many advanced optimizations for high-level language features (and still a good backlog of desired optimizations), but its optimizations often had major space or code-size tradeoffs. The good news is, JavaFX 2’s binding and properties don’t need those compiler optimizations. Everything is pay-as-you go: inx.add((view.getScaleX() - 1) * 25), notice the mix of methods like add() and operators like ‘–’ and ‘*’. JavaFX Script’s compiled bind was necessary because every variable was an observable value, so the compiler couldn’t trivially flatten sub-expressions to primitive operators. In JavaFX 2, the programmer does that optimization by judiciously using tree-building methods and observable terms only where necessary.

Beware of visual designers that may allow to write binding expressions but generate code that uses tree-building methods everywhere, or JavaFX DSLs that may reintroduce the weight of “every variable is observable”. Without compiled-bind-like optimizations, these tools may regress to the performance of JavaFX v1.0/1.1. At least for the Visage language, this is not a concern as it inherits javafxc’s technology for properties and binding (although seamless integration with the completely new system of JavaFX 2 may create some difficulties or overheads).

I could probably write a microbenchmark that shows JavaFX 2.0 much slower than 1.3.1 with intense use of complex binding trees. But that wouldn’t be realistic; in practice, the vast majority of bindings tend to be identity binding, or a trivial tree with one or two operators (“keep component X ten pixels below Y”). Then again, if you’re writing high-performance animation, in a system-level language like Java, then blind reliance on high-level features like binding is just wrong. My aggressive use of binding in JavaFX Balls was purposeful to stress-test the platform. I could have avoided all that binding easily; indeed, JavaFX Balls 3.0 can optionally do that, so I can measure the performance impact of binding.

Internally, JavaFX’s runtime contains a ton of code to handle all combinations of operations X observable data types (OK, damn primitive types!…). This code is massively redundant, I’m sure it’s based on template files and macro-expanded for all types. And I wonder if in a future version, most of it could be created dynamically – these days, runtime bytecode generation is just as fast as loading classfiles, and a dynamic system could bring back the Compiled Bind optimizations if at all necessary. JDK 7’s new great support for lightweight bytecode generation – method handles and anonymous classes – will enable a more efficient implementation of JavaFX 2, and also many other frameworks.

Even Better Beans Binding?

JavaFX’s property and binding packages can be used independently from the rest, and they are based on Java Beans, so you can benefit from this even if you’re not sold into the whole JavaFX platform. Higher-level features such as data validation and conversion are missing, but these could be easily built on top of the extensible property APIs. It’s just not a real beans binding framework because the *Property types are required; call that “Java Beans 2.0” if you like. It seems possible to add support to standard property types through additional property / observable / expression classes, using reflection to manipulate common bean properties; this may be a good compromise for some scenarios.

Besides the obvious advantages of having a unified API for properties and binding, JavaFX is also more powerful, type-safe, and efficient than existing options that I know. JavaFX’s package makes no use of reflection and it’s fully static-typed. As for boilerplate code, again I don’t see a better alternative with the current Java language syntax; only support from other JVM languages may improve on this. But the current design is the perfect match for the JVM and Java language’s own design and performance choices – the choices of a system-level library: features, performance and robustness first. You can easily wrap that in an Expression Languageor some other, higher-level layer, if you want.

Sequences and Generators

In a final exhibition of my bitter missing of JavaFX Script’s awesomeness, check this example:

             
JavaFX 1JavaFX 2
… in the middle of an initialization tree …

content: [ Group {
  content: bind for (b in test.balls) { b.view } },
…]

final Group ballsView = new Group();

test.balls.addListener(new ListChangeListener<Ball>() {
  public void onChanged (ListChangeListener.Change<? extends Ball> c) {
     final Node[] views = new Node[test.balls.size()];
     for (int i = 0; i < test.balls.size(); ++i) views[i] = test.balls.get(i).view;
     ballsView.getChildren().setAll(views);
}}
);

… then, in the middle of an initialization tree (with builder) …

.children(ballsView, …)…

This example mashes up everything. The new code suffers from the Java language’s lack of functions, binding, sequences and generators (or any special syntax for collections). But part of the problem is that JavaFX 2’s collections are still in flux. The EA builds had a Bindings.foreach() method that could save me some code, but this method was removed, and it alone wouldn’t completely solve the problem because the type ofGroup.children is just a ObservableList, not aListProperty – there’s no such class. There are alternatives like FilteredList andObjectProperty<T>, but again these don’t completely fill the shoes of a ListProperty. The design space here is difficult because JDK 8 will introduce a rich set of new lambda-based Collections methods, like filter(),map(), reduce() and forEach(), so it’s possible that JavaFX waits for that, to keep its collections aligned with Java’s.

JavaFX Script: Epilogue

In the average, no big loss in the syntax side. Some pros: I don’t have any more to pester the JavaFX Script team ;-) about operators or null handling. I don’t miss Java features, like generics, that JavaFX Script left out due to its focus on simplicity. The new APIs are all revved up to use advanced Java constructs (advanced? In the old APIs, absence of enums was irritating…). No half-baked concurrency; no missing basic features like a map type. We still need language improvements, but there’s progress; JavaFX 2.0’s FCS will actually happen after JDK 7’s so the first batch of apps can already pick up the Coin features, and by that time JDK 8 will be closer with lambdas and other improvements.

The hidden overheads of many JavaFX Script features are gone too. Compiled code is now as tight and fast as possible in the JVM platform. Extra productivity indulgencies will soon be provided by DSLs, libraries in extensible languages, or design tools. By the way, any language that makes your jar files several times bigger than a Java equivalent, and also carries a multi-megabyte runtime, is a hard sell for any target that’s sensitive to loading time and footprint.

Digression: Fixing an old performance bug

I’ve inherited the classic Bubblemark collision-detection code that’s very simple – each ball is hit-tested to every other ball after it in a list (a Bubble Sort pattern). The original benchmark was limited to 128 balls (16K hit tests), and I’ve raised that to 512 (260K tests), a bit taxing but still viable. JavaFX suffered more than other platforms due to property & binding overheads, but even with this handicap it led the competition so I didn’t care to optimize. ;-) Now for JavaFX 2 I wanted to raise the max count again, but then the program hit a brick wall: 4,096 balls needed 8M hit tests per frame, or half a billion for a 60fps goal – impossible. You can only go so far with an O(N2/2) algorithm.

There are many ways to skin this cat, and I decided for a simple spatial index. I also noticed that each ball could bounce many times in a single frame, useless for realism (doing thatright, like in a physics engine, would need extra work). So I’ve added a simple bounced flag to the balls; each ball that bounces against a wall or any other ball is marked and never hit-tested again in the same keyframe. This trick reduces the hit tests, towards a limit of O(N) as scenes get denser. But for non-aberrant densities, the spatial indexing is still much more scalable: the brute-force algorithm improves from 8M to 2,7M hit-tests/keyframe, but the indexing reduces it a thousand-fold to ~8,400.

Concurrent Rendering

The first thing you will notice in JavaFX 2 is that it does event handling and rendering in different threads. And you will notice that… drum roll… because it will likely break your code – either legacy code ported from JavaFX 1, or new code written with old habits in mind, from Swing or other single-threaded UI toolkits or game engines. It certainly broke my initial port of JavaFX Balls (see next section). The JavaFX 2 runtime manages two threads:

  • The EDT (event dispatch thread), identified as the “JavaFX Application Thread”.That’s where all your app code runs by default, including animation events (Timeline action handlers) or any other events.
  • The Renderer thread, identified as “QuantumRenderer”. That’s where your scene graph is transformed, composed, rasterized etc., until you get nice pixels in the screen.
  • The Media thread, identified as “JFXMedia Player EventQueueThread”. This takes care of video and sound playback tasks, such as decoding and buffering.

This is a powerful architecture; multicore CPUs are now the rule even in high-end mobile devices, so if your app leaves at least one core free, you get rendering “for free”. JavaFX’s Prism toolkit is fully GPU-accelerated, but the concurrent renderer is still important, because JavaFX’s rendering is not only rasterization; it involves higher-level steps like CSS-driven layout, scene graph transformation, resource and state management, caching, etc. Compared to other GPU-accelerated platforms, JavaFX has the extra advantage of offloading this high-level rendering from the EDT, increasing multicore efficiency without any effort or risk. Not to mention “business” machines without appropriate support for full GPU acceleration; in this case JavaFX will do software rendering, and if the system has at least a dual-core CPU (or even a single-core but hyperthreaded clunker), the concurrent rendering will provide some advantage.

There are still APIs like Platform.runLater() andjavafx.async; you don’t want to perform slow operations like I/O in the EDT to avoid unresponsiveness to user events. And you can also tap into the full power of JavaSE’s concurrency.

New rules for Timelines

The disentanglement between rendering and event processing results in other benefits. In JavaFX 1, a keyframe that should fire 10ms from now might actually fire only after 15ms, due to high CPU usage or latency from the renderer. Timeline actions ran in lock-step with the renderer, so a low rendering framerate would cause skipping (if allowed byKeyFrame.canSkip), and often need special care from the programmer. Interpolators automatically keep track of the actual firing rate and compensate for jitter and delays, but interpolators are more limited and less general than custom timeline handlers.

In JavaFX 2, your keyframes will always fire exactly when they should fire (unless of course, your EDT is bogged down by some other code – but then, that’s your fault). KeyFrame doesn’t have a canSkip property anymore. For JavaFX Balls, one important consequence is that I can’t use a timeline to measure the animation’s FPS; I used to do that counting the activations of the main animation handler per second. But that code was bad and obsolete even in JavaFX 1; I should use the PerformanceTracker class, which I’m finally doing now. (This is still an internal API, but you can also activate an MBean and get performance data through JMX.) By default Prism v-syncs, so you can’t get more FPS than your monitor’s refresh rate. This can be configured, but the default is the right choice for “real world” apps; and also for good benchmarks, that should lock FPS to typical monitor frequency and stress extra work per frame.

In a final surprise, even with the new hit testing code, the program was still slow in my first tests with high ball counts. Slower than JavaFX 1.3.1!!, what was wrong? It turned out, another side effect of the new concurrent architecture. My old code used aTimeline with a frequency of 1,000 Hz to move the balls (including hit-testing), but in practice this frequency was throttled down to whatever ratio the animation engine could sustain. This reduced the overhead of moving, hit testing, bouncing, and updating view nodes. At 1,000 Hz, the 4,096-balls test (large screen, 1/4th-size balls) would need 8,5 million hit-tests per second.

The solution is obvious for any seasoned game programmer. Instead of a fixed-frequency timeline, I bind the animation to the renderer, to update the scene exactly once after each frame – the well-known “game loop”. How to do this:


new AnimationTimer() { public void handle (long now) { … }}.start();

The new class AnimationTimer is similar toThread, except that it’s scheduled by the animation engine: its handler() method is invoked once after each frame is rendered. This reduced my animation overhead in 16X for a 60fps animation – only 0,5 million hit tests per second; performance was finally normal (and way better than JavaFX 1, as I will soon report). Different from a thread but more similar to a timeline, the same timer can be stopped and started multiple times.

Video and Audio

Motivated by other benchmarks such as Microsoft’s FishBowl, and also curious to have a feeling of the new media stack, I decided to add some gratuitous media to the program. So now when you run JavaFX Balls, press ‘V’ to add a background video behind the balls, and press ‘A’ to enable a ticking sound for ball collisions. (For nostalgia’s sake, I’ve linked to the promotional video from JavaFX 1…)

JavaFX

The video worked as expected, and without significant performance overhead. In one 4,096 balls test, performance dropped from 49fps to 48fps. But then, JavaFX 1 already had video support that was good enough for my usage here.


private static void flipVideo () {
    if (commandLock) return;
    commandLock = true;
  
    if (balls.getChildren().size() == 2) new Task<Void>() {
        protected Void execute () throws Exception {
            final MediaView mv = new MediaViewBuilder().mediaPlayer(
                new MediaPlayerBuilder().media(new Media(“http://…”)
                .autoPlay(true).cycleCount(MediaPlayer.INDEFINITE).volume(0.5).build())
            .fitWidth(Ball.WIDTH).fitHeight(Ball.HEIGHT)
            .opacity(0.25).preserveRatio(false).build();
            Platform.runLater(new Runnable() { public void run () {
                balls.getChildren().add(0, mv);
                commandLock = false;
            }});
            return null;
    }}.start();
    else {
        MediaView mv = (MediaView)balls.getChildren().remove(0);
        mv.getMediaPlayer().stop();
        commandLock = false;
    }
}

The code above either adds a MediaView to the scene graph, or removes it (so the ‘V’ key toggles video on/off). I initialize theMediaView object in an asynchronous Task, because it’s not a guaranteed-low-latency operation and I don’t want to block the EDT. When that’s complete, I must go back to the EDT with Platform.runLater(), to add the media node to the scene graph. I also keep acommandLock flag that, when set to true, causes any concurrent video-toggling to be ignored, while allowing other events to be processed along a slow initialization of theMediaView (always possible with a remote resource). These techniques and best-practices are of course, no surprise for veterans of Swing or other toolkits.

Audio is harder business, due to the requirements of low latency, light weight and scale (support a large number of playbacks at the same time or in quick bursts). JavaFX 1’s media stack simply didn’t have this capability; it was good enough for a great music application, but not good enough to implement even the simplest games with trivial sound effects (ever wondered why not a single JavaFX 1 game sample had sound?). The old media stack didn’t even support the WAV format, which is preferred for sound effects. JavaFX 2’s full-new media stack, based on GStreamer, should fix these limitations.


AudioClip acTick = new AudioClip(…URI…);

acTick.play();

The low-latency API is as simple as it gets: AudioClipkeeps the entire audio media in memory and in uncompressed form; this is essential for minimum latency, so when you callplay() there is no I/O, no buffering and no decoding. I’ve tested it in JavaFX and the first impression was pretty good. Well, except that the brand-new media stack shows its early status in two bugs that I’ve reported: one was a JVM crash (with an EA build – possibly gone in the Beta), and another, a latency problem (still possible to observe in the Beta). The only “new” part of the media stack is the glue between GStreamer and the rest of JavaFX; so I expect that these bugs will be shook out quickly. Meanwhile, I’ve worked around the latency bug once again with an asynchronous task, but this should not be necessary: you should be able to just call play()from the EDT; that method should return immediately, just enqueuing the clip for the JFXMedia thread.

UPDATE: This bug was just fixed, now a cal toplay() is basically zero (small enough to be difficult ot measure due to the accuracy of System.nanoTime()). The fix will be available in a future beta refresh, so I'm removing my workaround and just playing the clip from the EDT.

Odds and Ends

If you have read so far, congratulations for not TL;DR on me! ;-) As a bonus, some items that may deserve deep analysis in further blogs:

  • Great Browser deployment. The new “plugin3” is once again (and as expected/promised) much better than before; another significant step after JDK 6u10’s plugin2. Oracle finally hit the nail on the head, it’s (at long last) in the same league of Flash. Most pending problems discussed here are gone. Only the ultra-cold-start scenario, requiring installation of the JRE and/or JavaFX runtimes, cannot be tested at this time.
  • JavaSE as we know it is deprecated. I wonder how many people realize this; if you don’t, check again Cindy Castillo’s great overview of the JavaFX Architecture. It’s not just a new library of components, animation and rich media. It’s something thatcompletely replaces: AWT, Java2D, Swing, Java Sound, Applets, ImageIO, Acessibility – in short, the entire Client layer of the JavaSE platform. (No, a JavaFX “applet” doesn’t use the java.applet API anymore.) Oracle got rid of the massive legacy of the AWT and everything that was built on top of the AWT; that’s the major reason why the new browser plugin is much better.
  • JavaFX’s runtime is not small, but it largelyreplaces, not adds to, the JRE. Corollary of the previous item. And most of the replacement is much lighter-weight, remarkably due to effective hardware acceleration and massive reliance on native code: the installed Win32 runtime has 14Mb of DLLs, impressive even though this includes the 7Mb WebKit and new versions of deployment components that override the JRE’s. The overall dynamic footprint is down from similar JavaSE applications; the loading time, remarkably improved too. The runtime installer still weighs in almost 13Mb; it may shrink by 1-2Mb after it can rely on newer JREs containing the new deployment parts, but that’s still a nontrivial download size (and this Beta is not yet feature-complete, not to mention future releases). On the other hand, we can expect all sorts of “privileges” like JRE bundling and OEM distribution, so installer size won’t be a big deal.
  • Swing supported, but still in legacy mode.JavaFX 2 did the pragmatic thing here, supporting Swing as well as possible with zero compromises of the new architecture. There’s improved, official support to embed JavaFX components in Swing apps. JavaFX 1’s preview-quality support for the opposite embedding of Swing components in JavaFX scenes is gone as I predicted (just not reasonably possible with Prism). Swing applications that just need a bit of glitz – like a business chart, video playback, or web browser component – will be well served by this support, even if that’s coarse-grained and carrying the still-remaining limitations of embedded “heavyweight components”.
  • The mysterious platforms. The “all screens of your life” plan (JavaFX Mobile & TV) was a flop, at least as originally envisioned. But Richard’s blog mentions that JavaFX will support not only Windows + OSX + Linux, but also “a whole host of different platforms”. Which ones? Even Linux is barely worth the effort, except to court developers (the few Unix-loving Java developers not yet defected to OSX...) Solaris could be in line too just because it belongs to Oracle. But I can’t see anything else to complete that “host”, unless we move to post-PC devices (tablets, TV, etc.). Let’s just wait and see.

Finally, the JavaFX Balls 3.0 application is not yet available; I should publish it soon, in a follow-up blog looking at performance.