The Artima Developer Community
Sponsored Link

Turn, and Face the Strange
Building J2SE5.0-enabled Jini services in a mixed VM environment
by Calum Shaw-Mackay
October 6, 2004
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.


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....

#javac -target 1.4 -source 1.5
javac: source release 1.5 requires target release 1.5
Incidentally 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....
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.
	[javac srcdir="${src}" destdir="${build}"]
		[classpath refid="project.class.path" /]
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.
	[target name="compile" depends="init"]
		[echo message="Compiling J2SE 5.0 base build....." /]
		[javac srcdir="${src}" destdir="${classes}"]
			[exclude name="**/*" /]
			[classpath refid="project.class.path" /]
			[classpath refid="jaxbpath" /]
		[echo message="Compiling interface classes for 1.4 VMs" /]
                [javac destdir="${classes14intf}" source="1.4" target="1.4" srcdir="${src}"]
			[include name="my/service/" /]
			[include name="my/service/" /]
			[exclude name="**/*" /]
			[classpath refid="project.class.path" /]
			[classpath refid="jaxbpath" /]
		[echo message="Compiling dl classes for 1.4 VMs" /]
                [javac destdir="${classes14dl}" source="1.4" target="1.4" srcdir="${src}"]
			[include name="**/*Stub.class" /]
			[include name="my/service/" /]
			[classpath refid="project.class.path" /]
			[classpath refid="jaxbpath" /]

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.
${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.

About the Blogger

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.

This weblog entry is Copyright © 2004 Calum Shaw-Mackay. All rights reserved.

Sponsored Links


Copyright © 1996-2014 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us