Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 4 of 5
The ideal way to compile your application is:
<location of J2SDK 1.4 or whichever javac you think is "best">\bin\javac
-target <base J2SE version>
-bootclasspath <base J2SDK location>\jre\lib\rt.jar
-classpath <your application/build output classpath>
<other javac options>
<your Java source filelist>
Yes, this implies you might have to use two different J2SDK versions on your build machine: the one you pick for its javac
and the one that is your base supported J2SE platform. This seems like extra setup effort, but it is actually a small price
to pay for a robust build. The key here is explicitly controlling both the class version stamps and the bootstrap classpath
and not relying on defaults. Use the -verbose option to verify where core class definitions are coming from.
As a side comment, I'll mention that it is common to see developers include rt.jar from their J2SDKs on the -classpath line (this could be a habit from the JDK 1.1 days when you had to add classes.zip to the compilation classpath). If you followed the discussion above, you now understand that this is completely redundant,
and in the worst case, might interfere with the proper order of things.
Here you want to be more sophisticated than in Scenario 1: You have a base-supported Java platform version, but should your
code run in a higher Java version, you prefer to leverage newer APIs. For example, you can get by with java.io.* APIs but wouldn't mind benefiting from java.nio.* enhancements in a more recent JVM if the opportunity presents itself.
In this scenario, the basic compilation approach resembles Scenario 1's approach, except your bootstrap J2SDK should be the highest version you need to use:
<location of J2SDK 1.4 or whichever javac you think is "best">\bin\javac
-target <base J2SE version>
-bootclasspath <highest supported J2SDK location>\jre\lib\rt.jar
-classpath <your application/build output classpath>
<other javac options>
<your Java source filelist>
This is not enough, however; you also need to do something clever in your Java code so it does the right thing in different J2SE versions.
One alternative is to use a Java preprocessor (with at least #ifdef/#else/#endif support) and actually generate different builds for different J2SE platform versions. Although J2SDK lacks proper preprocessing
support, there is no shortage of such tools on the Web.
However, managing several distributions for different J2SE platforms is always an additional burden. With some extra foresight
you can get away with distributing a single build of your application. Here is an example of how to do that (URLTest1 is a simple class that extracts various interesting bits from a URL):
public class URLTest1 implements IJREVersion
{
public static void main (String [] args)
throws MalformedURLException
{
URL url = new URL (args [0]);
final String path, reference, query;
// getRef() has been available since Java 1.1:
reference = url.getRef ();
if (JRE_1_3_PLUS)
{
// In Java 1.3+ everything is easy:
query = url.getQuery ();
// [Note: J2SDK javadocs fail to mention that getPath() was added
// in version 1.3]
path = url.getPath ();
}
else
{
// Prior to Java 1.3 I have to do extra work:
final String file = url.getFile ();
final int qindex = file.indexOf ('?');
final int pindex = file.indexOf ('#');
if (qindex >= 0)
{
path = file.substring (0, qindex);
if (pindex >= 0)
query = file.substring (qindex + 1, pindex);
else
{
if (qindex < file.length () - 1)
query = file.substring (qindex + 1);
else
query = "";
}
}
else
{
query = null;
if (pindex >= 0)
path = file.substring (pindex);
else
path = file;
}
}
System.out.println ("path: " + path);
System.out.println ("ref: " + reference);
System.out.println ("query: " + query);
}
} // End of class
Instead of being preprocessed prior to compilation, URLTest1 code is compiled against J2SDK 1.4 bootstrap classes with -target set to 1.1. Furthermore, main() selects different execution paths at runtime based on the values of several static constants defined in this interface: