Skip to main content

JavaFX 2.0 Beta: First impressions

Posted by opinali on May 28, 2011 at 3:32 PM PDT

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 1 JavaFX 2

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

With JDK 8:

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

With JDK 6..7:

.onKeyPressed(new EventHandler() {
  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 1 JavaFX 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() {…}
})).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 the javafx.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 1 JavaFX 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 a ObservableNumberValue; 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 for DoubleProperty:

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 of translateXProperty().get(), just call getTranslateX(). See Mike Heinrichs’ introductions to 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 an ImageViewBuilder, 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 so ObservableDoubleValue cannot be a subtype of double 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 1 JavaFX 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() {
  public void invalidated (ObservableValue 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 overriding invalidated(). 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-programming or 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 *Property object (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 the ReadOnly*Property and ReadOnly*Wrapper APIs – these come to replace JavaFX Script’s public-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 overridden get() 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: in x.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 Language or 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 1 JavaFX 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() {
  public void onChanged (ListChangeListener.Change 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 of Group.children is just a ObservableList, not a ListProperty – there’s no such class. There are alternatives like FilteredList and ObjectProperty, 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 that right, 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() and javafx.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 by KeyFrame.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 a Timeline 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 to Thread, 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 the MediaView 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 a commandLock 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 the MediaView (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: AudioClip keeps the entire audio media in memory and in uncompressed form; this is essential for minimum latency, so when you call play() 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 to play() 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 that completely 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 largely replaces, 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.

Comments

<p>The following bindings are not fully ...

The following bindings are not fully equivalent:

opinali wrote:

JavaFX 1 JavaFX 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));

This is not a full equivalent, it has no binding over view.scaleX and view.scaleY variables. If view is a constant, you could fix it this way:

view.translateXProperty().bind(x.add(view.scaleXProperty()).subtract(1).multiply(25));

If view isn't then you need to use Bindings.select() method.

<p>&nbsp;[quote=opinali]&nbsp;(No, a JavaFX ...

opinali wrote:
(No, a JavaFX "applet" doesn't use the java.applet API anymore.)

What does it use then? How can a JavaFX applet communicate with the DOM? Got an API link?

<p>I'm not sure, I haven't investigated this and the current ...

I'm not sure, I haven't investigated this and the current javadocs have major holes. But I suppose you will just use the javafx.scene.web. This is the API to control an embedded web browser, but in the case of applets that run inside a browser, I suppose the same API would allow to connect to the containing browser so you'd just use WebEngine methods to set events, etc.

<p>&quot;Java does not have an equivalent to JavaFX ...

"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."
I stopped believing that Java will ever get lambdas. The current spec and proposal is so downright bizzare, that it will never any pass QA. Java chose to have Checked Exceptions, that means that Lambdas (short of explicitly not supporting anything throwing CEs) can't be reasonably supported.
Reasonable == not jokes like:

public static &lt;T, throws E extends Exception&gt; T withLock(Lock lock, #T()throws E block) throws E {
    lock.lock();
    try {
        return block.invoke();
    } finally {
        lock.unlock();
    }
}

or
Locks.&lt;throws IOException|NumberFormatException&gt;withLock(lock, #(){
    System.out.println(&quot;hello&quot;);
});

So my conclusion is that JavaFX used with the Java language doesn't make any sense at all, except for some hardcore Java-lovers
"Even Linux is barely worth the effort, except to court developers (the few Unix-loving Java developers not yet defected to OSX...)"
Pulling a Jon Gruber here?

<p>Rest assured that lambdas are coming; and if you haven't ...

Rest assured that lambdas are coming; and if you haven't been noticing, Oracle's major Java projects (JDK 6 and 7, Glassfish, JavaFX) have been running like clockwork since the last stages of Sun acquisition were completed... I know that's not a long time ago (roughly one year), and public perception is even less time due to the last schedule changes in both JDK 7 (postponing lambdas to JDK 8) and JavaFX, both near the end of last year. But these decisions had been some time in the making, for one thing I have reasons to believe the new plans for JavaFX were already being discussed as early as before v1.3.1 was finished. Oracle just doesn't preannounce things. ;-) Right now, JDK 7 seems to be on schedule like trains in London, and the lambda compiler is already looking pretty good although I haven't had much time to track that in detail. But the community will need some more time (after the last difficult years of Sun) to believe in the announced schedule for the next version of anything.

As for lambdas vs. exceptions... your example is very outdated, function types are over, lambdas can only by typed by SAM-types. Check the Exception Transparency proposal.

<p>My comment wasn't related to function types and I think ...

My comment wasn't related to function types and I think the code you linked to doesn't look any better:
[prettify]&amp;lt;T, throws X, throws Y&amp;gt; T executeOne(Block&amp;lt;T, throws X&amp;gt; first, Block&amp;lt;T, throws Y&amp;gt; second) throws X, Y { if (randomEvent()) first.invoke(); else second.invoke(); } [/prettify]
This is not something where Oracle can throw a "few more people" in to make development go faster. Not a single proposal or spec draft I have seen is even remotely sound and doesn't come with a huge list of "open issues".
Even without any sensible spec it will take years to get the compiler stable again after lambdas were introduced, so I predict that lambdas will either be delayed, Java 8 will be delayed or lambdas will be dropped completely.

No worry, no "more people" required at all, and I still ...

No worry, no "more people" required at all, and I still think you haven't been tracking the progress of lambda. Don't judge it only by the public specs and blogs, these haven't been updated as often as they should - which has been reason for criticism; Oracle is just doing most work internally, both spec and implementation - but we can still track it by announcements in lambda-dev and code pushes. I feel the core language spec and compiler will be mostly complete by the end of this year. The major "action" for JDK 8, from Q3 forward, will be in areas like APIs ("lambdification" of existing APIs; a full formal spec; creation of new APIs that take great advantage of lambdas - like Collections extensions via defender methods), and Jigsaw (which seems to be a much bigger effort than lambdas).

<p>&nbsp;Java SE is deprecated? &nbsp;Is there an official ...

Java SE is deprecated? Is there an official announcement?
I read your link to the architecture description, it's reassuring to see that Java2D is retained, at least as a rendering pipeline. I've probably missed something otherwise, as JavaFX seems oriented around the scene graph idea, which is fine for people doing flash-like stuff, but not as general purpose as the more flexible low-level Java2D (which is very useful for business and science). As a comparison, up until HTML 5, the web browser was an elaborate scene graph with which developers fought until finally we had access to Canvas...
Also, while it's nice to be able to apply CSS themes to JavaFX, does the default look manage to look like the host platform's UI? Swing as of Java 6 was actually very good despite popular misconceptions (it's possible to be more like a "Windows app" than with .NET). The original version of Swing didn't mirror the UI of the host platform and had difficulty tracking it, which turned out to be more important than theming in practice for a lot of use-cases.
And what's this nonsense about "Linux users just have Mac envy"? I have access to Mac, Windows and Linux on my MacBook pro via VMWare fusion (and natively on other devices), and while there are nice things (for a developer) - I like OmniGraffle - Finder is just rubbish compared with Windows Explorer, and requiring MacPorts to run most Unix applications isn't really great. Developers are entirely relevant, because if there aren't any, no-one develops. And even my parents use Ubuntu, because Windows is too pricey and slow (esp. w/ antivirus) and there's no way they can afford a Mac. Not to mention Apple's lock-in policy and schizophrenic Java support (supposedly Oracle will do better but we'll wait and see).

<p>I didn't mean officially deprecated of course; all JavaSE ...

I didn't mean officially deprecated of course; all JavaSE APIs will be supported longer than the time Dinosaurs walked on Earth... what I meant is, those APIs are the past, they won't receive significant investment in features, only continuous bugfixing and very incremental improvements. A very good example of this trend is JavaSE 7, originally planned to include the Swing Application Framework and also JDatePicker - for the latter, you can't even use the excuse of big engineering effort...

BTW Sun got lots of flak from Swing developers for these new directions, but it's worth notice all other big backer of the Java platform had done the same. IBM fully abandoned Swing a full decade before Sun, when they introduced SWT. The old Oracle (before buying Sun) had also created their own SWT-like replacement for AWT/Swing, the EWT; they didn't promote this to third-parties and they also had products using Swing (actually I think the EWT is legacy today), but still, at some point they had decided that Swing was hopeless to build professional GUIs. Look at the JCP Executive Committee, and the only other member that also has expertise and resources to create Java platforms is... Google, that's not interested in fat-clients at all. So, the status is that Swing doesn't have ANY friends within the companies that influence (and pay for!) the progress of the Java specifications and implementations.

Java2D is a fallback pipeline for JavaFX, but that's only because Prism needs reasonably up-to-date GPUs and graphic drivers, and also because Oracle is supporting a large base of client platforms, including Windows XP. Wait a few years until WinXP is forgotten for good and DirectX10+ can be expected everywhere, and JavaFX will probably drop support for the Java2D renderer (at least on Windows; I don't know much about other platforms).

The comparison with HTML/canvas is not good. The advantage of canvas is not being an immediate-mode graphics API; it's simply that it is a graphics API at all! Yes it's more lightweight than SVG, but the scenegraph/retained-mode aspect was not the reason why SVG was ignored for years. And now people are building scene graph libraries for canvas, check Amino. It's true that the HTML DOM is a very heavyweight base for a graphics scene graph, so it's possible that SVG will never compete with canvas; but canvas-with-scenegraph will compete. (JavaFX will bet on that too, with its "web runtime".)

I agree that a native look&feel is important; it puzzles me that JavaFX doesn't offer this yet. Basic support should only require a fine-tuned CSS stylesheet for each native LAF. Full support must also get the "theme" configurations from the OS and change styles to match it dynamically, but the native Swing LAFs already encode all this intelligence... well, if Oracle doesn't do it, somebody eventually will, even a static CSS-based LAF would be very useful (I mean, how many users, especially in corporate environments, change the default theme in any significant way? Most people just change their desktop background and maybe the "large fonts" settings).

Finally on Linux vs. Mac, maybe I was not clear or successful in my irony but down to the facts, Linux is basically irrelevant as a Consumer Desktop platform. Duke Nukem Forever was finished but we're still waiting for "the year of desktop Linux". The single successful GUI platform based on Linux is Android, and that's because it doesn't rely on the abominations of Gnome or KDE, or even X11. I agree completely that developers are relevant, and that was exactly was I was saying - I think this part was clear! - that Oracle only supports JavaFX on Linux at all, to please the Java developers that use Linux as their dev platform, even though that's a declining population, as the defection to OSX is noticeable, remarkably in the US and Europe but I started to notice this even when I was in Brazil (where a good, developer-grade MBP costs more than most developers' monthly salary). It really puzzles me to see even well-known FOSS enthusiasts/advocates using Macs; these days, Windows is a shining model of openness if compared to the Mac and iOS... not to mention that the Mac is a second-tier platform for every single product or technology that doesn't come from Apple, so the Mac developers are constantly bitching about the very latest JDK or JavaFX, or Firefox or tons of other software, trailing behind Windows in release dates or features/performance... hey guys, "get a PC" ;-)

<p>&nbsp;</p> <p>If JavaFX isn't cross-platform then it has ...

If JavaFX isn't cross-platform then it has no point - if I wanted to do windows only development why wouldn't I'd use .net et al?
> so the Mac developers are constantly bitching about the very latest JDK or JavaFX, or Firefox or tons of other software, trailing
> behind Windows in release dates or features/performance... hey guys, "get a PC" ;-)
This is a year or two out of date - for example after years of MS office being rubbish on OS X - office 2011 is pretty damn good, web browsers are pretty damn good ( Chrome rocks ), unix tools set it pretty good, and overall user experience ( performance and features ) is pretty good, even Java version is reasonably recent j6 update 24.
Also if you want to test cross platform - how are you going to test on a mac without one? ( I realise this is due to Apple's restrictive policies )
> Windows is a shining model of openness if compared to the Mac and iOS...
Yep - but it's growing - and the biggest threat to Java is that Apple loses interst - without Apple - Java as an enterprise development platform loses it's reason for existence. Note in Lion ( Apples next OS version ) Java moves to an optional part of the OS - not installed by default - though the downloading and installing it is reasonably slick. Java is also not welcome on IPad, iPhone.

<p>JavaFX <a ...

JavaFX is cross platform. Remember it's still in beta; Windows is just the primary development platform, other ports will follow. The OSX port should be already available in the EA channel; I am in the EA program and I just get a HTTP/403 right now, maybe will be available soon.  I agree that for cross-platform testing one needs to have all important desktop OSes; but we're still in the early beta stage, the current implementation is not yet feature-complete, even the API is not yet completely stable, so it's too early to focus on porting bugs.

On OSX not trailing so much behind Windows... I agree that it's improved from a couple years ago; but it is still trailing even if not that much. JDK 6u24 feature-wise is a big step backward from 6u25 (which has many nice improvements backported from JDK7). JDK7 builds are not available at all for the OSX (yeah you can build your own OpenJDK and run in on X11...). And we're talking about major software like MSOffice or Java or web browsers; when you move to more modest (native) applications and tools, it's still common to find important stuff that is just not available at all for OSX. Sometimes this includes even mostly-non-native, Java apps; for example if you are a JavaEE developer, IBM's RAD/RSM/RSA product line is an extremely important product - if you ever need to do nontrivial work for WebSphere, you really don't want to use any other IDEs as they are alone with extremely wide and deep integration and specific support for all Websphere line (WAS, MQ, Portal etc.). And guess what, these IDEs are only available for Windows and... Linux, the latter certainly because Linux is an important deployment platform for Websphere. The fact that RAD/RSM/RSA are based on Eclipse (Eclipse on OSX is pretty good), and virtually 100% of the proprietary plugins they put on top of Eclipse are pure-Java, means that the porting cost should be small. But the trouble of support for an extra major platform would not; it wouldn't make sense considering the tiny importance of that platform in IBM's target market (the Mac is basically non-existent in the enterprise market that buys Websphere).

<p>&nbsp;</p> <p>Of course lots of things, particularly in ...

Of course lots of things, particularly in the enterprise world, are better supported on Windows - that's what ~90% of the worlds desktops run.
The main point I was trying to make - while numerically small those other platforms are essential for the Java ecosystem - if they didn't exist neither would Java on the client ( it may still be on the server - where I suspect the proportion of websphere instances running on windows is much lower ) - so you can mock them but their existence has a disproportionate importance to their numeric numbers.
If they didn't exist you could imagine what the technology landscape would look like.
Second the trendy CIO mantra is 'any device, anywhere'. With that sort of rhethoric a 90% solutions isn't good enough - that last few percent suddenly become very important.
They have stated it is going to be cross-platform and I never really doubted it - because not to do so would be suicide! So mock the 1% linux, ~5% Mac, and the small share of tablets running Android/IOS at your peril.

<p>I generally agree with your points; the only think I am ...

I generally agree with your points; the only think I am mocking - let's explain it clearly now... - is the attitude of the devotees of those minority platforms, always making a big scandal when something doesn't support their platform since day one. Mac users, Linux users... should just accept the simple fact that they are the "1%-5%" people, they are the second priority. They must be happy that their platform will be supported at all, even if a couple months after Windows. CIOs don't care about such minor delays, they usually won't even consider a new platform before the first maintenance releases. The anxiety of testing bleeding-edge SDKs in the first day they're released, and still in beta, is shared only by technophiles like us, not by most CIOs.

In a project like JavaFX, it's very hard to develop support for all platforms in perfect sync, at least in the first stages of the project when architectural details are still being worked out. Any important core change could impact all ports, so if you keep 5 ports 100% in-sync since day one, the cost of any change in the foundation is always multiplied by up to 5 (in the worst-case of impacts in code that's completely distinct for each platform). You can start the porting efforts early, but keep it always limited to the parts of the design that are already stable; this means that the ports will lag behind the primary platform and will only catch up in the endgame when 100% of the architecture is very stable.

<p>&gt; They must be happy that their platform will be ...

> They must be happy that their platform will be supported at all, even if a couple months after Windows
I would suggest that's the wrong perspective - while you may view them as the poor - waiting and grateful for any scraps that come their way. It's actually the other way around - it's JavaFX is currently a platform with no software and needs developers, and those people on non-windows OS's have other choices.
> The anxiety of testing bleeding-edge SDKs in the first day they're released, and still in beta, is shared only by technophiles like us, not by most CIOs
Agreed. It's early (doesn't feel like it though!) days and actually the JavaFX team have done a good job on the communication front. However, perception is important - Java has a new steward - can I trust Oracle to see it through and deliver? People are sensitive to these things because commiting to a new development platform is a very important choice - and the rug can be pulled out from under you all too easily ( especially on those minor platforms ).
> You can start the porting efforts early, but keep it always limited to the parts of the design that are already stable; this means that the ports will lag behind the primary platform and will only catch up in the endgame when 100% of the architecture is very stable.
Agree about the effort of maintaining all the platforms and the need for velocity - however there is a risk if you take this too far you end up realising late in the game that you have baked in Windows ( in this case ) specific assumptions - cross-platfrom needs to be real and not token ( ie features work and perform well ). Now I expect they have been doing this and it's just a question of polish/installers etc that is holding things up.

<p>Check Richard's <a ...

Check Richard's comment about this; they develop all (major at least) platforms in parallel. It's possible that at this time the other ports are trailing behind only in minor things or in QA. These are just my guesses, I have no inside info on the FX development.

Agreed of course that FX needs to attract developers, I think it's just a bit too early to publish the other ports. The beta will reportedly be refreshed in a two-week schedule, I'm curious to see how long for the first public Mac and Linux builds.