single jar containing both Java 5 and 6 jars

N

neuneudr

Hi,

I know that the *free* Java 5 version shall be end-of-lined soon.

However Java 6 is *not* available on MacOS X 10.4 and apparently
never will (it is available starting from MacOS X 10.5.2).

I do want to support MacOS X 10.4. More precisely, I want my app
to start and run on systems having Java 1.5 and warning them that
some functionnalities (like table sorting) shall be disabled, which is
why they should upgrade to Java 6 (when possible).

I've already packaged application using a single .jar, using some
default class loader hack (to load APIs, packaged as jar files,
inside my main jar). And I've now found "one jar", which
does the same, just better ( http://one-jar.sourceforge.net/ ).

And I was wondering the following : is it conceivable to pack a
"Java 6 jar" inside a "Java 5 jar" and decide, at runtime, if we're
running on Java 6 VM, to launch the Java 6 jar? (of course I'd
have a build script building the two different jars, then packaging
them [and the 3rd-party libraries] into a single jar).

I might just "try it and seen" but I'd like to have some advice
from people here first,

Driss
 
N

neuneudr

Answering to myself...

Actually in my case, I realized that besides SwingWorker
and and RowSorter/TableRowSorter I don't really *need*
anything from Java 6.

I already "backported" SwingWorker to Java 5.

Either an already made backport of RowSorter/TableRowSorter
(I'm not backporting this myself, there's too much ;) or
another, easy, way to sort the rows in Java 5 would solve
my problem too.

I'd then be able to simply ship a single, Java 5, version
of my jar.

Out of curiosity I'm still interested about the feasibility
of having a Java 6 jar inside a Java 5 jar, which was my
original question.
 
A

Andrew Thompson

In the case of an entirely new class, you
can make a *single class* that caters for
both Java 1.5 and Java 1.6.

It works something like this..

In the code,

try {
Java6Class newThing = new Java6Class();
} catch(NoClassDefFoundError ncdfe) {
// proceed without it..
}

The hard part is compiling that code so it is
guaranteed to be 1.5 compatible. To do that
you might try..

REM: all one line, broken for clarity
javac
-target 1.5
-bootclasspath path/to/1.5/rt.jar
*.java

...but that, of course, will show a compilation
error on Java6Class. To fix that, ..

javac
-target 1.5
-bootclasspath path/to/1.5/rt.jar
-classpath path/to/1.6/rt.jar
*.java

1st javac will check the 1.5 rt.jar, if it
does not find the class, it will check the
1.6 rt.jar.

As far as I can figure, the only time you
need to factor out later functionality into
a separate class, is when using methods or
attributes of a class that already existed in
the ealrier version. In that event, the 1.5
class will be loaded, and the 1.6 member will
not be available.

At least, that is my latest best theory. I
had not gotten around to testing it. If you
should try, please report back the results.
 
N

neuneudr

In the case of an entirely new class, you
can make a *single class* that caters for
both Java 1.5 and Java 1.6.

Hi Andrew,

thanks for your answer, but I'm not as expericenced
as you are and don't understand everything :-/

To be sure I understand you correctly: you're
suggesting that it may be possible to have a
single .jar file containing all "target 1.5"
classes but one of which would actually call
1.6 libraries?

I'm doing a few tries as of now and I'm using
the system class loader to load the only "1.6"
class when I'm actually on a 1.6+ VM.

I got "as far" as making a separate "srcJava6only"
directory, containing the only .java file referencing
"since Java 1.6" APIs and having the system class loader
only loading this class when it's a 1.6+ VM.

So at this point I can quickly build either 1.6 or
1.5 versions, by simple bypassing compilation of that
"srcJava6only" directory.

I'll be trying what you explained now, thanks again,

Driss
 
N

neuneudr

The hard part is compiling that code so it is
guaranteed to be 1.5 compatible. To do that
you might try..

I made it work apparently!

What I did simply is to
create a .class file using the JDK 1.6 compiler and
made sure not to call that class if I'm not on a 1.6+ VM
(the JVM guarantees that the class shall not be instantiated
if I'm not referencing it nor using it, so I'm not getting
any errors when I run the code on the (old) MacOS X, under
a 1.5 VM).

I instantiate this class using the system ClassLoader
and everything is fine.

What I didn't realize is that I could have a mix of 1.5
and 1.6 classes inside a .jar and that a 1.6 VM would
be fine with that (apparently).

Some "cafe babe":

for a 1.5 class:

.... $ hexdump Test.class | head -n 1
0000000 feca beba 0000 3100 ...

Class version number: 0x31 (49)

for a 1.6 class:

.... $ hexdump KludgyHackTableRowSorter.class | head -n 1
0000000 feca beba 0000 3200 ...

Class version number: 0x32 (50)

And the same (unique) .jar is working as is wether
I run it on a 1.5 VM or a 1.6+ VM.

I didn't know it was allowed to "mix" .class files
targetting different versions.

Regarding the build, I just build the 1.6 file once
and incorporated it in the .jar.

I could now write a script that build my "srcJava6only"
using target 1.6 and the normal "src" targetting 1.5
and making them happily live together in the same .jar :)

Basically it seems to work, thanks for your help,


Driss
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,981
Messages
2,570,188
Members
46,731
Latest member
MarcyGipso

Latest Threads

Top