Some developers who installed Apple’s new java 1.4.1 for Mac OS X (and didn’t read the release notes or the mailing lists) got a nasty surprise when they tried to run apps they’d written for use with QuickTime for Java:
cadamson% java -classpath PlayMovie.zip PlayMovie Exception in thread "main" java.lang.NoClassDefFoundError: com/apple/mrj/macos/carbon/CarbonLock at quicktime.jdirect.QTNative._getLock(QTNative.java:111) at quicktime.jdirect.QTNative.(QTNative.java:105) at quicktime.QTSession.(QTSession.java:114) at PlayMovie.main(PlayMovie.java:24)
What’s happening is that java 1.4.1, now the default when you type
java on the command line, does not support certain Java-to-Carbon technologies that QuickTime for Java depends on. This problem was hinted at in a previous QTJ article, but I had to address the issue indirectly, since Apple’s 1.4.1 was still under NDA.
So why so much breakage? The story, as well-covered by
MacDevCenter’s Daniel Steinberg in href="http://www.macdevcenter.com/pub/a/mac/2003/03/10/osx_java.html">Apple
Releases Java 1.4.1 for Mac OS X is that Apple has made a huge
under-the-hood change, swapping out an AWT/Swing implementation based
on the Carbon API for one built on Cocoa.
The change is quite significant, as the move to the
object-oriented, multi-threaded Cocoa environment appears to have
significantly simplified Apple’s java codebase. However, it now makes
calls from Java into Carbon code much more difficult. As explained in
java-dev message from Apple’s Java Project Manager,
balancing between the pre-emptive threading of Java with the
co-operative threading model of Carbon is a tricky proposition.
As a result, in many cases, they’ve decided to replace or
simply abandon the Carbon-bound java extras. The
com.apple.mrj packages used to access Mac-specific
features are now deprecated, replaced in part by
com.apple.eio. In fact, the term "MRJ", a holdover from the old Mac OS’ "Macintosh Runtime for Java" era, seems to be going away. Also gone is the "JDirect" API for simplifying java-to-native calls.
Notice that both terms, "MRJ" and "JDirect" are implicated in the stack trace above. The QTJ code tries to get the carbon lock to avoid hosing the Human Interface Toolbox, but the
com.apple.mrj code to do so isn’t available in 1.4.1.
However, the situation is not as bad as it might sound. java 1.3.1
remains in place after a 1.4.1 upgrade, and will still run QTJ apps, and will reportedly be included in the next major release of Mac OS X. And in some cases, 1.3.1 will be the default JVM, for example, if your app is distributed as a
.app bundle — the schemes for every scenario are spelled out in
href="http://developer.apple.com/techpubs/macosx/ReleaseNotes/java141/multiplevms/index.html">the release notes. You could force use of 1.3.1 by using
href="http://java.sun.com/products/javawebstart/">Java Web Start, or by using a shell script that explicitly calls
/System/Library/Frameworks/JavaVM.framework /Versions/1.3.1/Commands/java, although the latter option is fraught with peril if a java 1.3.2 is ever released.
With java 1.3.1 sticking around on Mac OS X for the foreseeable
future, and with ways to call it explicitly, there doesn’t seem to be
need for QTJ developers to panic just yet.
Still, the future of QuickTime for Java does seem to be up in the
air. It has not been explicitly canceled or deprecated, as have
other API’s, but it clearly and unapologetically breaks in 1.4.1,
which makes a lot of QTJ fans nervous.
It’s strange because until now, QTJ had seemed like a first-class
citizen in the QuickTime world, prominently featured in developer
documentation (the main href="http://developer.apple.com/techpubs/quicktime/qtdevdocs/RM/frameset.htm">QuickTime
API documentation even cross-references all href="http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/javaalphaindex.htm">Java
equivalents to the native API’s calls). Yet on the href="http://developer.apple.com/quicktime/qtjava">QuickTime for Java
page, Apple says it is "interested in hearing from
QuickTime developers and understanding what aspects of the technology
they are using", as if it needs a business case to be made to
commit to the technology (or some subset of it) going forward.
From what I’ve seen, QTJ interest is greater than it has ever been,
a beneficiary to some degree of Sun’s neglect of the href="http://java.sun.com/products/java-media/jmf/index.html">Java
Media Framework, which has not seen a major version since 1999, as
Sun’s media team has focused on a href="http://java.sun.com/products/mmapi/">Mobile Media API
instead. Developers who want to do media apps in Java are choosing
between several imperfect options:
- Stick with JMF despite its limited collection of supported
media formats and codecs. This is still the most practical all-java option.
- Use QuickTime for Java and get great support of real-world
media types, and arguably the best API for editing and creating media,
with the gotcha that it only works on Windows and Mac
(and now only on 1.3.1 on Mac)
- Do everything yourself in Java like JavaZoom did with their all-Java MP3 decoder. Not for the faint of heart.
- Use JNI to tie into QuickTime, Windows Media, the
href="http://www.helixcommunity.org">Helix software open-sourced by RealNetworks, or other native media API’s. Also difficult,
and obviously limited to a handful of platforms.
- Dump Java and use the aforementioned media API’s in their
My fear is that if QTJ is not supported in the future, that option
5 will be the default, i.e., it will pretty much close the curtain on
developing media applications in java, because the other options are too much work for too little benefit. And that will make developers
like me wonder if we like QuickTime so much that we’re ready to give
in to the crazy square-braces and semi-automatic garbage collection of
Objective-C. Time… or is that QuickTime… will tell.
Does Apple need to get QTJ happy in java 1.4.1? Is there a better alternative? What do you think?