The way Roedy's question so perfectly fits the solution makes me wonder if
he's seen this before, but forgotten that he's seen it.
A word of warning about that Class-Path attribute. Say you write a library
Aries which depends on two other libraries, Castor and Pollux. You ship a
distribution with three jars, yours and those of the dependencies:
Aries
|
+- aries.jar
+- castor.jar
\- pollux.jar
In the manifest of aries.jar, you write a Class-Path attribute which
refers to castor.jar and pollux.jar, and all is well.
Now i come along, with a project containing two modules, Odin and Thor,
where Thor depends on Odin (that is, all the classes present in Odin are
made available to Thor by my build and execution processes). Thor uses
Aries. But Odin already uses Castor, for some purpose unrelated to Aries.
My layout needs to look like this:
Odin
|
+- build/classes
| |
| \- Odin's own class files
|
+- lib
|
\- castor.jar
Thor
|
+- build/classes
| |
| \- Thor's own class files
|
+- lib
|
+- aries.jar
\- pollux.jar
Note that Thor does not include castor.jar, because it is supplied by its
dependency on Odin. All the libraries have the classes they need
available, and all is well.
Except that aries.jar has a Class-Path entry saying there should be a
castor.jar right next to it. Which there isn't. So, every time a tool
which cares about Class-Path entries loads that jar, it will notice the
absence, and moan about it. Sun's javac certainly does this - i have
projects, with situations like the above, where half of the output is
javac squawking about path problems which aren't problems at all. Luckily,
i don't think java itself does.
If you think the above setup is overcomplex, how about a simpler one; one
project, but where the different dependencies are kept in different
folders, for clerical convenience:
Krishna
|
\- lib
|
+- Aries
| |
| +- aries.jar
| \- README
|
+- Castor
| |
| +- castor.jar
| \- castor-javadoc.zip
|
+- Pollux
|
+- castor.jar
\- castor-extras.jar
Seems reasonable, right? And yet javac isn't going to like that at all.
The problem is that the Class-Path header expresses the dependency as a
URL; a direct path that can be resolved in the filesystem. That constrains
filesystem layout. It should have been a symbolic reference; perhaps a
pairing of a Specification-Title and a Specification-Version that
identifies what is needed, with the onus then being on the code loading
the jar to go off and find that, by scanning the classpath, exploring the
filesystem, looking in a module repository, etc. I think OSGi does
something a bit like this; the JBoss 7 module system certainly does.
Or an even easier case - my new project Loki uses Aries, but i like naming
my jars with a version number:
Loki
|
+- lib
|
+- aries-1.0.jar
+- castor-1.4.jar
\- pollux-2.2.1.jar
They're in the right place, but they have the wrong names. Cue javac
complaining!
Having pointed out these problems, i feel like i should give some advice
for what you should do. But i don't really know what you should do.
Perhaps you should restrict the use of Class-Path to cases where you can
control or predict the filesystem layout. Two cases spring to mind.
Firstly, where you have a library that is split into multiple jars, but
where these will always be present together; perhaps you have a US tax
rate library, where the code is updated occasionally, but the data for
each state is updated frequently. You might have a jar for the code and a
jar file for each state, containing classpath resources with data in.
There, it would be reasonable to use a Class-Path in the code jar to drag
in the state jars. This still falls over if i want to rename the jars, of
course.
Secondly, where you are packaging for deployment as an application, not
for further reuse. The main jar for an applet, application, or JWS app
would all be good examples of this. Nobody but you will ever incorporate
those jars into a project, so there is no worry about constaining
filesystem layout.
Or just not worry about Class-Path, and rely on consumers to set up a
classpath correctly.
tom