Turn, and Face the Strange Building J2SE5.0-enabled Jini services in a mixed VM environment by Calum Shaw-Mackay October 6, 2004
Summary
Yes, J2SE 5.0 is out, and as much as we all would like to use it, we know that there are some things that just won't happen over night - such as mass adoption by Appserver vendors,etc. But if you are willing to make a small compromise you can use J2SE5.0 in the guts of your code, but also let it play nicely with your 1.4 environment.
Advertisement
So, what is the problem? To put it technically, this is the problem; 'javac
-source 1.5 -target 1.4 does not work'. Originally, Sun believed that parts
of the new languages features of J2SE5.0 would be backwards compatible with
1.4, since many of them are syntactic in nature, examples being enhanced
'for', and enums (Potentially some generics, and even varags, could have
been compatible). Although a laudible goal, it didn't come to pass, and the
nearest we get to it is....
Incidentally showProps.java has absolutely no new 1.5 features; it just
dumps System.getProperties to a console. So from this we can deduce the
following things; 1) The compiler does not 'evaluate' the code it is
compiling for compliancy of 1.4 or 1.5 and adjust the -source parameter
accordingly; and 2) backtargeting will not be allowed under any
circumstances - the compiler refuses.
So what does all this mean to us programmers. It means many different
things to different people. Here's a few of the more 'standardised'
thoughts on this.
"I won't move to J2SE5.0 because....
it doesn't play well with 1.4
my appserver vendor doesn't support it and won't for the next X months
I don't like any of the new stuff anyway so neeeerrrhhhh!"
Classes that are 1.4 compatible, compiled under 1.5 don't work with 1.4
Some of these are based on real fears about the extent of change between 1.4 and 5.0
Lets look at them in turn
It doesn't play well with 1.4
Yes you have the '-target 1.4 -source 1.4' combination, but the issue goes much
deeper than this. In a distributed environment which can use java objects,
such as RMI or JINI, or indeed any serializable object sent down a socket can cause a major concern; if everything uses the '-target/source 1.4', then the parts of J2SE5.0
that you do want to use (the new concurrency package, for instance) are
potentially out of reach.
My Appserver vendor......
This is a big issue, and is not only technical, but political as well. And
it's not only appserver vendors, any java-based product your company has
invested in, will have developers going through exactly the same issues as
you, and you won't be able to fully make a move to 5.0 until they do.
Some people will get worried, if you suddenly start running a J2EE server
on 5.0, because your support may be invalidated. Even if worries of
significant differences in operation between 1.4 and 5.0 are unfounded,
many companies and IT departments will not take the risk. And this is
completely understandable. My point is rather than thinking about what the
appserver is running under, if you have external programs that interface to
it, you may be able to run those under 5.0 , yet you need to maintain
compatability with the 1.4 appserver (because of reduction of risk). This
gives you a possible path to move into 5.0 development, whilst not
tampering with the operational environment of your appserver.
I don't like all the new stuff anyway......
Fair enough, but it'll catch up with you in the end, whether you like it or
not.
Classes that are 1.4 compatible, but compiled under 5.0 don't work under 1.4
This is simply the class versioning problem.
Exception in thread "main" java.lang.UnsupportedClassVersionError:
my/service/ServiceStartup (Unsupported major.minor version 49.0)
And there is very,very little you can do about this.
Possible solutions
Really, this requires some thought on your part, a fair bit of grunt work
with Ant, and a little bit of compromise.
The first key thing about using J2SE5.0 in a predominately 1.4VM
distributed environment, is knowing how much the outside environment needs
to know about your service.
The second key thing to remember, is that J2SE5.0 can load 1.4 classes -
completely obvious I know, but it is very important to this discussion.
For Jini and RMI programmers, most distributed interactions occur through
interfaces and proxies and you can quickly get a fair idea of which classes
are required to be known about at compile-time (and if using mobile code,
run-time) by a 1.4VM. It is these classes and library files that must be
compiled with '-target 1.4 -source 1.4'. So these files must not contain
any 5.0 specific constructs- no annotations, generics, enums, vararg
declarations, static imports, and of course no new package references. Once
you've done this you're nearly there. So let's move onto the Ant builds
My 1.4 builds generally consisted of a javac "*" approach, Note: Angle brackets replaced with square brackets.
Then I jar'ed up my interface and code download jars from the 'build'
directory and voila, job done. For a mixed environment, it's a bit more
fiddly. I decided to go for three separate compilation steps.
I already knew what files to compile for the 1.4 jars, because I was
specifying them in the [jar] task. For safety's sake, I decided to
compile the classes for each part into separate directories, so that
versions would not get overwritten. I then jar'ed each individual directory
up into the proper jar files.
i.e.
${classes} => myService.jar; ${classes14intf}=> myService-intf.jar;
${classes14dl} =>myService-dl.jar.
I then moved my test clients to another project and compiled those for 1.4
(using the source and target flags). I made a small change to my service,
which at the time was still completely 1.4 compatible, a very simple change
- ArrayList stringlist = new ArrayList();
Just to be sure, I got both the client and the service to output the
content of "java.vm.version". Once everything was compiled, I decided to
give it a try, and it worked!
My 1.4 client was happily communicating with my service running under 5.0
without any problems. Of course, this isn't completely conclusive, but I
can't see many problems beyond moving a few classes into the 1.4 builds.
Of course there is a downside - no interfaces, or dependent classes can use
5.0 stuff; your ant builds start to get a bit bloated; you have to be more
diligent when you change stuff - you can't just think "hey, I'm on 5.0",
and go adding things in everywhere. But for all these compromises you need
to make, at least it can be done. And I think they are only small
compromises.
You may also want to look at reorganising your Ant build.xml so that you
compile your 1.4 stuff, create a 1.4 library jar, and then exclude any
classes in that jar from being built with 5.0, but use this library jar in
the 5.0 build. So in effect you build two/three partial builds that
together create your application
So if I can get a Jini2.0 service with all it's distributed object finery working in
a mixed VM environment, then there's hope for anyone, regardless of what
you're working with, be it J2EE or any other distributed environment.
Talk Back!
Have an opinion?
Be the first to
post a comment about
this weblog entry.
RSS Feed
If you'd like to be notified whenever Calum Shaw-Mackay adds a new entry to his weblog, subscribe to his RSS feed.
Calum Shaw-Mackay is an architect on Java and Jini systems, working in the UK. His interests lie in distributed computing, adaptability, and abstraction. Calum has been using Jini for longer than he would care to mention. His main area for taking the blame (some people would call it 'expertise') is systems integration and distributed frameworks, and is an advocate of using Jini's unique strengths to build adaptable enterprise systems. His opinions are his own. He's tried to get other people to take his opinions off him, but they just won't.